Java 11 integration;
[jalview.git] / src2 / fr / orsay / lri / varna / VARNAPanel.java
1 /*
2  VARNA is a tool for the automated drawing, visualization and annotation of the secondary structure of RNA, designed as a companion software for web servers and databases.
3  Copyright (C) 2012  Kevin Darty, Alain Denise and Yann Ponty.
4  electronic mail : Yann.Ponty@lri.fr
5  paper mail : LRI, bat 490 Universit� Paris-Sud 91405 Orsay Cedex France
6
7  This file is part of VARNA version 3.9.
8  VARNA version 3.9 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
9  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10
11  VARNA version 3.9 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  See the GNU General Public License for more details.
14
15  You should have received a copy of the GNU General Public License along with VARNA version 3.1.
16  If not, see http://www.gnu.org/licenses.
17  */
18
19 /*
20  GNU GENERAL PUBLIC LICENSE
21  Version 3, 29 June 2007
22
23  Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
24  Everyone is permitted to copy and distribute verbatim copies
25  of this license document, but changing it is not allowed.
26
27  Preamble
28
29  The GNU General Public License is a free, copyleft license for
30  software and other kinds of works.
31
32  The licenses for most software and other practical works are designed
33  to take away your freedom to share and change the works.  By contrast,
34  the GNU General Public License is intended to guarantee your freedom to
35  share and change all versions of a program--to make sure it remains free
36  software for all its users.  We, the Free Software Foundation, use the
37  GNU General Public License for most of our software; it applies also to
38  any other work released this way by its authors.  You can apply it to
39  your programs, too.
40
41  When we speak of free software, we are referring to freedom, not
42  price.  Our General Public Licenses are designed to make sure that you
43  have the freedom to distribute copies of free software (and charge for
44  them if you wish), that you receive source code or can get it if you
45  want it, that you can change the software or use pieces of it in new
46  free programs, and that you know you can do these things.
47
48  To protect your rights, we need to prevent others from denying you
49  these rights or asking you to surrender the rights.  Therefore, you have
50  certain responsibilities if you distribute copies of the software, or if
51  you modify it: responsibilities to respect the freedom of others.
52
53  For example, if you distribute copies of such a program, whether
54  gratis or for a fee, you must pass on to the recipients the same
55  freedoms that you received.  You must make sure that they, too, receive
56  or can get the source code.  And you must show them these terms so they
57  know their rights.
58
59  Developers that use the GNU GPL protect your rights with two steps:
60  (1) assert copyright on the software, and (2) offer you this License
61  giving you legal permission to copy, distribute and/or modify it.
62
63  For the developers' and authors' protection, the GPL clearly explains
64  that there is no warranty for this free software.  For both users' and
65  authors' sake, the GPL requires that modified versions be marked as
66  changed, so that their problems will not be attributed erroneously to
67  authors of previous versions.
68
69  Some devices are designed to deny users access to install or run
70  modified versions of the software inside them, although the manufacturer
71  can do so.  This is fundamentally incompatible with the aim of
72  protecting users' freedom to change the software.  The systematic
73  pattern of such abuse occurs in the area of products for individuals to
74  use, which is precisely where it is most unacceptable.  Therefore, we
75  have designed this version of the GPL to prohibit the practice for those
76  products.  If such problems arise substantially in other domains, we
77  stand ready to extend this provision to those domains in future versions
78  of the GPL, as needed to protect the freedom of users.
79
80  Finally, every program is threatened constantly by software patents.
81  States should not allow patents to restrict development and use of
82  software on general-purpose computers, but in those that do, we wish to
83  avoid the special danger that patents applied to a free program could
84  make it effectively proprietary.  To prevent this, the GPL assures that
85  patents cannot be used to render the program non-free.
86
87  The precise terms and conditions for copying, distribution and
88  modification follow.
89
90  TERMS AND CONDITIONS
91
92  0. Definitions.
93
94  "This License" refers to version 3 of the GNU General Public License.
95
96  "Copyright" also means copyright-like laws that apply to other kinds of
97  works, such as semiconductor masks.
98
99  "The Program" refers to any copyrightable work licensed under this
100  License.  Each licensee is addressed as "you".  "Licensees" and
101  "recipients" may be individuals or organizations.
102
103  To "modify" a work means to copy from or adapt all or part of the work
104  in a fashion requiring copyright permission, other than the making of an
105  exact copy.  The resulting work is called a "modified version" of the
106  earlier work or a work "based on" the earlier work.
107
108  A "covered work" means either the unmodified Program or a work based
109  on the Program.
110
111  To "propagate" a work means to do anything with it that, without
112  permission, would make you directly or secondarily liable for
113  infringement under applicable copyright law, except executing it on a
114  computer or modifying a private copy.  Propagation includes copying,
115  distribution (with or without modification), making available to the
116  public, and in some countries other activities as well.
117
118  To "convey" a work means any kind of propagation that enables other
119  parties to make or receive copies.  Mere interaction with a user through
120  a computer network, with no transfer of a copy, is not conveying.
121
122  An interactive user interface displays "Appropriate Legal Notices"
123  to the extent that it includes a convenient and prominently visible
124  feature that (1) displays an appropriate copyright notice, and (2)
125  tells the user that there is no warranty for the work (except to the
126  extent that warranties are provided), that licensees may convey the
127  work under this License, and how to view a copy of this License.  If
128  the interface presents a list of user commands or options, such as a
129  menu, a prominent item in the list meets this criterion.
130
131  1. Source Code.
132
133  The "source code" for a work means the preferred form of the work
134  for making modifications to it.  "Object code" means any non-source
135  form of a work.
136
137  A "Standard Interface" means an interface that either is an official
138  standard defined by a recognized standards body, or, in the case of
139  interfaces specified for a particular programming language, one that
140  is widely used among developers working in that language.
141
142  The "System Libraries" of an executable work include anything, other
143  than the work as a whole, that (a) is included in the normal form of
144  packaging a Major Component, but which is not part of that Major
145  Component, and (b) serves only to enable use of the work with that
146  Major Component, or to implement a Standard Interface for which an
147  implementation is available to the public in source code form.  A
148  "Major Component", in this context, means a major essential component
149  (kernel, window system, and so on) of the specific operating system
150  (if any) on which the executable work runs, or a compiler used to
151  produce the work, or an object code interpreter used to run it.
152
153  The "Corresponding Source" for a work in object code form means all
154  the source code needed to generate, install, and (for an executable
155  work) run the object code and to modify the work, including scripts to
156  control those activities.  However, it does not include the work's
157  System Libraries, or general-purpose tools or generally available free
158  programs which are used unmodified in performing those activities but
159  which are not part of the work.  For example, Corresponding Source
160  includes interface definition files associated with source files for
161  the work, and the source code for shared libraries and dynamically
162  linked subprograms that the work is specifically designed to require,
163  such as by intimate data communication or control flow between those
164  subprograms and other parts of the work.
165
166  The Corresponding Source need not include anything that users
167  can regenerate automatically from other parts of the Corresponding
168  Source.
169
170  The Corresponding Source for a work in source code form is that
171  same work.
172
173  2. Basic Permissions.
174
175  All rights granted under this License are granted for the term of
176  copyright on the Program, and are irrevocable provided the stated
177  conditions are met.  This License explicitly affirms your unlimited
178  permission to run the unmodified Program.  The output from running a
179  covered work is covered by this License only if the output, given its
180  content, constitutes a covered work.  This License acknowledges your
181  rights of fair use or other equivalent, as provided by copyright law.
182
183  You may make, run and propagate covered works that you do not
184  convey, without conditions so long as your license otherwise remains
185  in force.  You may convey covered works to others for the sole purpose
186  of having them make modifications exclusively for you, or provide you
187  with facilities for running those works, provided that you comply with
188  the terms of this License in conveying all material for which you do
189  not control copyright.  Those thus making or running the covered works
190  for you must do so exclusively on your behalf, under your direction
191  and control, on terms that prohibit them from making any copies of
192  your copyrighted material outside their relationship with you.
193
194  Conveying under any other circumstances is permitted solely under
195  the conditions stated below.  Sublicensing is not allowed; section 10
196  makes it unnecessary.
197
198  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
199
200  No covered work shall be deemed part of an effective technological
201  measure under any applicable law fulfilling obligations under article
202  11 of the WIPO copyright treaty adopted on 20 December 1996, or
203  similar laws prohibiting or restricting circumvention of such
204  measures.
205
206  When you convey a covered work, you waive any legal power to forbid
207  circumvention of technological measures to the extent such circumvention
208  is effected by exercising rights under this License with respect to
209  the covered work, and you disclaim any intention to limit operation or
210  modification of the work as a means of enforcing, against the work's
211  users, your or third parties' legal rights to forbid circumvention of
212  technological measures.
213
214  4. Conveying Verbatim Copies.
215
216  You may convey verbatim copies of the Program's source code as you
217  receive it, in any medium, provided that you conspicuously and
218  appropriately publish on each copy an appropriate copyright notice;
219  keep intact all notices stating that this License and any
220  non-permissive terms added in accord with section 7 apply to the code;
221  keep intact all notices of the absence of any warranty; and give all
222  recipients a copy of this License along with the Program.
223
224  You may charge any price or no price for each copy that you convey,
225  and you may offer support or warranty protection for a fee.
226
227  5. Conveying Modified Source Versions.
228
229  You may convey a work based on the Program, or the modifications to
230  produce it from the Program, in the form of source code under the
231  terms of section 4, provided that you also meet all of these conditions:
232
233  a) The work must carry prominent notices stating that you modified
234  it, and giving a relevant date.
235
236  b) The work must carry prominent notices stating that it is
237  released under this License and any conditions added under section
238  7.  This requirement modifies the requirement in section 4 to
239  "keep intact all notices".
240
241  c) You must license the entire work, as a whole, under this
242  License to anyone who comes into possession of a copy.  This
243  License will therefore apply, along with any applicable section 7
244  additional terms, to the whole of the work, and all its parts,
245  regardless of how they are packaged.  This License gives no
246  permission to license the work in any other way, but it does not
247  invalidate such permission if you have separately received it.
248
249  d) If the work has interactive user interfaces, each must display
250  Appropriate Legal Notices; however, if the Program has interactive
251  interfaces that do not display Appropriate Legal Notices, your
252  work need not make them do so.
253
254  A compilation of a covered work with other separate and independent
255  works, which are not by their nature extensions of the covered work,
256  and which are not combined with it such as to form a larger program,
257  in or on a volume of a storage or distribution medium, is called an
258  "aggregate" if the compilation and its resulting copyright are not
259  used to limit the access or legal rights of the compilation's users
260  beyond what the individual works permit.  Inclusion of a covered work
261  in an aggregate does not cause this License to apply to the other
262  parts of the aggregate.
263
264  6. Conveying Non-Source Forms.
265
266  You may convey a covered work in object code form under the terms
267  of sections 4 and 5, provided that you also convey the
268  machine-readable Corresponding Source under the terms of this License,
269  in one of these ways:
270
271  a) Convey the object code in, or embodied in, a physical product
272  (including a physical distribution medium), accompanied by the
273  Corresponding Source fixed on a durable physical medium
274  customarily used for software interchange.
275
276  b) Convey the object code in, or embodied in, a physical product
277  (including a physical distribution medium), accompanied by a
278  written offer, valid for at least three years and valid for as
279  long as you offer spare parts or customer support for that product
280  model, to give anyone who possesses the object code either (1) a
281  copy of the Corresponding Source for all the software in the
282  product that is covered by this License, on a durable physical
283  medium customarily used for software interchange, for a price no
284  more than your reasonable cost of physically performing this
285  conveying of source, or (2) access to copy the
286  Corresponding Source from a network server at no charge.
287
288  c) Convey individual copies of the object code with a copy of the
289  written offer to provide the Corresponding Source.  This
290  alternative is allowed only occasionally and noncommercially, and
291  only if you received the object code with such an offer, in accord
292  with subsection 6b.
293
294  d) Convey the object code by offering access from a designated
295  place (gratis or for a charge), and offer equivalent access to the
296  Corresponding Source in the same way through the same place at no
297  further charge.  You need not require recipients to copy the
298  Corresponding Source along with the object code.  If the place to
299  copy the object code is a network server, the Corresponding Source
300  may be on a different server (operated by you or a third party)
301  that supports equivalent copying facilities, provided you maintain
302  clear directions next to the object code saying where to find the
303  Corresponding Source.  Regardless of what server hosts the
304  Corresponding Source, you remain obligated to ensure that it is
305  available for as long as needed to satisfy these requirements.
306
307  e) Convey the object code using peer-to-peer transmission, provided
308  you inform other peers where the object code and Corresponding
309  Source of the work are being offered to the general public at no
310  charge under subsection 6d.
311
312  A separable portion of the object code, whose source code is excluded
313  from the Corresponding Source as a System Library, need not be
314  included in conveying the object code work.
315
316  A "User Product" is either (1) a "consumer product", which means any
317  tangible personal property which is normally used for personal, family,
318  or household purposes, or (2) anything designed or sold for incorporation
319  into a dwelling.  In determining whether a product is a consumer product,
320  doubtful cases shall be resolved in favor of coverage.  For a particular
321  product received by a particular user, "normally used" refers to a
322  typical or common use of that class of product, regardless of the status
323  of the particular user or of the way in which the particular user
324  actually uses, or expects or is expected to use, the product.  A product
325  is a consumer product regardless of whether the product has substantial
326  commercial, industrial or non-consumer uses, unless such uses represent
327  the only significant mode of use of the product.
328
329  "Installation Information" for a User Product means any methods,
330  procedures, authorization keys, or other information required to install
331  and execute modified versions of a covered work in that User Product from
332  a modified version of its Corresponding Source.  The information must
333  suffice to ensure that the continued functioning of the modified object
334  code is in no case prevented or interfered with solely because
335  modification has been made.
336
337  If you convey an object code work under this section in, or with, or
338  specifically for use in, a User Product, and the conveying occurs as
339  part of a transaction in which the right of possession and use of the
340  User Product is transferred to the recipient in perpetuity or for a
341  fixed term (regardless of how the transaction is characterized), the
342  Corresponding Source conveyed under this section must be accompanied
343  by the Installation Information.  But this requirement does not apply
344  if neither you nor any third party retains the ability to install
345  modified object code on the User Product (for example, the work has
346  been installed in ROM).
347
348  The requirement to provide Installation Information does not include a
349  requirement to continue to provide support service, warranty, or updates
350  for a work that has been modified or installed by the recipient, or for
351  the User Product in which it has been modified or installed.  Access to a
352  network may be denied when the modification itself materially and
353  adversely affects the operation of the network or violates the rules and
354  protocols for communication across the network.
355
356  Corresponding Source conveyed, and Installation Information provided,
357  in accord with this section must be in a format that is publicly
358  documented (and with an implementation available to the public in
359  source code form), and must require no special password or key for
360  unpacking, reading or copying.
361
362  7. Additional Terms.
363
364  "Additional permissions" are terms that supplement the terms of this
365  License by making exceptions from one or more of its conditions.
366  Additional permissions that are applicable to the entire Program shall
367  be treated as though they were included in this License, to the extent
368  that they are valid under applicable law.  If additional permissions
369  apply only to part of the Program, that part may be used separately
370  under those permissions, but the entire Program remains governed by
371  this License without regard to the additional permissions.
372
373  When you convey a copy of a covered work, you may at your option
374  remove any additional permissions from that copy, or from any part of
375  it.  (Additional permissions may be written to require their own
376  removal in certain cases when you modify the work.)  You may place
377  additional permissions on material, added by you to a covered work,
378  for which you have or can give appropriate copyright permission.
379
380  Notwithstanding any other provision of this License, for material you
381  add to a covered work, you may (if authorized by the copyright holders of
382  that material) supplement the terms of this License with terms:
383
384  a) Disclaiming warranty or limiting liability differently from the
385  terms of sections 15 and 16 of this License; or
386
387  b) Requiring preservation of specified reasonable legal notices or
388  author attributions in that material or in the Appropriate Legal
389  Notices displayed by works containing it; or
390
391  c) Prohibiting misrepresentation of the origin of that material, or
392  requiring that modified versions of such material be marked in
393  reasonable ways as different from the original version; or
394
395  d) Limiting the use for publicity purposes of names of licensors or
396  authors of the material; or
397
398  e) Declining to grant rights under trademark law for use of some
399  trade names, trademarks, or service marks; or
400
401  f) Requiring indemnification of licensors and authors of that
402  material by anyone who conveys the material (or modified versions of
403  it) with contractual assumptions of liability to the recipient, for
404  any liability that these contractual assumptions directly impose on
405  those licensors and authors.
406
407  All other non-permissive additional terms are considered "further
408  restrictions" within the meaning of section 10.  If the Program as you
409  received it, or any part of it, contains a notice stating that it is
410  governed by this License along with a term that is a further
411  restriction, you may remove that term.  If a license document contains
412  a further restriction but permits relicensing or conveying under this
413  License, you may add to a covered work material governed by the terms
414  of that license document, provided that the further restriction does
415  not survive such relicensing or conveying.
416
417  If you add terms to a covered work in accord with this section, you
418  must place, in the relevant source files, a statement of the
419  additional terms that apply to those files, or a notice indicating
420  where to find the applicable terms.
421
422  Additional terms, permissive or non-permissive, may be stated in the
423  form of a separately written license, or stated as exceptions;
424  the above requirements apply either way.
425
426  8. Termination.
427
428  You may not propagate or modify a covered work except as expressly
429  provided under this License.  Any attempt otherwise to propagate or
430  modify it is void, and will automatically terminate your rights under
431  this License (including any patent licenses granted under the third
432  paragraph of section 11).
433
434  However, if you cease all violation of this License, then your
435  license from a particular copyright holder is reinstated (a)
436  provisionally, unless and until the copyright holder explicitly and
437  finally terminates your license, and (b) permanently, if the copyright
438  holder fails to notify you of the violation by some reasonable means
439  prior to 60 days after the cessation.
440
441  Moreover, your license from a particular copyright holder is
442  reinstated permanently if the copyright holder notifies you of the
443  violation by some reasonable means, this is the first time you have
444  received notice of violation of this License (for any work) from that
445  copyright holder, and you cure the violation prior to 30 days after
446  your receipt of the notice.
447
448  Termination of your rights under this section does not terminate the
449  licenses of parties who have received copies or rights from you under
450  this License.  If your rights have been terminated and not permanently
451  reinstated, you do not qualify to receive new licenses for the same
452  material under section 10.
453
454  9. Acceptance Not Required for Having Copies.
455
456  You are not required to accept this License in order to receive or
457  run a copy of the Program.  Ancillary propagation of a covered work
458  occurring solely as a consequence of using peer-to-peer transmission
459  to receive a copy likewise does not require acceptance.  However,
460  nothing other than this License grants you permission to propagate or
461  modify any covered work.  These actions infringe copyright if you do
462  not accept this License.  Therefore, by modifying or propagating a
463  covered work, you indicate your acceptance of this License to do so.
464
465  10. Automatic Licensing of Downstream Recipients.
466
467  Each time you convey a covered work, the recipient automatically
468  receives a license from the original licensors, to run, modify and
469  propagate that work, subject to this License.  You are not responsible
470  for enforcing compliance by third parties with this License.
471
472  An "entity transaction" is a transaction transferring control of an
473  organization, or substantially all assets of one, or subdividing an
474  organization, or merging organizations.  If propagation of a covered
475  work results from an entity transaction, each party to that
476  transaction who receives a copy of the work also receives whatever
477  licenses to the work the party's predecessor in interest had or could
478  give under the previous paragraph, plus a right to possession of the
479  Corresponding Source of the work from the predecessor in interest, if
480  the predecessor has it or can get it with reasonable efforts.
481
482  You may not impose any further restrictions on the exercise of the
483  rights granted or affirmed under this License.  For example, you may
484  not impose a license fee, royalty, or other charge for exercise of
485  rights granted under this License, and you may not initiate litigation
486  (including a cross-claim or counterclaim in a lawsuit) alleging that
487  any patent claim is infringed by making, using, selling, offering for
488  sale, or importing the Program or any portion of it.
489
490  11. Patents.
491
492  A "contributor" is a copyright holder who authorizes use under this
493  License of the Program or a work on which the Program is based.  The
494  work thus licensed is called the contributor's "contributor version".
495
496  A contributor's "essential patent claims" are all patent claims
497  owned or controlled by the contributor, whether already acquired or
498  hereafter acquired, that would be infringed by some manner, permitted
499  by this License, of making, using, or selling its contributor version,
500  but do not include claims that would be infringed only as a
501  consequence of further modification of the contributor version.  For
502  purposes of this definition, "control" includes the right to grant
503  patent sublicenses in a manner consistent with the requirements of
504  this License.
505
506  Each contributor grants you a non-exclusive, worldwide, royalty-free
507  patent license under the contributor's essential patent claims, to
508  make, use, sell, offer for sale, import and otherwise run, modify and
509  propagate the contents of its contributor version.
510
511  In the following three paragraphs, a "patent license" is any express
512  agreement or commitment, however denominated, not to enforce a patent
513  (such as an express permission to practice a patent or covenant not to
514  sue for patent infringement).  To "grant" such a patent license to a
515  party means to make such an agreement or commitment not to enforce a
516  patent against the party.
517
518  If you convey a covered work, knowingly relying on a patent license,
519  and the Corresponding Source of the work is not available for anyone
520  to copy, free of charge and under the terms of this License, through a
521  publicly available network server or other readily accessible means,
522  then you must either (1) cause the Corresponding Source to be so
523  available, or (2) arrange to deprive yourself of the benefit of the
524  patent license for this particular work, or (3) arrange, in a manner
525  consistent with the requirements of this License, to extend the patent
526  license to downstream recipients.  "Knowingly relying" means you have
527  actual knowledge that, but for the patent license, your conveying the
528  covered work in a country, or your recipient's use of the covered work
529  in a country, would infringe one or more identifiable patents in that
530  country that you have reason to believe are valid.
531
532  If, pursuant to or in connection with a single transaction or
533  arrangement, you convey, or propagate by procuring conveyance of, a
534  covered work, and grant a patent license to some of the parties
535  receiving the covered work authorizing them to use, propagate, modify
536  or convey a specific copy of the covered work, then the patent license
537  you grant is automatically extended to all recipients of the covered
538  work and works based on it.
539
540  A patent license is "discriminatory" if it does not include within
541  the scope of its coverage, prohibits the exercise of, or is
542  conditioned on the non-exercise of one or more of the rights that are
543  specifically granted under this License.  You may not convey a covered
544  work if you are a party to an arrangement with a third party that is
545  in the business of distributing software, under which you make payment
546  to the third party based on the extent of your activity of conveying
547  the work, and under which the third party grants, to any of the
548  parties who would receive the covered work from you, a discriminatory
549  patent license (a) in connection with copies of the covered work
550  conveyed by you (or copies made from those copies), or (b) primarily
551  for and in connection with specific products or compilations that
552  contain the covered work, unless you entered into that arrangement,
553  or that patent license was granted, prior to 28 March 2007.
554
555  Nothing in this License shall be construed as excluding or limiting
556  any implied license or other defenses to infringement that may
557  otherwise be available to you under applicable patent law.
558
559  12. No Surrender of Others' Freedom.
560
561  If conditions are imposed on you (whether by court order, agreement or
562  otherwise) that contradict the conditions of this License, they do not
563  excuse you from the conditions of this License.  If you cannot convey a
564  covered work so as to satisfy simultaneously your obligations under this
565  License and any other pertinent obligations, then as a consequence you may
566  not convey it at all.  For example, if you agree to terms that obligate you
567  to collect a royalty for further conveying from those to whom you convey
568  the Program, the only way you could satisfy both those terms and this
569  License would be to refrain entirely from conveying the Program.
570
571  13. Use with the GNU Affero General Public License.
572
573  Notwithstanding any other provision of this License, you have
574  permission to link or combine any covered work with a work licensed
575  under version 3 of the GNU Affero General Public License into a single
576  combined work, and to convey the resulting work.  The terms of this
577  License will continue to apply to the part which is the covered work,
578  but the special requirements of the GNU Affero General Public License,
579  section 13, concerning interaction through a network will apply to the
580  combination as such.
581
582  14. Revised Versions of this License.
583
584  The Free Software Foundation may publish revised and/or new versions of
585  the GNU General Public License from time to time.  Such new versions will
586  be similar in spirit to the present version, but may differ in detail to
587  address new problems or concerns.
588
589  Each version is given a distinguishing version number.  If the
590  Program specifies that a certain numbered version of the GNU General
591  Public License "or any later version" applies to it, you have the
592  option of following the terms and conditions either of that numbered
593  version or of any later version published by the Free Software
594  Foundation.  If the Program does not specify a version number of the
595  GNU General Public License, you may choose any version ever published
596  by the Free Software Foundation.
597
598  If the Program specifies that a proxy can decide which future
599  versions of the GNU General Public License can be used, that proxy's
600  public statement of acceptance of a version permanently authorizes you
601  to choose that version for the Program.
602
603  Later license versions may give you additional or different
604  permissions.  However, no additional obligations are imposed on any
605  author or copyright holder as a result of your choosing to follow a
606  later version.
607
608  15. Disclaimer of Warranty.
609
610  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
611  APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
612  HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
613  OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
614  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
615  PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
616  IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
617  ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
618
619  16. Limitation of Liability.
620
621  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
622  WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
623  THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
624  GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
625  USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
626  DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
627  PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
628  EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
629  SUCH DAMAGES.
630
631  17. Interpretation of Sections 15 and 16.
632
633  If the disclaimer of warranty and limitation of liability provided
634  above cannot be given local legal effect according to their terms,
635  reviewing courts shall apply local law that most closely approximates
636  an absolute waiver of all civil liability in connection with the
637  Program, unless a warranty or assumption of liability accompanies a
638  copy of the Program in return for a fee.
639
640  END OF TERMS AND CONDITIONS
641  */
642
643 package fr.orsay.lri.varna;
644
645 import java.awt.BasicStroke;
646 import java.awt.Color;
647 import java.awt.Component;
648 import java.awt.Dimension;
649 import java.awt.Font;
650 import java.awt.Graphics;
651 import java.awt.Graphics2D;
652 import java.awt.Point;
653 import java.awt.Rectangle;
654 import java.awt.RenderingHints;
655 import java.awt.Shape;
656 import java.awt.Stroke;
657 import java.awt.event.MouseEvent;
658 import java.awt.geom.AffineTransform;
659 import java.awt.geom.GeneralPath;
660 import java.awt.geom.Point2D;
661 import java.awt.geom.Rectangle2D;
662 import java.awt.print.PrinterException;
663 import java.awt.print.PrinterJob;
664 import java.beans.PropertyChangeEvent;
665 import java.beans.PropertyChangeListener;
666 import java.io.File;
667 import java.io.FileInputStream;
668 import java.io.FileNotFoundException;
669 import java.io.FileOutputStream;
670 import java.io.FileReader;
671 import java.io.IOException;
672 import java.io.InputStream;
673 import java.io.PrintWriter;
674 import java.io.Reader;
675 import java.text.NumberFormat;
676 import java.util.ArrayList;
677 import java.util.Collection;
678 import java.util.Hashtable;
679 import java.util.Set;
680
681 import javax.print.attribute.HashPrintRequestAttributeSet;
682 import javax.print.attribute.PrintRequestAttributeSet;
683 import javax.swing.JOptionPane;
684 import javax.swing.JPanel;
685 import javax.swing.undo.UndoManager;
686 import javax.xml.parsers.ParserConfigurationException;
687 import javax.xml.parsers.SAXParser;
688 import javax.xml.parsers.SAXParserFactory;
689 import javax.xml.transform.OutputKeys;
690 import javax.xml.transform.Transformer;
691 import javax.xml.transform.TransformerConfigurationException;
692 import javax.xml.transform.sax.SAXTransformerFactory;
693 import javax.xml.transform.sax.TransformerHandler;
694 import javax.xml.transform.stream.StreamResult;
695
696 import org.xml.sax.SAXException;
697 import org.xml.sax.helpers.AttributesImpl;
698
699 import fr.orsay.lri.varna.controlers.ControleurBlinkingThread;
700 import fr.orsay.lri.varna.controlers.ControleurClicMovement;
701 import fr.orsay.lri.varna.controlers.ControleurDraggedMolette;
702 import fr.orsay.lri.varna.controlers.ControleurInterpolator;
703 import fr.orsay.lri.varna.controlers.ControleurMolette;
704 import fr.orsay.lri.varna.controlers.ControleurVARNAPanelKeys;
705 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
706 import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;
707 import fr.orsay.lri.varna.exceptions.ExceptionNAViewAlgorithm;
708 import fr.orsay.lri.varna.exceptions.ExceptionNonEqualLength;
709 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
710 import fr.orsay.lri.varna.factories.RNAFactory;
711 import fr.orsay.lri.varna.interfaces.InterfaceVARNABasesListener;
712 import fr.orsay.lri.varna.interfaces.InterfaceVARNAListener;
713 import fr.orsay.lri.varna.interfaces.InterfaceVARNARNAListener;
714 import fr.orsay.lri.varna.interfaces.InterfaceVARNASelectionListener;
715 import fr.orsay.lri.varna.models.BaseList;
716 import fr.orsay.lri.varna.models.FullBackup;
717 import fr.orsay.lri.varna.models.VARNAConfig;
718 import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation;
719 import fr.orsay.lri.varna.models.annotations.HighlightRegionAnnotation;
720 import fr.orsay.lri.varna.models.annotations.TextAnnotation;
721 import fr.orsay.lri.varna.models.export.SwingGraphics;
722 import fr.orsay.lri.varna.models.export.VueVARNAGraphics;
723 import fr.orsay.lri.varna.models.rna.Mapping;
724 import fr.orsay.lri.varna.models.rna.ModeleBP;
725 import fr.orsay.lri.varna.models.rna.ModeleBackbone;
726 import fr.orsay.lri.varna.models.rna.ModeleBackboneElement.BackboneType;
727 import fr.orsay.lri.varna.models.rna.ModeleBase;
728 import fr.orsay.lri.varna.models.rna.ModeleBaseNucleotide;
729 import fr.orsay.lri.varna.models.rna.ModeleBasesComparison;
730 import fr.orsay.lri.varna.models.rna.ModeleColorMap;
731 import fr.orsay.lri.varna.models.rna.RNA;
732 import fr.orsay.lri.varna.utils.VARNASessionParser;
733 import fr.orsay.lri.varna.views.VueMenu;
734 import fr.orsay.lri.varna.views.VueUI;
735
736 /**
737  * 
738  * BH (early) j2s SwingJS Added PropertyChangeListener for returns from VueUI.
739  * 
740  * BH 2019.05.15 flashes white background solution: replaced during-paint
741  * setBackground() with g.setColor();g.fill();
742  * 
743  * BH 2019.05.15 initialization shows popup menu raw creation objects solution:
744  * moved menu creation out of paintComponent()
745  * 
746  * 
747  * The RNA 2D Panel is a lightweight component that allows for an automatic
748  * basic drawing of an RNA secondary structures. The drawing algorithms do not
749  * ensure a non-overlapping drawing of helices, thus it is possible to "spin the
750  * helices" through a click-and-drag approach. A typical usage of the class from
751  * within the constructor of a <code>JFrame</code> would be the following:<br/>
752  * <code>
753  * &nbsp;&nbsp;VARNAPanel _rna = new VARNAPanel("CCCCAUAUGGGGACC","((((....))))...");<br />
754  * &nbsp;&nbsp;this.getContentPane().add(_rna);
755  * </code>
756  * 
757  * @version 3.4
758  * @author Yann Ponty & Kevin Darty
759  * 
760  */
761
762 public class VARNAPanel extends JPanel implements PropertyChangeListener
763 {
764
765   /**
766    * SwingJS uses a PropertyChangeEvent to signal that a pseudo-modal dialog has
767    * been closed.
768    * 
769    * @param event
770    */
771   @Override
772   public void propertyChange(PropertyChangeEvent event)
773   {
774     Object val = event.getNewValue();
775     switch (event.getPropertyName())
776     {
777     case "value":
778       _UI.onDialogReturn(val == null ? JOptionPane.CLOSED_OPTION
779               : ((Integer) val).intValue());
780       return;
781     case "SelectedFile":
782     case "SelectedColor":
783     case "inputValue":
784       _UI.onDialogReturn(val);
785       break;
786     }
787   }
788
789   private static final long serialVersionUID = 8194421570308956001L;
790
791   private RNA _RNA = new RNA();
792
793   private boolean _debug = false;
794
795   private VARNAConfig _conf = new VARNAConfig();
796
797   private ArrayList<InterfaceVARNAListener> _VARNAListeners = new ArrayList<>();
798
799   private ArrayList<InterfaceVARNASelectionListener> _selectionListeners = new ArrayList<>();
800
801   private ArrayList<InterfaceVARNARNAListener> _RNAListeners = new ArrayList<>();
802
803   private ArrayList<InterfaceVARNABasesListener> _basesListeners = new ArrayList<>();
804
805   UndoManager _manager;
806
807   // private boolean _foldMode = true;
808
809   private Point2D.Double[] _realCoords = new Point2D.Double[0];
810
811   private Point2D.Double[] _realCenters = new Point2D.Double[0];
812
813   private double _scaleFactor = 1.0;
814
815   private Point2D.Double _offsetPanel = new Point2D.Double();
816
817   private Point2D.Double _offsetRNA = new Point2D.Double();
818
819   private double _offX;
820
821   private double _offY;
822
823   private ControleurBlinkingThread _blink;
824
825   private BaseList _selectedBases = new BaseList("selection");
826
827   private ArrayList<ModeleBase> _backupSelection = new ArrayList<>();
828
829   private Integer _nearestBase = null;
830
831   private Point2D.Double _lastSelectedCoord = new Point2D.Double(0.0, 0.0);
832
833   private Point2D.Double _linkOrigin = null;
834
835   private Point2D.Double _linkDestination = null;
836
837   private Rectangle _selectionRectangle = null;
838
839   private boolean _highlightAnnotation = false;
840
841   private int _titleHeight;
842
843   // BH SwingJS issue here is that we are using _border already. Hmm.
844   private Dimension _border = new Dimension(0, 0);
845
846   private boolean _drawBBox = false;
847
848   private boolean _drawBorder = false;
849
850   // private Point _positionRelativeSouris;
851   private Point _translation;
852
853   private boolean _horsCadre;
854
855   private boolean _premierAffichage;
856
857   private ControleurInterpolator _interpolator;
858
859   /**
860    * If comparison mode is TRUE (ON), then the application will be used to
861    * display a super-structure resulting on an RNA secondary structure
862    * comparison. Else, the application is used by default.
863    */
864
865   private VueMenu _popup = new VueMenu(this);
866
867   private VueUI _UI = new VueUI(this);
868
869   private TextAnnotation _selectedAnnotation;
870
871   /**
872    * Creates an RNA 2D panel with initially displays the empty structure.
873    * 
874    * @throws ExceptionNonEqualLength
875    * 
876    */
877   public VARNAPanel()
878   {
879     init();
880     drawRNA();
881   }
882
883   /**
884    * Creates an RNA 2D panel, and creates and displays an RNA coupled with its
885    * secondary structure formatted as a well-balanced parenthesis with dots word
886    * (DBN format).
887    * 
888    * @param seq
889    *          The raw nucleotide sequence
890    * @param str
891    *          The secondary structure in DBN format
892    * @throws ExceptionNonEqualLength
893    */
894
895   public VARNAPanel(String seq, String str) throws ExceptionNonEqualLength
896   {
897     this(seq, str, RNA.DRAW_MODE_RADIATE);
898   }
899
900   /**
901    * Creates a VARNAPanel instance, and creates and displays an RNA coupled with
902    * its secondary structure formatted as a well-balanced parenthesis with dots
903    * word (DBN format). Allows the user to choose the drawing algorithm to be
904    * used.
905    * 
906    * @param seq
907    *          The raw nucleotide sequence
908    * @param str
909    *          The secondary structure in DBN format
910    * @param drawMode
911    *          The drawing mode
912    * @throws ExceptionNonEqualLength
913    * @see RNA#DRAW_MODE_RADIATE
914    * @see RNA#DRAW_MODE_CIRCULAR
915    * @see RNA#DRAW_MODE_NAVIEW
916    */
917   public VARNAPanel(String seq, String str, int drawMode)
918           throws ExceptionNonEqualLength
919   {
920     this(seq, str, drawMode, "");
921   }
922
923   public VARNAPanel(Reader r)
924           throws ExceptionNonEqualLength, ExceptionFileFormatOrSyntax
925   {
926     this(r, RNA.DRAW_MODE_RADIATE);
927   }
928
929   public VARNAPanel(Reader r, int drawMode)
930           throws ExceptionNonEqualLength, ExceptionFileFormatOrSyntax
931   {
932     this(r, drawMode, "");
933   }
934
935   public VARNAPanel(Reader r, int drawMode, String title)
936           throws ExceptionNonEqualLength, ExceptionFileFormatOrSyntax
937   {
938     init();
939     drawRNA(r, drawMode);
940     setTitle(title);
941   }
942
943   public void setOriginLink(Point2D.Double p)
944   {
945     _linkOrigin = (p);
946   }
947
948   public void setDestinationLink(Point2D.Double p)
949   {
950     _linkDestination = (p);
951   }
952
953   public void removeLink()
954   {
955     _linkOrigin = null;
956     _linkDestination = null;
957   }
958
959   /**
960    * Creates a VARNAPanel instance, and displays an RNA.
961    * 
962    * @param r
963    *          The RNA to be displayed within this panel
964    */
965
966   public VARNAPanel(RNA r)
967   {
968     showRNA(r);
969     init();
970   }
971
972   /**
973    * Creates a VARNAPanel instance, and creates and displays an RNA coupled with
974    * its secondary structure formatted as a well-balanced parenthesis with dots
975    * word (DBN format). Allows the user to choose the drawing algorithm to be
976    * used. Additionally, sets the panel's title.
977    * 
978    * @param seq
979    *          The raw nucleotide sequence
980    * @param str
981    *          The secondary structure in DBN format
982    * @param drawMode
983    *          The drawing mode
984    * @param title
985    *          The panel title
986    * @throws ExceptionNonEqualLength
987    * @see RNA#DRAW_MODE_CIRCULAR
988    * @see RNA#DRAW_MODE_RADIATE
989    * @see RNA#DRAW_MODE_NAVIEW
990    */
991
992   public VARNAPanel(String seq, String str, int drawMode, String title)
993           throws ExceptionNonEqualLength
994   {
995     drawRNA(seq, str, drawMode);
996     init();
997     setTitle(title);
998     // VARNASecDraw._vp = this;
999   }
1000
1001   public VARNAPanel(String seq1, String struct1, String seq2,
1002           String struct2, int drawMode, String title)
1003   {
1004     _conf._comparisonMode = true;
1005     drawRNA(seq1, struct1, seq2, struct2, drawMode);
1006     init();
1007     setTitle(title);
1008   }
1009
1010   private void init()
1011   {
1012     _popup.buildPopupMenu();
1013     // BH 2019.05.16 *add* a popup menu? SwingJS issue here -- actually does ADD
1014     // the menu
1015     // this.add(_popup);
1016     setBackground(VARNAConfig.DEFAULT_BACKGROUND_COLOR);
1017     _manager = new UndoManager();
1018     _manager.setLimit(10000);
1019     _UI.addUndoableEditListener(_manager);
1020
1021     _blink = new ControleurBlinkingThread(this,
1022             ControleurBlinkingThread.DEFAULT_FREQUENCY, 0, 1.0, 0.0, 0.2);
1023     _blink.start();
1024
1025     _premierAffichage = true;
1026     _translation = new Point(0, 0);
1027
1028     _horsCadre = false;
1029     this.setFont(_conf._fontBasesGeneral);
1030
1031     // ajout des controleurs au VARNAPanel
1032     ControleurClicMovement controleurClicMovement = new ControleurClicMovement(
1033             this);
1034     this.addMouseListener(controleurClicMovement);
1035     this.addMouseMotionListener(controleurClicMovement);
1036     this.addMouseWheelListener(new ControleurMolette(this));
1037
1038     ControleurDraggedMolette ctrlDraggedMolette = new ControleurDraggedMolette(
1039             this);
1040     this.addMouseMotionListener(ctrlDraggedMolette);
1041     this.addMouseListener(ctrlDraggedMolette);
1042
1043     ControleurVARNAPanelKeys ctrlKey = new ControleurVARNAPanelKeys(this);
1044     this.addKeyListener(ctrlKey);
1045     this.addFocusListener(ctrlKey);
1046
1047     _interpolator = new ControleurInterpolator(this);
1048     /**
1049      * 
1050      * BH SwingJS do not start this thread
1051      * 
1052      * @j2sNative
1053      */
1054     {
1055       _interpolator.start();
1056     }
1057
1058   }
1059
1060   public void undo()
1061   {
1062     if (_manager.canUndo())
1063     {
1064       _manager.undo();
1065     }
1066   }
1067
1068   public void redo()
1069   {
1070     if (_manager.canRedo())
1071     {
1072       _manager.redo();
1073     }
1074   }
1075
1076   /**
1077    * Sets the new style of the title font.
1078    * 
1079    * @param newStyle
1080    *          An int that describes the new font style ("PLAIN","BOLD",
1081    *          "BOLDITALIC", or "ITALIC")
1082    */
1083   public void setTitleFontStyle(int newStyle)
1084   {
1085     _conf._titleFont = _conf._titleFont.deriveFont(newStyle);
1086     updateTitleHeight();
1087   }
1088
1089   /**
1090    * Sets the new size of the title font.
1091    * 
1092    * @param newSize
1093    *          The new size of the title font
1094    */
1095   public void setTitleFontSize(float newSize)
1096   {
1097     // System.err.println("Applying title size "+newSize);
1098     _conf._titleFont = _conf._titleFont.deriveFont(newSize);
1099     updateTitleHeight();
1100   }
1101
1102   /**
1103    * Sets the new font family to be used for the title. Available fonts are
1104    * system-specific, yet it seems that "Arial", "Dialog", and "MonoSpaced" are
1105    * almost always available.
1106    * 
1107    * @param newFamily
1108    *          New font family used for the title
1109    */
1110   public void setTitleFontFamily(String newFamily)
1111   {
1112     _conf._titleFont = new Font(newFamily, _conf._titleFont.getStyle(),
1113             _conf._titleFont.getSize());
1114     updateTitleHeight();
1115   }
1116
1117   /**
1118    * Sets the color to be used for the title.
1119    * 
1120    * @param newColor
1121    *          A color used to draw the title
1122    */
1123   public void setTitleFontColor(Color newColor)
1124   {
1125     _conf._titleColor = newColor;
1126     updateTitleHeight();
1127   }
1128
1129   /**
1130    * Sets the font size for displaying bases
1131    * 
1132    * @param size
1133    *          Font size for base caption
1134    */
1135
1136   public void setBaseFontSize(Float size)
1137   {
1138     _conf._fontBasesGeneral = _conf._fontBasesGeneral.deriveFont(size);
1139   }
1140
1141   /**
1142    * Sets the font size for displaying base numbers
1143    * 
1144    * @param size
1145    *          Font size for base numbers
1146    */
1147
1148   public void setNumbersFontSize(Float size)
1149   {
1150     _conf._numbersFont = _conf._numbersFont.deriveFont(size);
1151   }
1152
1153   /**
1154    * Sets the font style for displaying bases
1155    * 
1156    * @param style
1157    *          An int that describes the new font style ("PLAIN","BOLD",
1158    *          "BOLDITALIC", or "ITALIC")
1159    */
1160
1161   public void setBaseFontStyle(int style)
1162   {
1163     _conf._fontBasesGeneral = _conf._fontBasesGeneral.deriveFont(style);
1164   }
1165
1166   private void updateTitleHeight()
1167   {
1168     if (!getTitle().equals(""))
1169     {
1170       _titleHeight = (int) (_conf._titleFont.getSize() * 1.5);
1171     }
1172     else
1173     {
1174       _titleHeight = 0;
1175     }
1176     if (Math.abs(this.getZoom() - 1) < .02)
1177     {
1178       _translation.y = (int) (-getTitleHeight() / 2.0);
1179     }
1180   }
1181
1182   /**
1183    * Sets the panel's title, giving a short description of the RNA secondary
1184    * structure.
1185    * 
1186    * @param title
1187    *          The new title
1188    */
1189   public void setTitle(String title)
1190   {
1191     _RNA.setName(title);
1192     updateTitleHeight();
1193   }
1194
1195   /**
1196    * Sets the distance between consecutive base numbers. Please notice that :
1197    * <ul>
1198    * <li>The first and last base are always numbered</li>
1199    * <li>The numbering is based on the base numbers, not on the indices. So base
1200    * numbers may appear more frequently than expected if bases are skipped</li>
1201    * <li>The periodicity is measured starting from 0. This means that for a
1202    * period of 10 and bases numbered from 1 to 52, the base numbers
1203    * [1,10,20,30,40,50,52] will be drawn.</li>
1204    * </ul>
1205    * 
1206    * @param n
1207    *          New numbering period
1208    */
1209   public void setNumPeriod(int n)
1210   {
1211     _conf._numPeriod = n;
1212   }
1213
1214   /**
1215    * Returns the current numbering period. Please notice that :
1216    * <ul>
1217    * <li>The first and last base are always numbered</li>
1218    * <li>The numbering is based on the base numbers, not on the indices. So base
1219    * numbers may appear more frequently than expected if bases are skipped</li>
1220    * <li>The periodicity is measured starting from 0. This means that for a
1221    * period of 10 and bases numbered from 1 to 52, the base numbers
1222    * [1,10,20,30,40,50,52] will be drawn.</li>
1223    * </ul>
1224    * 
1225    * @return Current numbering period
1226    */
1227   public int getNumPeriod()
1228   {
1229     return _conf._numPeriod;
1230   }
1231
1232   private void setScaleFactor(double d)
1233   {
1234     _scaleFactor = d;
1235   }
1236
1237   private double getScaleFactor()
1238   {
1239     return _scaleFactor;
1240   }
1241
1242   private void setAutoFit(boolean fit)
1243   {
1244     _conf._autoFit = fit;
1245     repaint();
1246   }
1247
1248   public void lockScrolling()
1249   {
1250     setAutoFit(false);
1251     setAutoCenter(false);
1252   }
1253
1254   public void unlockScrolling()
1255   {
1256     setAutoFit(true);
1257     setAutoCenter(true);
1258   }
1259
1260   private void drawStringOutline(VueVARNAGraphics g2D, String res, double x,
1261           double y, double margin)
1262   {
1263     Dimension d = g2D.getStringDimension(res);
1264     x -= d.width / 2.0;
1265     y += d.height / 2.0;
1266     g2D.setColor(Color.GRAY);
1267     g2D.setSelectionStroke();
1268     g2D.drawRect((x - margin), (y - d.height - margin),
1269             (d.width + 2.0 * margin), (d.height + 2.0 * margin));
1270   }
1271
1272   private void drawSymbol(VueVARNAGraphics g2D, double posx, double posy,
1273           double normx, double normy, double radius, boolean isCIS,
1274           ModeleBP.Edge e)
1275   {
1276     Color bck = g2D.getColor();
1277     switch (e)
1278     {
1279     case WC:
1280       if (isCIS)
1281       {
1282         g2D.setColor(bck);
1283         g2D.fillCircle((posx - (radius) / 2.0), (posy - (radius) / 2.0),
1284                 radius);
1285         g2D.drawCircle((posx - (radius) / 2.0), (posy - (radius) / 2.0),
1286                 radius);
1287       }
1288       else
1289       {
1290         g2D.setColor(Color.white);
1291         g2D.fillCircle(posx - (radius) / 2.0, (posy - (radius) / 2.0),
1292                 (radius));
1293         g2D.setColor(bck);
1294         g2D.drawCircle((posx - (radius) / 2.0), (posy - (radius) / 2.0),
1295                 (radius));
1296       }
1297       break;
1298     case HOOGSTEEN:
1299     {
1300       GeneralPath p2 = new GeneralPath();
1301       radius /= 1.05;
1302       p2.moveTo(
1303               (float) (posx - radius * normx / 2.0 - radius * normy / 2.0),
1304               (float) (posy - radius * normy / 2.0 + radius * normx / 2.0));
1305       p2.lineTo(
1306               (float) (posx + radius * normx / 2.0 - radius * normy / 2.0),
1307               (float) (posy + radius * normy / 2.0 + radius * normx / 2.0));
1308       p2.lineTo(
1309               (float) (posx + radius * normx / 2.0 + radius * normy / 2.0),
1310               (float) (posy + radius * normy / 2.0 - radius * normx / 2.0));
1311       p2.lineTo(
1312               (float) (posx - radius * normx / 2.0 + radius * normy / 2.0),
1313               (float) (posy - radius * normy / 2.0 - radius * normx / 2.0));
1314       p2.closePath();
1315
1316       if (isCIS)
1317       {
1318         g2D.setColor(bck);
1319         g2D.fill(p2);
1320         g2D.draw(p2);
1321       }
1322       else
1323       {
1324         g2D.setColor(Color.white);
1325         g2D.fill(p2);
1326         g2D.setColor(bck);
1327         g2D.draw(p2);
1328       }
1329     }
1330       break;
1331     case SUGAR:
1332     {
1333       double ix = radius * normx / 2.0;
1334       double iy = radius * normy / 2.0;
1335       double jx = radius * normy / 2.0;
1336       double jy = -radius * normx / 2.0;
1337
1338       GeneralPath p2 = new GeneralPath();
1339       p2.moveTo((float) (posx - ix + jx), (float) (posy - iy + jy));
1340       p2.lineTo((float) (posx + ix + jx), (float) (posy + iy + jy));
1341       p2.lineTo((float) (posx - jx), (float) (posy - jy));
1342       p2.closePath();
1343
1344       if (isCIS)
1345       {
1346         g2D.setColor(bck);
1347         g2D.fill(p2);
1348         g2D.draw(p2);
1349       }
1350       else
1351       {
1352         g2D.setColor(Color.white);
1353         g2D.fill(p2);
1354         g2D.setColor(bck);
1355         g2D.draw(p2);
1356       }
1357     }
1358       break;
1359     }
1360     g2D.setColor(bck);
1361   }
1362
1363   private void drawBasePairArc(VueVARNAGraphics g2D, int i, int j,
1364           Point2D.Double orig, Point2D.Double dest, double scaleFactor,
1365           ModeleBP style, double newRadius)
1366   {
1367     double distance, coef;
1368     if (j - i == 1)
1369     {
1370       coef = getBPHeightIncrement() * 1.75;
1371     }
1372     else
1373     {
1374       coef = getBPHeightIncrement();
1375     }
1376     distance = dest.x - orig.x;
1377     switch (_conf._mainBPStyle)
1378     {
1379     case LW:
1380     {
1381       double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS)
1382               / 5.0) * scaleFactor;
1383       if (style.isCanonical())
1384       {
1385         if (style.isCanonicalGC())
1386         {
1387           if ((orig.x != dest.x) || (orig.y != dest.y))
1388           {
1389             g2D.drawArc((dest.x + orig.x) / 2.,
1390                     dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1391                     (distance - scaleFactor * _RNA.BASE_RADIUS / 3.0),
1392                     (distance * coef
1393                             - scaleFactor * _RNA.BASE_RADIUS / 3.0),
1394                     0, 180);
1395             g2D.drawArc((dest.x + orig.x) / 2.,
1396                     dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1397                     (distance + scaleFactor * _RNA.BASE_RADIUS / 3.0),
1398                     (distance * coef
1399                             + scaleFactor * _RNA.BASE_RADIUS / 3.0),
1400                     0, 180);
1401           }
1402         }
1403         else if (style.isCanonicalAU())
1404         {
1405           g2D.drawArc((dest.x + orig.x) / 2.,
1406                   dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0, (distance),
1407                   (distance * coef), 0, 180);
1408         }
1409         else if (style.isWobbleUG())
1410         {
1411           Point2D.Double midtop = new Point2D.Double((dest.x + orig.x) / 2.,
1412                   dest.y - distance * coef / 2.
1413                           - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1414           g2D.drawArc(midtop.x,
1415                   dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0, (distance),
1416                   (distance * coef), 0, 180);
1417           drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle, false,
1418                   ModeleBP.Edge.WC);
1419         }
1420         else
1421         {
1422           Point2D.Double midtop = new Point2D.Double((dest.x + orig.x) / 2.,
1423                   dest.y - distance * coef / 2.
1424                           - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1425           g2D.drawArc(midtop.x,
1426                   dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0, (distance),
1427                   (distance * coef), 0, 180);
1428           drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle,
1429                   style.isCIS(), style.getEdgePartner5());
1430         }
1431       }
1432       else
1433       {
1434         ModeleBP.Edge p1 = style.getEdgePartner5();
1435         ModeleBP.Edge p2 = style.getEdgePartner3();
1436         Point2D.Double midtop = new Point2D.Double((dest.x + orig.x) / 2.,
1437                 dest.y - distance * coef / 2.
1438                         - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1439         g2D.drawArc(midtop.x, dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1440                 (distance), (distance * coef), 0, 180);
1441         if (p1 == p2)
1442         {
1443           drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle, false,
1444                   style.getEdgePartner5());
1445         }
1446         else
1447         {
1448           drawSymbol(g2D, midtop.x - scaleFactor * _RNA.BASE_RADIUS,
1449                   midtop.y, 1., 0., radiusCircle, style.isCIS(), p1);
1450           drawSymbol(g2D, midtop.x + scaleFactor * _RNA.BASE_RADIUS,
1451                   midtop.y, -1., 0., radiusCircle, style.isCIS(), p2);
1452         }
1453       }
1454     }
1455       break;
1456     case LW_ALT:
1457     {
1458       double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS)
1459               / 5.0) * scaleFactor;
1460       double distFromBaseCenter = DISTANCE_FACT * scaleFactor;
1461       orig = new Point2D.Double(orig.x,
1462               orig.y - (distFromBaseCenter + newRadius));
1463       dest = new Point2D.Double(dest.x,
1464               dest.y - (distFromBaseCenter + newRadius));
1465       if (style.isCanonical())
1466       {
1467         if (style.isCanonicalGC())
1468         {
1469           if ((orig.x != dest.x) || (orig.y != dest.y))
1470           {
1471             g2D.drawArc((dest.x + orig.x) / 2.,
1472                     dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1473                     (distance - scaleFactor * _RNA.BASE_RADIUS / 3.0),
1474                     (distance * coef
1475                             - scaleFactor * _RNA.BASE_RADIUS / 3.0),
1476                     0, 180);
1477             g2D.drawArc((dest.x + orig.x) / 2.,
1478                     dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1479                     (distance + scaleFactor * _RNA.BASE_RADIUS / 3.0),
1480                     (distance * coef
1481                             + scaleFactor * _RNA.BASE_RADIUS / 3.0),
1482                     0, 180);
1483           }
1484         }
1485         else if (style.isCanonicalAU())
1486         {
1487           g2D.drawArc((dest.x + orig.x) / 2.,
1488                   dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0, (distance),
1489                   (distance * coef), 0, 180);
1490         }
1491       }
1492       else
1493       {
1494         ModeleBP.Edge p1 = style.getEdgePartner5();
1495         ModeleBP.Edge p2 = style.getEdgePartner3();
1496         Point2D.Double midtop = new Point2D.Double((dest.x + orig.x) / 2.,
1497                 dest.y - distance * coef / 2.
1498                         - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1499         g2D.drawArc(midtop.x, dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1500                 (distance), (distance * coef), 0, 180);
1501         drawSymbol(g2D, orig.x, orig.y - radiusCircle * .95, 1., 0.,
1502                 radiusCircle, style.isCIS(), p1);
1503         drawSymbol(g2D, dest.x, dest.y - radiusCircle * .95, -1., 0.,
1504                 radiusCircle, style.isCIS(), p2);
1505       }
1506     }
1507       break;
1508     default:
1509       g2D.drawArc((dest.x + orig.x) / 2.,
1510               dest.y - scaleFactor * _RNA.BASE_RADIUS / 2.0, (distance),
1511               (distance * coef), 0, 180);
1512       break;
1513     }
1514
1515   }
1516
1517   public static double DISTANCE_FACT = 2.;
1518
1519   private void drawBasePair(VueVARNAGraphics g2D, Point2D.Double orig,
1520           Point2D.Double dest, ModeleBP style, double newRadius,
1521           double scaleFactor)
1522   {
1523
1524     double dx = dest.x - orig.x;
1525     double dy = dest.y - orig.y;
1526     double dist = Math.sqrt((dest.x - orig.x) * (dest.x - orig.x)
1527             + (dest.y - orig.y) * (dest.y - orig.y));
1528     dx /= dist;
1529     dy /= dist;
1530     double nx = -dy;
1531     double ny = dx;
1532     orig = new Point2D.Double(orig.x + newRadius * dx,
1533             orig.y + newRadius * dy);
1534     dest = new Point2D.Double(dest.x - newRadius * dx,
1535             dest.y - newRadius * dy);
1536     switch (_conf._mainBPStyle)
1537     {
1538     case LW:
1539     {
1540       double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS)
1541               / 5.0) * scaleFactor;
1542       if (style.isCanonical())
1543       {
1544         if (style.isCanonicalGC())
1545         {
1546           if ((orig.x != dest.x) || (orig.y != dest.y))
1547           {
1548             nx *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1549             ny *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1550             g2D.drawLine((orig.x + nx), (orig.y + ny), (dest.x + nx),
1551                     (dest.y + ny));
1552             g2D.drawLine((orig.x - nx), (orig.y - ny), (dest.x - nx),
1553                     (dest.y - ny));
1554           }
1555         }
1556         else if (style.isCanonicalAU())
1557         {
1558           g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1559         }
1560         else if (style.isWobbleUG())
1561         {
1562           double cx = (dest.x + orig.x) / 2.0;
1563           double cy = (dest.y + orig.y) / 2.0;
1564           g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1565           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, false,
1566                   ModeleBP.Edge.WC);
1567         }
1568         else
1569         {
1570           double cx = (dest.x + orig.x) / 2.0;
1571           double cy = (dest.y + orig.y) / 2.0;
1572           g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1573           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, style.isCIS(),
1574                   style.getEdgePartner5());
1575         }
1576       }
1577       else
1578       {
1579         ModeleBP.Edge p1 = style.getEdgePartner5();
1580         ModeleBP.Edge p2 = style.getEdgePartner3();
1581         double cx = (dest.x + orig.x) / 2.0;
1582         double cy = (dest.y + orig.y) / 2.0;
1583         g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1584         if (p1 == p2)
1585         {
1586           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, style.isCIS(), p1);
1587
1588         }
1589         else
1590         {
1591           double vdx = (dest.x - orig.x);
1592           double vdy = (dest.y - orig.y);
1593           vdx /= 6.0;
1594           vdy /= 6.0;
1595           drawSymbol(g2D, cx + vdx, cy + vdy, -nx, -ny, radiusCircle,
1596                   style.isCIS(), p2);
1597           drawSymbol(g2D, cx - vdx, cy - vdy, nx, ny, radiusCircle,
1598                   style.isCIS(), p1);
1599         }
1600       }
1601     }
1602       break;
1603     case LW_ALT:
1604     {
1605       double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS)
1606               / 5.0) * scaleFactor;
1607       double distFromBaseCenter = DISTANCE_FACT * scaleFactor;
1608       Point2D.Double norig = new Point2D.Double(
1609               orig.x + (distFromBaseCenter + .5 * newRadius) * dx,
1610               orig.y + (distFromBaseCenter + .5 * newRadius) * dy);
1611       Point2D.Double ndest = new Point2D.Double(
1612               dest.x - (distFromBaseCenter + .5 * newRadius) * dx,
1613               dest.y - (distFromBaseCenter + .5 * newRadius) * dy);
1614       if (style.isCanonical())
1615       {
1616         if (style.isCanonicalGC())
1617         {
1618           if ((norig.x != ndest.x) || (norig.y != ndest.y))
1619           {
1620             nx *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1621             ny *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1622             g2D.drawLine((norig.x + nx), (norig.y + ny), (ndest.x + nx),
1623                     (ndest.y + ny));
1624             g2D.drawLine((norig.x - nx), (norig.y - ny), (ndest.x - nx),
1625                     (ndest.y - ny));
1626           }
1627         }
1628         else if (style.isCanonicalAU())
1629         {
1630           g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1631         }
1632         else if (style.isWobbleUG())
1633         {
1634           double cx = (ndest.x + norig.x) / 2.0;
1635           double cy = (ndest.y + norig.y) / 2.0;
1636           g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1637           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, false,
1638                   ModeleBP.Edge.WC);
1639         }
1640         else
1641         {
1642           double cx = (ndest.x + norig.x) / 2.0;
1643           double cy = (ndest.y + norig.y) / 2.0;
1644           g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1645           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, style.isCIS(),
1646                   style.getEdgePartner5());
1647         }
1648       }
1649       else
1650       {
1651         ModeleBP.Edge p1 = style.getEdgePartner5();
1652         ModeleBP.Edge p2 = style.getEdgePartner3();
1653         double cx = (ndest.x + norig.x) / 2.0;
1654         double cy = (ndest.y + norig.y) / 2.0;
1655         g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1656         if (p1 == p2)
1657         {
1658           drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, style.isCIS(), p1);
1659
1660         }
1661         else
1662         {
1663           double fac = .4;
1664           drawSymbol(g2D, ndest.x - fac * radiusCircle * dx,
1665                   ndest.y - fac * radiusCircle * dy, -nx, -ny, radiusCircle,
1666                   style.isCIS(), p2);
1667           drawSymbol(g2D, norig.x + fac * radiusCircle * dx,
1668                   norig.y + fac * radiusCircle * dy, nx, ny, radiusCircle,
1669                   style.isCIS(), p1);
1670         }
1671       }
1672     }
1673       break;
1674     case SIMPLE:
1675       g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1676       break;
1677     case RNAVIZ:
1678       double xcenter = (orig.x + dest.x) / 2.0;
1679       double ycenter = (orig.y + dest.y) / 2.0;
1680       double radius = Math.max(4.0 * scaleFactor, 1.0);
1681       g2D.fillCircle((xcenter - radius), (ycenter - radius),
1682               (2.0 * radius));
1683       break;
1684     case NONE:
1685       break;
1686     }
1687   }
1688
1689   private Color getHighlightedVersion(Color c1, Color c2)
1690   {
1691     int r1 = c1.getRed();
1692     int g1 = c1.getGreen();
1693     int b1 = c1.getBlue();
1694     int r2 = c2.getRed();
1695     int g2 = c2.getGreen();
1696     int b2 = c2.getBlue();
1697     double val = _blink.getVal();
1698     int nr = Math.max(0,
1699             Math.min((int) ((r1 * val + r2 * (1.0 - val))), 255));
1700     int ng = Math.max(0,
1701             Math.min((int) ((g1 * val + g2 * (1.0 - val))), 255));
1702     int nb = Math.max(0,
1703             Math.min((int) ((b1 * val + b2 * (1.0 - val))), 255));
1704     return new Color(nr, ng, nb);
1705   }
1706
1707   private Color highlightFilter(int index, Color initialColor, Color c1,
1708           Color c2, boolean localView)
1709   {
1710     if (_selectedBases.contains(_RNA.getBaseAt(index)) && localView)
1711     {
1712       return getHighlightedVersion(c1, c2);
1713     }
1714     else
1715     {
1716       return initialColor;
1717     }
1718   }
1719
1720   public static Point2D.Double computeExcentricUnitVector(int i,
1721           Point2D.Double[] points, Point2D.Double[] centers)
1722   {
1723     double dist = points[i].distance(centers[i]);
1724     Point2D.Double byCenter = new Point2D.Double(
1725             (points[i].x - centers[i].x) / dist,
1726             (points[i].y - centers[i].y) / dist);
1727     if ((i > 0) && (i < points.length - 1))
1728     {
1729       Point2D.Double p0 = points[i - 1];
1730       Point2D.Double p1 = points[i];
1731       Point2D.Double p2 = points[i + 1];
1732       double dist1 = p2.distance(p1);
1733       Point2D.Double v1 = new Point2D.Double((p2.x - p1.x) / dist1,
1734               (p2.y - p1.y) / dist1);
1735       Point2D.Double vn1 = new Point2D.Double(v1.y, -v1.x);
1736       double dist2 = p1.distance(p0);
1737       Point2D.Double v2 = new Point2D.Double((p1.x - p0.x) / dist2,
1738               (p1.y - p0.y) / dist2);
1739       Point2D.Double vn2 = new Point2D.Double(v2.y, -v2.x);
1740       Point2D.Double vn = new Point2D.Double((vn1.x + vn2.x) / 2.0,
1741               (vn1.y + vn2.y) / 2.0);
1742       double D = vn.distance(new Point2D.Double(0.0, 0.0));
1743       vn.x /= D;
1744       vn.y /= D;
1745       if (byCenter.x * vn.x + byCenter.y * vn.y < 0)
1746       {
1747         vn.x = -vn.x;
1748         vn.y = -vn.y;
1749       }
1750       return vn;
1751     }
1752     else if (((i == 0) || (i == points.length - 1)) && (points.length > 1))
1753     {
1754       int a = (i == 0) ? 0 : points.length - 1;
1755       int b = (i == 0) ? 1 : points.length - 2;
1756       double D = points[a].distance(points[b]);
1757       return new Point2D.Double((points[a].x - points[b].x) / D,
1758               (points[a].y - points[b].y) / D);
1759     }
1760     else
1761     {
1762       return byCenter;
1763     }
1764   }
1765
1766   private void drawBase(VueVARNAGraphics g2D, int i,
1767           Point2D.Double[] points, Point2D.Double[] centers,
1768           double newRadius, double _scaleFactor, boolean localView)
1769   {
1770     Point2D.Double p = points[i];
1771     ModeleBase mb = _RNA.get_listeBases().get(i);
1772     g2D.setFont(_conf._fontBasesGeneral);
1773     Color baseInnerColor = highlightFilter(i,
1774             _RNA.getBaseInnerColor(i, _conf), Color.white,
1775             _RNA.getBaseInnerColor(i, _conf), localView);
1776     Color baseOuterColor = highlightFilter(i,
1777             _RNA.getBaseOuterColor(i, _conf),
1778             _RNA.getBaseOuterColor(i, _conf), Color.white, localView);
1779     Color baseNameColor = highlightFilter(i,
1780             _RNA.getBaseNameColor(i, _conf),
1781             _RNA.getBaseNameColor(i, _conf), Color.white, localView);
1782     if (RNA.whiteLabelPreferrable(baseInnerColor))
1783     {
1784       baseNameColor = Color.white;
1785     }
1786
1787     if (mb instanceof ModeleBaseNucleotide)
1788     {
1789       ModeleBaseNucleotide mbn = (ModeleBaseNucleotide) mb;
1790       String res = mbn.getBase();
1791       if (_hoveredBase == mb && localView && isModifiable())
1792       {
1793         g2D.setColor(_conf._hoverColor);
1794         g2D.fillCircle(p.getX() - 1.5 * newRadius,
1795                 p.getY() - 1.5 * newRadius, 3.0 * newRadius);
1796         g2D.setColor(_conf._hoverColor.darker());
1797         g2D.drawCircle(p.getX() - 1.5 * newRadius,
1798                 p.getY() - 1.5 * newRadius, 3.0 * newRadius);
1799         g2D.setPlainStroke();
1800       }
1801       if (_conf._fillBases)
1802       {
1803         // Filling inner circle
1804         g2D.setColor(baseInnerColor);
1805         g2D.fillCircle(p.getX() - newRadius, p.getY() - newRadius,
1806                 2.0 * newRadius);
1807       }
1808
1809       if (_conf._drawOutlineBases)
1810       {
1811         // Drawing outline
1812         g2D.setColor(baseOuterColor);
1813         g2D.setStrokeThickness(_conf._baseThickness * _scaleFactor);
1814         g2D.drawCircle(p.getX() - newRadius, p.getY() - newRadius,
1815                 2.0 * newRadius);
1816       }
1817       // Drawing label
1818       g2D.setColor(baseNameColor);
1819       g2D.drawStringCentered(String.valueOf(res), p.getX(), p.getY());
1820     }
1821     else if (mb instanceof ModeleBasesComparison)
1822     {
1823
1824       ModeleBasesComparison mbc = (ModeleBasesComparison) mb;
1825
1826       // On lui donne l'aspect voulue (on a un trait droit)
1827       g2D.setPlainStroke(); // On doit avoir un trait droit, sans arrondit
1828       g2D.setStrokeThickness(_conf._baseThickness * _scaleFactor);
1829
1830       // On dessine l'étiquette, rectangle aux bords arrondies.
1831       g2D.setColor(baseInnerColor);
1832       g2D.fillRoundRect((p.getX() - 1.5 * newRadius),
1833               (p.getY() - newRadius), (3.0 * newRadius), (2.0 * newRadius),
1834               10 * _scaleFactor, 10 * _scaleFactor);
1835
1836       /* Dessin du rectangle exterieur (bords) */
1837       g2D.setColor(baseOuterColor);
1838       g2D.drawRoundRect((p.getX() - 1.5 * newRadius),
1839               (p.getY() - newRadius), (3 * newRadius), (2 * newRadius),
1840               10 * _scaleFactor, 10 * _scaleFactor);
1841
1842       // On le dessine au centre de l'étiquette.
1843       g2D.drawLine((p.getX()), (p.getY() + newRadius) - 1, (p.getX()),
1844               (p.getY() - newRadius) + 1);
1845
1846       /* Dessin du nom de la base (A,C,G,U,etc...) */
1847       // On créer le texte des étiquettes
1848       String label1 = String.valueOf(mbc.getBase1());
1849       String label2 = String.valueOf(mbc.getBase2());
1850
1851       // On leur donne une couleur
1852       g2D.setColor(getRNA().get_listeBases().get(i).getStyleBase()
1853               .getBaseNameColor());
1854
1855       // Et on les dessine.
1856       g2D.drawStringCentered(label1, p.getX() - (.75 * newRadius),
1857               p.getY());
1858       g2D.drawStringCentered(label2, p.getX() + (.75 * newRadius),
1859               p.getY());
1860     }
1861
1862     // Drawing base number
1863     if (_RNA.isNumberDrawn(mb, getNumPeriod()))
1864     {
1865
1866       Point2D.Double vn = computeExcentricUnitVector(i, points, centers);
1867       g2D.setColor(mb.getStyleBase().getBaseNumberColor());
1868       g2D.setFont(_conf._numbersFont);
1869       double factorMin = Math.min(.5, _conf._distNumbers);
1870       double factorMax = Math.min(_conf._distNumbers - 1.5,
1871               _conf._distNumbers);
1872       g2D.drawLine(p.x + vn.x * ((1 + factorMin) * newRadius),
1873               p.y + vn.y * ((1 + factorMin) * newRadius),
1874               p.x + vn.x * ((1 + factorMax) * newRadius),
1875               p.y + vn.y * ((1 + factorMax) * newRadius));
1876       g2D.drawStringCentered(mb.getLabel(),
1877               p.x + vn.x * ((1 + _conf._distNumbers) * newRadius),
1878               p.y + vn.y * ((1 + _conf._distNumbers) * newRadius));
1879
1880     }
1881   }
1882
1883   void drawChemProbAnnotation(VueVARNAGraphics g2D, ChemProbAnnotation cpa,
1884           Point2D.Double anchor, double scaleFactor)
1885   {
1886     g2D.setColor(cpa.getColor());
1887     g2D.setStrokeThickness(RNA.CHEM_PROB_ARROW_THICKNESS * scaleFactor
1888             * cpa.getIntensity());
1889     g2D.setPlainStroke();
1890     Point2D.Double v = cpa.getDirVector();
1891     Point2D.Double vn = cpa.getNormalVector();
1892     Point2D.Double base = new Point2D.Double(
1893             (anchor.x + _RNA.CHEM_PROB_DIST * scaleFactor * v.x),
1894             (anchor.y + _RNA.CHEM_PROB_DIST * scaleFactor * v.y));
1895     Point2D.Double edge = new Point2D.Double(
1896             (base.x + _RNA.CHEM_PROB_BASE_LENGTH * cpa.getIntensity()
1897                     * scaleFactor * v.x),
1898             (base.y + _RNA.CHEM_PROB_BASE_LENGTH * cpa.getIntensity()
1899                     * scaleFactor * v.y));
1900     switch (cpa.getType())
1901     {
1902     case ARROW:
1903     {
1904       Point2D.Double arrowTip1 = new Point2D.Double(
1905               (base.x + cpa.getIntensity() * scaleFactor
1906                       * (_RNA.CHEM_PROB_ARROW_WIDTH * vn.x
1907                               + _RNA.CHEM_PROB_ARROW_HEIGHT * v.x)),
1908               (base.y + cpa.getIntensity() * scaleFactor
1909                       * (_RNA.CHEM_PROB_ARROW_WIDTH * vn.y
1910                               + _RNA.CHEM_PROB_ARROW_HEIGHT * v.y)));
1911       Point2D.Double arrowTip2 = new Point2D.Double(
1912               (base.x + cpa.getIntensity() * scaleFactor
1913                       * (-_RNA.CHEM_PROB_ARROW_WIDTH * vn.x
1914                               + _RNA.CHEM_PROB_ARROW_HEIGHT * v.x)),
1915               (base.y + cpa.getIntensity() * scaleFactor
1916                       * (-_RNA.CHEM_PROB_ARROW_WIDTH * vn.y
1917                               + _RNA.CHEM_PROB_ARROW_HEIGHT * v.y)));
1918       g2D.drawLine(base.x, base.y, edge.x, edge.y);
1919       g2D.drawLine(base.x, base.y, arrowTip1.x, arrowTip1.y);
1920       g2D.drawLine(base.x, base.y, arrowTip2.x, arrowTip2.y);
1921     }
1922       break;
1923     case PIN:
1924     {
1925       Point2D.Double side1 = new Point2D.Double(
1926               (edge.x - cpa.getIntensity() * scaleFactor
1927                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.x)),
1928               (edge.y - cpa.getIntensity() * scaleFactor
1929                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.y)));
1930       Point2D.Double side2 = new Point2D.Double(
1931               (edge.x - cpa.getIntensity() * scaleFactor
1932                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1933               (edge.y - cpa.getIntensity() * scaleFactor
1934                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1935       Point2D.Double side3 = new Point2D.Double(
1936               (edge.x + cpa.getIntensity() * scaleFactor
1937                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.x)),
1938               (edge.y + cpa.getIntensity() * scaleFactor
1939                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.y)));
1940       Point2D.Double side4 = new Point2D.Double(
1941               (edge.x + cpa.getIntensity() * scaleFactor
1942                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1943               (edge.y + cpa.getIntensity() * scaleFactor
1944                       * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1945       GeneralPath p2 = new GeneralPath();
1946       p2.moveTo((float) side1.x, (float) side1.y);
1947       p2.lineTo((float) side2.x, (float) side2.y);
1948       p2.lineTo((float) side3.x, (float) side3.y);
1949       p2.lineTo((float) side4.x, (float) side4.y);
1950       p2.closePath();
1951       g2D.fill(p2);
1952       g2D.drawLine(base.x, base.y, edge.x, edge.y);
1953     }
1954       break;
1955     case TRIANGLE:
1956     {
1957       Point2D.Double arrowTip1 = new Point2D.Double(
1958               (edge.x + cpa.getIntensity() * scaleFactor
1959                       * (_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1960               (edge.y + cpa.getIntensity() * scaleFactor
1961                       * (_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1962       Point2D.Double arrowTip2 = new Point2D.Double(
1963               (edge.x + cpa.getIntensity() * scaleFactor
1964                       * (-_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1965               (edge.y + cpa.getIntensity() * scaleFactor
1966                       * (-_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1967       GeneralPath p2 = new GeneralPath();
1968       p2.moveTo((float) base.x, (float) base.y);
1969       p2.lineTo((float) arrowTip1.x, (float) arrowTip1.y);
1970       p2.lineTo((float) arrowTip2.x, (float) arrowTip2.y);
1971       p2.closePath();
1972       g2D.fill(p2);
1973     }
1974       break;
1975     case DOT:
1976     {
1977       Double radius = scaleFactor * _RNA.CHEM_PROB_DOT_RADIUS
1978               * cpa.getIntensity();
1979       Point2D.Double center = new Point2D.Double((base.x + radius * v.x),
1980               (base.y + radius * v.y));
1981       g2D.fillCircle((center.x - radius), (center.y - radius),
1982               (2 * radius));
1983     }
1984       break;
1985     }
1986   }
1987
1988   Point2D.Double buildCaptionPosition(ModeleBase mb, double scaleFactor,
1989           double heightEstimate)
1990   {
1991     double radius = 2.0;
1992     if (_RNA.isNumberDrawn(mb, getNumPeriod()))
1993     {
1994       radius += _conf._distNumbers;
1995     }
1996     Point2D.Double center = mb.getCenter();
1997     Point2D.Double p = mb.getCoords();
1998     double realDistance = _RNA.BASE_RADIUS * radius + heightEstimate;
1999     return new Point2D.Double(center.getX() + (p.getX() - center.getX())
2000             * ((p.distance(center) + realDistance) / p.distance(center)),
2001             center.getY() + (p.getY() - center.getY())
2002                     * ((p.distance(center) + realDistance)
2003                             / p.distance(center)));
2004   }
2005
2006   private void renderAnnotations(VueVARNAGraphics g2D, double offX,
2007           double offY, double rnaBBoxX, double rnaBBoxY, double scaleFactor)
2008   {
2009     for (TextAnnotation textAnnotation : _RNA.getAnnotations())
2010     {
2011       g2D.setColor(textAnnotation.getColor());
2012       g2D.setFont(textAnnotation.getFont().deriveFont((float) (2.0
2013               * textAnnotation.getFont().getSize() * scaleFactor)));
2014       Point2D.Double position = textAnnotation.getCenterPosition();
2015       if (textAnnotation.getType() == TextAnnotation.AnchorType.BASE)
2016       {
2017         ModeleBase mb = (ModeleBase) textAnnotation.getAncrage();
2018         double fontHeight = Math.ceil(textAnnotation.getFont().getSize());
2019         position = buildCaptionPosition(mb, scaleFactor, fontHeight);
2020       }
2021       position = transformCoord(position, offX, offY, rnaBBoxX, rnaBBoxY,
2022               scaleFactor);
2023       g2D.drawStringCentered(textAnnotation.getTexte(), position.x,
2024               position.y);
2025       if ((_selectedAnnotation == textAnnotation) && (_highlightAnnotation))
2026       {
2027         drawStringOutline(g2D, textAnnotation.getTexte(), position.x,
2028                 position.y, 5);
2029       }
2030     }
2031     for (ChemProbAnnotation cpa : _RNA.getChemProbAnnotations())
2032     {
2033       Point2D.Double anchor = transformCoord(cpa.getAnchorPosition(), offX,
2034               offY, rnaBBoxX, rnaBBoxY, scaleFactor);
2035       drawChemProbAnnotation(g2D, cpa, anchor, scaleFactor);
2036     }
2037
2038   }
2039
2040   public Rectangle2D.Double getExtendedRNABBox()
2041   {
2042     // We get the logical bounding box
2043     Rectangle2D.Double rnabbox = _RNA.getBBox();
2044     rnabbox.y -= _conf._distNumbers * _RNA.BASE_RADIUS;
2045     rnabbox.height += 2.0 * _conf._distNumbers * _RNA.BASE_RADIUS;
2046     rnabbox.x -= _conf._distNumbers * _RNA.BASE_RADIUS;
2047     rnabbox.width += 2.0 * _conf._distNumbers * _RNA.BASE_RADIUS;
2048     if (_RNA.hasVirtualLoops())
2049     {
2050       rnabbox.y -= RNA.VIRTUAL_LOOP_RADIUS;
2051       rnabbox.height += 2.0 * RNA.VIRTUAL_LOOP_RADIUS;
2052       rnabbox.x -= RNA.VIRTUAL_LOOP_RADIUS;
2053       rnabbox.width += 2.0 * RNA.VIRTUAL_LOOP_RADIUS;
2054     }
2055     return rnabbox;
2056   }
2057
2058   public void drawBackbone(VueVARNAGraphics g2D, Point2D.Double[] newCoords,
2059           double newRadius, double _scaleFactor)
2060   {
2061     // Drawing backbone
2062     if (getDrawBackbone())
2063     {
2064       g2D.setStrokeThickness(1.5 * _scaleFactor);
2065       g2D.setColor(_conf._backboneColor);
2066
2067       ModeleBackbone bck = _RNA.getBackbone();
2068
2069       for (int i = 1; i < _RNA.get_listeBases().size(); i++)
2070       {
2071         Point2D.Double p1 = newCoords[i - 1];
2072         Point2D.Double p2 = newCoords[i];
2073         double dist = p1.distance(p2);
2074         int a = _RNA.getBaseAt(i - 1).getElementStructure();
2075         int b = _RNA.getBaseAt(i).getElementStructure();
2076         boolean consecutivePair = (a == i) && (b == i - 1);
2077
2078         if ((dist > 0))
2079         {
2080           Point2D.Double vbp = new Point2D.Double();
2081           vbp.x = (p2.x - p1.x) / dist;
2082           vbp.y = (p2.y - p1.y) / dist;
2083
2084           BackboneType bt = bck.getTypeBefore(i);
2085           if (bt != BackboneType.DISCONTINUOUS_TYPE)
2086           {
2087             if (bt == BackboneType.MISSING_PART_TYPE)
2088             {
2089               g2D.setSelectionStroke();
2090             }
2091             else
2092             {
2093               g2D.setPlainStroke();
2094             }
2095             g2D.setColor(bck.getColorBefore(i, _conf._backboneColor));
2096
2097             if (consecutivePair
2098                     && (_RNA.getDrawMode() != RNA.DRAW_MODE_LINEAR)
2099                     && (_RNA.getDrawMode() != RNA.DRAW_MODE_CIRCULAR))
2100             {
2101               int dir = 0;
2102               if (i + 1 < newCoords.length)
2103               {
2104                 dir = (_RNA.testDirectionality(i - 1, i, i + 1) ? -1 : 1);
2105               }
2106               else if (i - 2 >= 0)
2107               {
2108                 dir = (_RNA.testDirectionality(i - 2, i - 1, i) ? -1 : 1);
2109               }
2110               Point2D.Double vn = new Point2D.Double(dir * vbp.y,
2111                       -dir * vbp.x);
2112               Point2D.Double centerSeg = new Point2D.Double(
2113                       (p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0);
2114               double distp1CenterSeq = p1.distance(centerSeg);
2115               double centerDist = Math
2116                       .sqrt((RNA.VIRTUAL_LOOP_RADIUS * _scaleFactor
2117                               * RNA.VIRTUAL_LOOP_RADIUS * _scaleFactor)
2118                               - distp1CenterSeq * distp1CenterSeq);
2119               Point2D.Double centerLoop = new Point2D.Double(
2120                       centerSeg.x + centerDist * vn.x,
2121                       centerSeg.y + centerDist * vn.y);
2122               double radius = centerLoop.distance(p1);
2123               double a1 = 360. * (Math.atan2(-(p1.y - centerLoop.y),
2124                       (p1.x - centerLoop.x))) / (2. * Math.PI);
2125               double a2 = 360. * (Math.atan2(-(p2.y - centerLoop.y),
2126                       (p2.x - centerLoop.x))) / (2. * Math.PI);
2127               double angle = (a2 - a1);
2128               if (-dir * angle < 0)
2129               {
2130                 angle += -dir * 360.;
2131               }
2132               // if (angle<0.) angle += 360.;
2133               // angle = -dir*(360-dir*angle);
2134               g2D.drawArc(centerLoop.x + .8 * newRadius * vn.x,
2135                       centerLoop.y + .8 * newRadius * vn.y, 2 * radius,
2136                       2 * radius, a1, angle);
2137             }
2138             else
2139             {
2140               g2D.drawLine((newCoords[i - 1].x + newRadius * vbp.x),
2141                       (newCoords[i - 1].y + newRadius * vbp.y),
2142                       (newCoords[i].x - newRadius * vbp.x),
2143                       (newCoords[i].y - newRadius * vbp.y));
2144             }
2145           }
2146         }
2147       }
2148     }
2149   }
2150
2151   public Point2D.Double logicToPanel(Point2D.Double logicPoint)
2152   {
2153     return new Point2D.Double(
2154             _offX + (getScaleFactor() * (logicPoint.x - _offsetRNA.x)),
2155             _offY + (getScaleFactor() * (logicPoint.y - _offsetRNA.y)));
2156
2157   }
2158
2159   public Rectangle2D.Double renderRNA(VueVARNAGraphics g2D,
2160           Rectangle2D.Double bbox)
2161   {
2162     return renderRNA(g2D, bbox, false, true);
2163   }
2164
2165   private double computeScaleFactor(Rectangle2D.Double bbox,
2166           boolean localView, boolean autoCenter)
2167   {
2168     Rectangle2D.Double rnabbox = getExtendedRNABBox();
2169     double scaleFactor = Math.min(
2170             bbox.width / rnabbox.width,
2171             bbox.height / rnabbox.height);
2172
2173     // Use it to get an estimate of the font size for numbers ...
2174     float newFontSize = Math.max(1,
2175             (int) ((1.7 * _RNA.BASE_RADIUS) * scaleFactor));
2176     // ... and increase bounding box accordingly
2177     rnabbox.y -= newFontSize;
2178     rnabbox.height += newFontSize;
2179     if (_conf._drawColorMap)
2180     {
2181       rnabbox.height += getColorMapHeight();
2182     }
2183     rnabbox.x -= newFontSize;
2184     rnabbox.width += newFontSize;
2185
2186     // Now, compute the final scaling factor and corresponding font size
2187     scaleFactor = Math.min(bbox.width / rnabbox.width,
2188             bbox.height / rnabbox.height);
2189     if (localView)
2190     {
2191       if (_conf._autoFit)
2192       {
2193         setScaleFactor(scaleFactor);
2194       }
2195       scaleFactor = getScaleFactor();
2196     }
2197     return scaleFactor;
2198   }
2199
2200   public synchronized Rectangle2D.Double renderRNA(VueVARNAGraphics g2D,
2201           Rectangle2D.Double bbox, boolean localView, boolean autoCenter)
2202   {
2203     Rectangle2D.Double rnaMultiBox = new Rectangle2D.Double(0, 0, 1, 1);
2204     double scaleFactor = computeScaleFactor(bbox, localView, autoCenter);
2205     float newFontSize = Math.max(1,
2206             (int) ((1.7 * _RNA.BASE_RADIUS) * scaleFactor));
2207     double newRadius = Math.max(1.0, (scaleFactor * _RNA.BASE_RADIUS));
2208     setBaseFontSize(newFontSize);
2209     setNumbersFontSize(newFontSize);
2210     double offX = bbox.x;
2211     double offY = bbox.y;
2212     Rectangle2D.Double rnabbox = getExtendedRNABBox();
2213
2214     if (_RNA.getSize() != 0)
2215     {
2216
2217       Point2D.Double offsetRNA = new Point2D.Double(rnabbox.x, rnabbox.y);
2218
2219       if (autoCenter)
2220       {
2221         offX = (bbox.x
2222                 + (bbox.width - Math.round(rnabbox.width * scaleFactor))
2223                         / 2.0);
2224         offY = (bbox.y
2225                 + (bbox.height - Math.round(rnabbox.height * scaleFactor))
2226                         / 2.0);
2227         if (localView)
2228         {
2229           _offX = offX;
2230           _offY = offY;
2231           _offsetPanel = new Point2D.Double(_offX, _offY);
2232           _offsetRNA = new Point2D.Double(rnabbox.x, rnabbox.y);
2233         }
2234       }
2235
2236       if (localView)
2237       {
2238         offX = _offX;
2239         offY = _offY;
2240         offsetRNA = _offsetRNA;
2241       }
2242
2243       // Re-scaling once and for all
2244       Point2D.Double[] newCoords = new Point2D.Double[_RNA.get_listeBases()
2245               .size()];
2246       Point2D.Double[] newCenters = new Point2D.Double[_RNA.get_listeBases()
2247               .size()];
2248       for (int i = 0; i < _RNA.get_listeBases().size(); i++)
2249       {
2250         ModeleBase mb = _RNA.getBaseAt(i);
2251         newCoords[i] = new Point2D.Double(
2252                 offX + (scaleFactor * (mb.getCoords().x - offsetRNA.x)),
2253                 offY + (scaleFactor * (mb.getCoords().y - offsetRNA.y)));
2254
2255         Point2D.Double centerBck = _RNA.getCenter(i);
2256         // si la base est dans un angle entre une boucle et une helice
2257         if (_RNA.get_drawMode() == RNA.DRAW_MODE_NAVIEW
2258                 || _RNA.get_drawMode() == RNA.DRAW_MODE_RADIATE)
2259         {
2260           if ((mb.getElementStructure() != -1)
2261                   && i < _RNA.get_listeBases().size() - 1 && i > 1)
2262           {
2263             ModeleBase b1 = _RNA.get_listeBases().get(i - 1);
2264             ModeleBase b2 = _RNA.get_listeBases().get(i + 1);
2265             int j1 = b1.getElementStructure();
2266             int j2 = b2.getElementStructure();
2267             if ((j1 == -1) ^ (j2 == -1))
2268             {
2269               // alors la position du nombre associé doit etre
2270               Point2D.Double a1 = b1.getCoords();
2271               Point2D.Double a2 = b2.getCoords();
2272               Point2D.Double c1 = b1.getCenter();
2273               Point2D.Double c2 = b2.getCenter();
2274
2275               centerBck.x = mb.getCoords().x
2276                       + (c1.x - a1.x) / c1.distance(a1)
2277                       + (c2.x - a2.x) / c2.distance(a2);
2278               centerBck.y = mb.getCoords().y
2279                       + (c1.y - a1.y) / c1.distance(a1)
2280                       + (c2.y - a2.y) / c2.distance(a2);
2281             }
2282           }
2283         }
2284         newCenters[i] = new Point2D.Double(
2285                 offX + (scaleFactor * (centerBck.x - offsetRNA.x)),
2286                 offY + (scaleFactor * (centerBck.y - offsetRNA.y)));
2287       }
2288       // Keep track of coordinates for mouse interactions
2289       if (localView)
2290       {
2291         _realCoords = newCoords;
2292         _realCenters = newCenters;
2293       }
2294
2295       g2D.setStrokeThickness(1.5 * scaleFactor);
2296       g2D.setPlainStroke();
2297       g2D.setFont(_conf._fontBasesGeneral);
2298
2299       // Drawing region highlights Annotation
2300       drawRegionHighlightsAnnotation(g2D, _realCoords, _realCenters,
2301               scaleFactor);
2302       drawBackbone(g2D, newCoords, newRadius, scaleFactor);
2303
2304       // Drawing base-pairs
2305       // pour chaque base
2306       for (int i = 0; i < _RNA.get_listeBases().size(); i++)
2307       {
2308         int j = _RNA.get_listeBases().get(i).getElementStructure();
2309         // si c'est une parenthese ouvrante (premiere base du
2310         // couple)
2311         if (j > i)
2312         {
2313           ModeleBP msbp = _RNA.get_listeBases().get(i).getStyleBP();
2314           // System.err.println(msbp);
2315           if (msbp.isCanonical() || _conf._drawnNonCanonicalBP)
2316           {
2317             if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR)
2318             {
2319               g2D.setStrokeThickness(_RNA.getBasePairThickness(msbp, _conf)
2320                       * 2.0 * scaleFactor * _conf._bpThickness);
2321             }
2322             else
2323             {
2324               g2D.setStrokeThickness(_RNA.getBasePairThickness(msbp, _conf)
2325                       * 1.5 * scaleFactor);
2326             }
2327             g2D.setColor(_RNA.getBasePairColor(msbp, _conf));
2328
2329             if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR)
2330             {
2331               drawBasePairArc(g2D, i, j, newCoords[i], newCoords[j],
2332                       scaleFactor, msbp, newRadius);
2333             }
2334             else
2335             {
2336               drawBasePair(g2D, newCoords[i], newCoords[j], msbp, newRadius,
2337                       scaleFactor);
2338             }
2339           }
2340         }
2341       }
2342
2343       // Liaisons additionelles (non planaires)
2344       if (_conf._drawnNonPlanarBP)
2345       {
2346         ArrayList<ModeleBP> bpaux = _RNA.getStructureAux();
2347         for (int k = 0; k < bpaux.size(); k++)
2348         {
2349           ModeleBP msbp = bpaux.get(k);
2350           if (msbp.isCanonical() || _conf._drawnNonCanonicalBP)
2351           {
2352             int i = msbp.getPartner5().getIndex();
2353             int j = msbp.getPartner3().getIndex();
2354             if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR)
2355             {
2356               g2D.setStrokeThickness(_RNA.getBasePairThickness(msbp, _conf)
2357                       * 2.5 * scaleFactor * _conf._bpThickness);
2358               g2D.setPlainStroke();
2359             }
2360             else
2361             {
2362               g2D.setStrokeThickness(_RNA.getBasePairThickness(msbp, _conf)
2363                       * 1.5 * scaleFactor);
2364               g2D.setPlainStroke();
2365             }
2366
2367             g2D.setColor(_RNA.getBasePairColor(msbp, _conf));
2368             if (j > i)
2369             {
2370               if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR)
2371               {
2372                 drawBasePairArc(g2D, i, j, newCoords[i], newCoords[j],
2373                         scaleFactor, msbp, newRadius);
2374               }
2375               else
2376               {
2377                 drawBasePair(g2D, newCoords[i], newCoords[j], msbp,
2378                         newRadius, scaleFactor);
2379               }
2380             }
2381           }
2382         }
2383       }
2384
2385       // Drawing bases
2386       g2D.setPlainStroke();
2387       for (int i = 0; i < Math.min(_RNA.get_listeBases().size(),
2388               newCoords.length); i++)
2389       {
2390         drawBase(g2D, i, newCoords, newCenters, newRadius, scaleFactor,
2391                 localView);
2392       }
2393
2394       rnaMultiBox = new Rectangle2D.Double(offX, offY,
2395               (scaleFactor * rnabbox.width) - 1,
2396               (scaleFactor * rnabbox.height) - 1);
2397
2398       if (localView)
2399       {
2400         // Drawing bbox
2401         if (_debug || _drawBBox)
2402         {
2403           g2D.setColor(Color.RED);
2404           g2D.setSelectionStroke();
2405           g2D.drawRect(rnaMultiBox.x, rnaMultiBox.y, rnaMultiBox.width,
2406                   rnaMultiBox.height);
2407         }
2408
2409         // Draw color map
2410         if (_conf._drawColorMap)
2411         {
2412           drawColorMap(g2D, scaleFactor, rnabbox);
2413         }
2414
2415         if (_debug || _drawBBox)
2416         {
2417           g2D.setColor(Color.GRAY);
2418           g2D.setSelectionStroke();
2419           g2D.drawRect(0, 0, getWidth() - 1,
2420                   getHeight() - getTitleHeight() - 1);
2421         }
2422       }
2423       // Draw annotations
2424       renderAnnotations(g2D, offX, offY, offsetRNA.x, offsetRNA.y,
2425               scaleFactor);
2426       // Draw additional debug shape
2427       if (_RNA._debugShape != null)
2428       {
2429         Color c = new Color(255, 0, 0, 50);
2430         g2D.setColor(c);
2431         AffineTransform at = new AffineTransform();
2432         at.translate(offX - scaleFactor * rnabbox.x,
2433                 offY - scaleFactor * rnabbox.y);
2434         at.scale(scaleFactor, scaleFactor);
2435         Shape s = at.createTransformedShape(_RNA._debugShape);
2436         if (s instanceof GeneralPath)
2437         {
2438           g2D.fill((GeneralPath) s);
2439         }
2440       }
2441     }
2442     else
2443     {
2444       g2D.setColor(VARNAConfig.DEFAULT_MESSAGE_COLOR);
2445       g2D.setFont(VARNAConfig.DEFAULT_MESSAGE_FONT);
2446       rnaMultiBox = new Rectangle2D.Double(0, 0, 10, 10);
2447       g2D.drawStringCentered("No RNA here", bbox.getCenterX(),
2448               bbox.getCenterY());
2449     }
2450     return rnaMultiBox;
2451   }
2452
2453   public void centerViewOn(double x, double y)
2454   {
2455     Rectangle2D.Double r = _RNA.getBBox();
2456     _target = new Point2D.Double(x, y);
2457     Point2D.Double q = logicToPanel(_target);
2458     Point p = new Point((int) (-q.x), (int) (-q.y));
2459     setTranslation(p);
2460     repaint();
2461   }
2462
2463   Point2D.Double _target = new Point2D.Double(0, 0);
2464
2465   Point2D.Double _target2 = new Point2D.Double(0, 0);
2466
2467   public ModeleBase getBaseAt(Point2D.Double po)
2468   {
2469     ModeleBase mb = null;
2470     Point2D.Double p = panelToLogicPoint(po);
2471     double dist = Double.MAX_VALUE;
2472     for (ModeleBase tmp : _RNA.get_listeBases())
2473     {
2474       double ndist = tmp.getCoords().distance(p);
2475       if (dist > ndist)
2476       {
2477         mb = tmp;
2478         dist = ndist;
2479       }
2480     }
2481     return mb;
2482   }
2483
2484   public void setColorMapValues(Double[] values)
2485   {
2486     _RNA.setColorMapValues(values, _conf._cm, true);
2487     _conf._drawColorMap = true;
2488     repaint();
2489   }
2490
2491   public void setColorMapMaxValue(double d)
2492   {
2493     _conf._cm.setMaxValue(d);
2494   }
2495
2496   public void setColorMapMinValue(double d)
2497   {
2498     _conf._cm.setMinValue(d);
2499   }
2500
2501   public ModeleColorMap getColorMap()
2502   {
2503     return _conf._cm;
2504   }
2505
2506   public void setColorMap(ModeleColorMap cm)
2507   {
2508     // _RNA.adaptColorMapToValues(cm);
2509     _conf._cm = cm;
2510     repaint();
2511   }
2512
2513   public void setColorMapCaption(String caption)
2514   {
2515     _conf._colorMapCaption = caption;
2516     repaint();
2517   }
2518
2519   public String getColorMapCaption()
2520   {
2521     return _conf._colorMapCaption;
2522   }
2523
2524   public void drawColorMap(boolean draw)
2525   {
2526     _conf._drawColorMap = draw;
2527   }
2528
2529   private double getColorMapHeight()
2530   {
2531     double result = VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE
2532             + _conf._colorMapHeight;
2533     if (!_conf._colorMapCaption.equals(""))
2534     {
2535       result += VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE;
2536     }
2537     return result;
2538   }
2539
2540   private void drawColorMap(VueVARNAGraphics g2D, double scaleFactor,
2541           Rectangle2D.Double rnabbox)
2542   {
2543     double v1 = _conf._cm.getMinValue();
2544     double v2 = _conf._cm.getMaxValue();
2545     double x, y;
2546     g2D.setPlainStroke();
2547
2548     double xSpaceAvail = 0;
2549     double ySpaceAvail = Math.min(
2550             (getHeight() - rnabbox.height * scaleFactor - getTitleHeight())
2551                     / 2.0,
2552             scaleFactor * (_conf._colorMapHeight
2553                     + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE));
2554     if ((int) ySpaceAvail == 0)
2555     {
2556       xSpaceAvail = Math.min((getWidth() - rnabbox.width * scaleFactor) / 2,
2557               scaleFactor * (_conf._colorMapWidth)
2558                       + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH);
2559     }
2560     double xBase = (xSpaceAvail + _offX + scaleFactor * (rnabbox.width
2561             - _conf._colorMapWidth - _conf._colorMapXOffset));
2562     double hcaption = VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE;
2563     double yBase = (ySpaceAvail + _offY + scaleFactor * (rnabbox.height
2564             - _conf._colorMapHeight - _conf._colorMapYOffset - hcaption));
2565
2566     for (int i = 0; i < _conf._colorMapWidth; i++)
2567     {
2568       double ratio = ((i) / (_conf._colorMapWidth));
2569       double val = v1 + (v2 - v1) * ratio;
2570       g2D.setColor(_conf._cm.getColorForValue(val));
2571       x = (xBase + scaleFactor * i);
2572       y = yBase;
2573       g2D.fillRect(x, y,
2574               scaleFactor * VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH,
2575               (scaleFactor * _conf._colorMapHeight));
2576     }
2577     g2D.setColor(VARNAConfig.DEFAULT_COLOR_MAP_OUTLINE);
2578     g2D.drawRect(xBase, yBase,
2579             (VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH - 1
2580                     + scaleFactor * _conf._colorMapWidth),
2581             ((scaleFactor * _conf._colorMapHeight)));
2582     g2D.setFont(getFont().deriveFont((float) (scaleFactor
2583             * VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE)));
2584     g2D.setColor(VARNAConfig.DEFAULT_COLOR_MAP_FONT_COLOR);
2585     NumberFormat nf = NumberFormat.getInstance();
2586     nf.setMaximumFractionDigits(2);
2587     nf.setMinimumFractionDigits(0);
2588     g2D.drawStringCentered(nf.format(_conf._cm.getMinValue()), xBase,
2589             yBase + scaleFactor * (_conf._colorMapHeight
2590                     + (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7)));
2591     g2D.drawStringCentered(nf.format(_conf._cm.getMaxValue()),
2592             xBase + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH
2593                     + scaleFactor * _conf._colorMapWidth,
2594             yBase + scaleFactor * (_conf._colorMapHeight
2595                     + (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7)));
2596     if (!_conf._colorMapCaption.equals(""))
2597     {
2598       g2D.drawStringCentered("" + _conf._colorMapCaption,
2599               xBase + scaleFactor * _conf._colorMapWidth / 2.0,
2600               yBase + scaleFactor
2601                       * (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7
2602                               + _conf._colorMapHeight));
2603     }
2604
2605   }
2606
2607   public Point2D.Double panelToLogicPoint(Point2D.Double p)
2608   {
2609     return new Point2D.Double(
2610             ((p.x - getOffsetPanel().x) / getScaleFactor())
2611                     + getRNAOffset().x,
2612             ((p.y - getOffsetPanel().y) / getScaleFactor())
2613                     + getRNAOffset().y);
2614   }
2615
2616   public Point2D.Double transformCoord(Point2D.Double coordDebut,
2617           double offX, double offY, double rnaBBoxX, double rnaBBoxY,
2618           double scaleFactor)
2619   {
2620     return new Point2D.Double(
2621             offX + (scaleFactor * (coordDebut.x - rnaBBoxX)),
2622             offY + (scaleFactor * (coordDebut.y - rnaBBoxY)));
2623   }
2624
2625   public void eraseSequence()
2626   {
2627     _RNA.eraseSequence();
2628   }
2629
2630   public Point2D.Double transformCoord(Point2D.Double coordDebut)
2631   {
2632     Rectangle2D.Double rnabbox = getExtendedRNABBox();
2633     return new Point2D.Double(
2634             _offX + (getScaleFactor() * (coordDebut.x - rnabbox.x)),
2635             _offY + (getScaleFactor() * (coordDebut.y - rnabbox.y)));
2636   }
2637
2638   @Override
2639   public void paintComponent(Graphics g)
2640   {
2641     paintComponent(g, false);
2642   }
2643
2644   public void paintComponent(Graphics g, boolean transparentBackground)
2645   {
2646     if (_premierAffichage)
2647     {
2648       // _border = new Dimension(0, 0);
2649       _translation.x = 0;
2650       _translation.y = (int) (-getTitleHeight() / 2.0);
2651       _premierAffichage = false;
2652     }
2653
2654     Graphics2D g2 = (Graphics2D) g;
2655     Stroke dflt = g2.getStroke();
2656     VueVARNAGraphics g2D = new SwingGraphics(g2);
2657     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
2658             RenderingHints.VALUE_ANTIALIAS_ON);
2659     // BH 2019.05.16 *remove* the popup menu?
2660     // this.removeAll();
2661     super.paintComponent(g2);
2662     renderComponent(g2D, transparentBackground, getScaleFactor());
2663     if (isFocusOwner())
2664     {
2665       g2.setStroke(new BasicStroke(1.5f));
2666       g2.setColor(Color.decode("#C0C0C0"));
2667       g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
2668
2669     }
2670     g2.setStroke(dflt);
2671     /*
2672      * PSExport e = new PSExport(); SecStrProducerGraphics export = new
2673      * SecStrProducerGraphics(e); renderRNA(export, getExtendedRNABBox());
2674      * try { export.saveToDisk("./out.ps"); } catch
2675      * (ExceptionWritingForbidden e1) { e1.printStackTrace(); }
2676      */
2677   }
2678
2679   /**
2680    * Draws current RNA structure in a given Graphics "device".
2681    * 
2682    * @param g2D
2683    *          A graphical device
2684    * @param transparentBackground
2685    *          Whether the background should be transparent, or drawn.
2686    */
2687   public synchronized void renderComponent(VueVARNAGraphics g2D,
2688           boolean transparentBackground, double scaleFactor)
2689   {
2690
2691     updateTitleHeight();
2692
2693     if (true || !transparentBackground)
2694     {
2695       g2D.setColor(_conf._backgroundColor);
2696       g2D.fillRect(0, 0, getWidth(), getHeight());
2697     }
2698     else
2699     {
2700       g2D.setColor(new Color(0, 0, 0, 120));
2701       // BH SwingJS not allowing this TODO -- fix alpha for background color
2702       // super.setBackground(new Color(0, 0, 0, 120));
2703     }
2704
2705     if (_debug || _drawBorder)
2706     {
2707       g2D.setColor(Color.BLACK);
2708       g2D.setPlainStroke();
2709       g2D.drawRect(getLeftOffset(), getTopOffset(), getInnerWidth(),
2710               getInnerHeight());
2711
2712     }
2713
2714     // if (!transparentBackground) {
2715     // super.setBackground(_conf._backgroundColor);
2716     // } else {
2717     // super.setBackground(new Color(0, 0, 0, 120));
2718     // }
2719
2720     if (getMinimumSize().height < getSize().height
2721             && getMinimumSize().width < getSize().width)
2722     {
2723       // Draw Title
2724       if (!getTitle().equals(""))
2725       {
2726         g2D.setColor(_conf._titleColor);
2727         g2D.setFont(_conf._titleFont);
2728         g2D.drawStringCentered(getTitle(), this.getWidth() / 2,
2729                 this.getHeight() - getTitleHeight() / 2.0);
2730       }
2731       // Draw RNA
2732       renderRNA(g2D, getClip(), true, _conf._autoCenter);
2733     }
2734     if (_selectionRectangle != null)
2735     {
2736       g2D.setColor(Color.BLACK);
2737       g2D.setSelectionStroke();
2738       g2D.drawRect(_selectionRectangle.x, _selectionRectangle.y,
2739               _selectionRectangle.width, _selectionRectangle.height);
2740     }
2741     if ((_linkOrigin != null) && (_linkDestination != null))
2742     {
2743       g2D.setColor(_conf._bondColor);
2744       g2D.setPlainStroke();
2745       g2D.setStrokeThickness(3.0 * scaleFactor);
2746       Point2D.Double linkOrigin = (_linkOrigin);
2747       Point2D.Double linkDestination = (_linkDestination);
2748       g2D.drawLine(linkOrigin.x, linkOrigin.y, linkDestination.x,
2749               linkDestination.y);
2750       for (int i : getSelection().getIndices())
2751       {
2752         drawBase(g2D, i, _realCoords, _realCenters,
2753                 scaleFactor * _RNA.BASE_RADIUS, scaleFactor, true);
2754       }
2755     }
2756
2757     if (_debug)
2758     {
2759       g2D.setStrokeThickness(3.0 * scaleFactor);
2760       g2D.setColor(Color.black);
2761       Point2D.Double t = this.logicToPanel(_target);
2762       g2D.drawLine(t.x - 3, t.y - 3, t.x + 3, t.y + 3);
2763       g2D.drawLine(t.x - 3, t.y + 3, t.x + 3, t.y - 3);
2764       g2D.setColor(Color.red);
2765       t = this.logicToPanel(_target2);
2766       g2D.drawLine(t.x - 3, t.y - 3, t.x + 3, t.y + 3);
2767       g2D.drawLine(t.x - 3, t.y + 3, t.x + 3, t.y - 3);
2768     }
2769   }
2770
2771   public void drawRegionHighlightsAnnotation(VueVARNAGraphics g2D,
2772           Point2D.Double[] realCoords, Point2D.Double[] realCenters,
2773           double scaleFactor)
2774   {
2775     g2D.setStrokeThickness(2.0 * scaleFactor);
2776     g2D.setPlainStroke();
2777     for (HighlightRegionAnnotation r : _RNA.getHighlightRegion())
2778     {
2779       GeneralPath s = r.getShape(realCoords, realCenters, scaleFactor);
2780       g2D.setColor(r.getFillColor());
2781       g2D.fill(s);
2782       g2D.setColor(r.getOutlineColor());
2783       g2D.draw(s);
2784     }
2785   }
2786
2787   private Rectangle2D.Double getClip()
2788   {
2789     return new Rectangle2D.Double(getLeftOffset(), getTopOffset(),
2790             this.getInnerWidth(), this.getInnerHeight());
2791   }
2792
2793   public Rectangle2D.Double getViewClip()
2794   {
2795     return new Rectangle2D.Double(this.getLeftOffset(), this.getTopOffset(),
2796             this.getInnerWidth(), this.getInnerHeight());
2797   }
2798
2799   /**
2800    * Returns the color used to draw backbone bounds.
2801    * 
2802    * @return The color used to draw backbone bounds
2803    */
2804   public Color getBackboneColor()
2805   {
2806     return _conf._backboneColor;
2807   }
2808
2809   /**
2810    * Sets the color to be used for drawing backbone interactions.
2811    * 
2812    * @param backbone_color
2813    *          The new color for the backbone bounds
2814    */
2815   public void setBackboneColor(Color backbone_color)
2816   {
2817     _conf._backboneColor = backbone_color;
2818   }
2819
2820   /**
2821    * Returns the color used to display hydrogen bonds (base pairings)
2822    * 
2823    * @return The color of hydrogen bonds
2824    */
2825   public Color getBondColor()
2826   {
2827     return _conf._bondColor;
2828   }
2829
2830   /**
2831    * Returns the title of this panel
2832    * 
2833    * @return The title
2834    */
2835   public String getTitle()
2836   {
2837     return _RNA.getName();
2838   }
2839
2840   /**
2841    * Sets the new color to be used for hydrogen bonds (base pairings)
2842    * 
2843    * @param bond_color
2844    *          The new color for hydrogen bonds
2845    */
2846   public void setDefaultBPColor(Color bond_color)
2847   {
2848     _conf._bondColor = bond_color;
2849   }
2850
2851   /**
2852    * Sets the size of the border, i.e. the empty space between the end of the
2853    * drawing area and the actual border.
2854    * 
2855    * @param b
2856    *          The new border size
2857    */
2858   public void setBorderSize(Dimension b)
2859   {
2860     _border = b;
2861   }
2862
2863   /**
2864    * Returns the size of the border, i.e. the empty space between the end of the
2865    * drawing area
2866    * 
2867    * @return The border size
2868    */
2869   public Dimension getBorderSize()
2870   {
2871     return _border;
2872   }
2873
2874   /**
2875    * Sets the RNA to be displayed within this Panel. This method does not use a
2876    * drawing algorithm to reassigns base coordinates, rather assuming that the
2877    * RNA was previously drawn.
2878    * 
2879    * @param r
2880    *          An already drawn RNA to display in this panel
2881    */
2882   public synchronized void showRNA(RNA r)
2883   {
2884     fireUINewStructure(r);
2885     _RNA = r;
2886   }
2887
2888   /**
2889    * Sets the RNA secondary structure to be drawn in this panel, using the
2890    * default layout algorithm. In addition to the raw nucleotides sequence, the
2891    * secondary structure is given in the so-called "Dot-bracket notation" (DBN)
2892    * format. This format is a well-parenthesized word over the alphabet
2893    * '(',')','.'.<br/>
2894    * Ex:<code>((((((((....))))..(((((...))).))))))</code><br />
2895    * Returns <code>true</code> if the sequence/structure couple could be parsed
2896    * into a valid secondary structure, and <code>false</code> otherwise.
2897    * 
2898    * @param seq
2899    *          The raw nucleotides sequence
2900    * @param str
2901    *          The secondary structure
2902    * @throws ExceptionNonEqualLength
2903    */
2904   public void drawRNA(String seq, String str) throws ExceptionNonEqualLength
2905   {
2906     drawRNA(seq, str, _RNA.get_drawMode());
2907   }
2908
2909   /**
2910    * Sets the RNA secondary structure to be drawn in this panel, using a given
2911    * layout algorithm.
2912    * 
2913    * @param r
2914    *          The new secondary structure
2915    * @param drawMode
2916    *          The drawing algorithm
2917    */
2918   public void drawRNA(RNA r, int drawMode)
2919   {
2920     r.setDrawMode(drawMode);
2921     drawRNA(r);
2922   }
2923
2924   /**
2925    * Redraws the current RNA. This reassigns base coordinates to their default
2926    * value using the current drawing algorithm.
2927    */
2928
2929   public void drawRNA()
2930   {
2931     try
2932     {
2933       _RNA.drawRNA(_RNA.get_drawMode(), _conf);
2934     } catch (ExceptionNAViewAlgorithm e)
2935     {
2936       errorDialog(e);
2937       e.printStackTrace();
2938     }
2939     repaint();
2940   }
2941
2942   /**
2943    * Sets the RNA secondary structure to be drawn in this panel, using the
2944    * current drawing algorithm.
2945    * 
2946    * @param r
2947    *          The new secondary structure
2948    */
2949   public void drawRNA(RNA r)
2950   {
2951     if (r != null)
2952     {
2953       _RNA = r;
2954       drawRNA();
2955     }
2956   }
2957
2958   /**
2959    * Sets the RNA secondary structure to be drawn in this panel, using a given
2960    * layout algorithm. In addition to the raw nucleotides sequence, the
2961    * secondary structure is given in the so-called "Dot-bracket notation" (DBN)
2962    * format. This format is a well-parenthesized word over the alphabet
2963    * '(',')','.'.<br/>
2964    * Ex: <code>((((((((....))))..(((((...))).))))))</code><br />
2965    * Returns <code>true</code> if the sequence/structure couple could be parsed
2966    * into a valid secondary structure, and <code>false</code> otherwise.
2967    * 
2968    * @param seq
2969    *          The raw nucleotides sequence
2970    * @param str
2971    *          The secondary structure
2972    * @param drawMode
2973    *          The drawing algorithm
2974    * @throws ExceptionNonEqualLength
2975    */
2976   public void drawRNA(String seq, String str, int drawMode)
2977           throws ExceptionNonEqualLength
2978   {
2979     _RNA.setDrawMode(drawMode);
2980     try
2981     {
2982       _RNA.setRNA(seq, str);
2983       drawRNA();
2984     } catch (ExceptionUnmatchedClosingParentheses e)
2985     {
2986       errorDialog(e);
2987     } catch (ExceptionFileFormatOrSyntax e1)
2988     {
2989       errorDialog(e1);
2990     }
2991   }
2992
2993   public void drawRNA(Reader r, int drawMode)
2994           throws ExceptionNonEqualLength, ExceptionFileFormatOrSyntax
2995   {
2996     _RNA.setDrawMode(drawMode);
2997     Collection<RNA> rnas = RNAFactory.loadSecStr(r);
2998     if (rnas.isEmpty())
2999     {
3000       throw new ExceptionFileFormatOrSyntax(
3001               "No RNA could be parsed from that source.");
3002     }
3003     _RNA = rnas.iterator().next();
3004     drawRNA();
3005   }
3006
3007   /**
3008    * Draws a secondary structure of RNA using the default drawing algorithm and
3009    * displays it, using an interpolated transition between the previous one and
3010    * the new one. Extra bases, resulting from a size difference between the two
3011    * successive RNAs, are assumed to initiate from the middle of the sequence.
3012    * In other words, both prefixes and suffixes of the RNAs are assumed to
3013    * match, and what remains is an insertion.
3014    * 
3015    * @param seq
3016    *          Sequence
3017    * @param str
3018    *          Structure in dot bracket notation
3019    * @throws ExceptionNonEqualLength
3020    *           If len(seq)!=len(str)
3021    */
3022   public void drawRNAInterpolated(String seq, String str)
3023           throws ExceptionNonEqualLength
3024   {
3025     drawRNAInterpolated(seq, str, _RNA.get_drawMode());
3026   }
3027
3028   /**
3029    * Draws a secondary structure of RNA using a given algorithm and displays it,
3030    * using an interpolated transition between the previous one and the new one.
3031    * Extra bases, resulting from a size difference between the two successive
3032    * RNAs, are assumed to initiate from the middle of the sequence. In other
3033    * words, both prefixes and suffixes of the RNAs are assumed to match, and
3034    * what remains is an insertion.
3035    * 
3036    * @param seq
3037    *          Sequence
3038    * @param str
3039    *          Structure in dot bracket notation
3040    * @param drawMode
3041    *          The drawing algorithm to be used for the initial placement
3042    * @throws ExceptionNonEqualLength
3043    *           If len(seq)!=len(str)
3044    */
3045   public void drawRNAInterpolated(String seq, String str, int drawMode)
3046   {
3047     drawRNAInterpolated(seq, str, drawMode, Mapping.DefaultOutermostMapping(
3048             _RNA.get_listeBases().size(), str.length()));
3049   }
3050
3051   /**
3052    * Draws a secondary structure of RNA using the default drawing algorithm and
3053    * displays it, using an interpolated transition between the previous one and
3054    * the new one. Here, a mapping between those bases of the new structure and
3055    * the previous one is explicitly provided.
3056    * 
3057    * @param seq
3058    *          Sequence
3059    * @param str
3060    *          Structure in dot bracket notation
3061    * @param m
3062    *          A mapping between the currently rendered structure and its
3063    *          successor (seq,str)
3064    * @throws ExceptionNonEqualLength
3065    *           If len(seq)!=len(str)
3066    */
3067   public void drawRNAInterpolated(String seq, String str, Mapping m)
3068   {
3069     drawRNAInterpolated(seq, str, _RNA.get_drawMode(), m);
3070   }
3071
3072   /**
3073    * Draws a secondary structure of RNA using a given drawing algorithm and
3074    * displays it, using an interpolated transition between the previous one and
3075    * the new one. Here, a mapping between those bases of the new structure and
3076    * the previous one is provided.
3077    * 
3078    * @param seq
3079    *          Sequence
3080    * @param str
3081    *          Structure in dot bracket notation
3082    * @param drawMode
3083    *          The drawing algorithm to be used for the initial placement
3084    * @param m
3085    *          A mapping between the currently rendered structure and its
3086    *          successor (seq,str)
3087    */
3088   public void drawRNAInterpolated(String seq, String str, int drawMode,
3089           Mapping m)
3090   {
3091     RNA target = new RNA();
3092     try
3093     {
3094       target.setRNA(seq, str);
3095       drawRNAInterpolated(target, drawMode, m);
3096     } catch (ExceptionUnmatchedClosingParentheses e)
3097     {
3098       errorDialog(e);
3099     } catch (ExceptionFileFormatOrSyntax e)
3100     {
3101       errorDialog(e);
3102     }
3103   }
3104
3105   /**
3106    * Draws a secondary structure of RNA using the default drawing algorithm and
3107    * displays it, using an interpolated transition between the previous one and
3108    * the new one. Here, a mapping between those bases of the new structure and
3109    * the previous one is explicitly provided.
3110    * 
3111    * @param target
3112    *          Secondary structure
3113    */
3114   public void drawRNAInterpolated(RNA target)
3115   {
3116     drawRNAInterpolated(target, target.get_drawMode(),
3117             Mapping.DefaultOutermostMapping(_RNA.get_listeBases().size(),
3118                     target.getSize()));
3119   }
3120
3121   /**
3122    * Draws a secondary structure of RNA using the default drawing algorithm and
3123    * displays it, using an interpolated transition between the previous one and
3124    * the new one. Here, a mapping between those bases of the new structure and
3125    * the previous one is explicitly provided.
3126    * 
3127    * @param target
3128    *          Secondary structure
3129    * @param m
3130    *          A mapping between the currently rendered structure and its
3131    *          successor (seq,str)
3132    */
3133   public void drawRNAInterpolated(RNA target, Mapping m)
3134   {
3135     drawRNAInterpolated(target, target.get_drawMode(), m);
3136   }
3137
3138   /**
3139    * Draws a secondary structure of RNA using a given drawing algorithm and
3140    * displays it, using an interpolated transition between the previous one and
3141    * the new one. Here, a mapping between those bases of the new structure and
3142    * the previous one is provided.
3143    * 
3144    * @param target
3145    *          Secondary structure of RNA
3146    * @param drawMode
3147    *          The drawing algorithm to be used for the initial placement
3148    * @param m
3149    *          A mapping between the currently rendered structure and its
3150    *          successor (seq,str)
3151    */
3152   public void drawRNAInterpolated(RNA target, int drawMode, Mapping m)
3153   {
3154     try
3155     {
3156       target.drawRNA(drawMode, _conf);
3157       _conf._drawColorMap = false;
3158       _interpolator.addTarget(target, m);
3159     } catch (ExceptionNAViewAlgorithm e)
3160     {
3161       errorDialog(e);
3162       e.printStackTrace();
3163     }
3164   }
3165
3166   /**
3167    * Returns the current algorithm used for drawing the structure
3168    * 
3169    * @return The current drawing algorithm
3170    */
3171   public int getDrawMode()
3172   {
3173     return this._RNA.getDrawMode();
3174   }
3175
3176   public void showRNA(RNA t, VARNAConfig cfg)
3177   {
3178     showRNA(t);
3179     if (cfg != null)
3180     {
3181       this.setConfig(cfg);
3182     }
3183     repaint();
3184   }
3185
3186   /**
3187    * Checks whether an interpolated transition bewteen two RNAs is occurring.
3188    * 
3189    * @return True if an interpolated transition is occurring, false otherwise
3190    */
3191
3192   public boolean isInterpolationInProgress()
3193   {
3194     if (_interpolator == null)
3195     {
3196       return false;
3197     }
3198     else
3199     {
3200       return _interpolator.isInterpolationInProgress();
3201     }
3202   }
3203
3204   /**
3205    * Simply displays (does not redraw) a secondary structure , using an
3206    * interpolated transition between the previous one and the new one. A default
3207    * mapping between those bases of the new structure and the previous one is
3208    * used.
3209    * 
3210    * @param target
3211    *          Secondary structure of RNA
3212    */
3213   public void showRNAInterpolated(RNA target)
3214   {
3215     showRNAInterpolated(target, Mapping.DefaultOutermostMapping(
3216             _RNA.get_listeBases().size(), target.getSize()));
3217   }
3218
3219   /**
3220    * Simply displays (does not redraw) a secondary structure , using an
3221    * interpolated transition between the previous one and the new one. Here, a
3222    * mapping between bases of the new structure and the previous one is given.
3223    * 
3224    * @param target
3225    *          Secondary structure of RNA
3226    * @param m
3227    *          A mapping between the currently rendered structure and its
3228    *          successor (seq,str)
3229    * @throws ExceptionNonEqualLength
3230    *           If len(seq)!=len(str)
3231    */
3232   public void showRNAInterpolated(RNA target, Mapping m)
3233   {
3234     showRNAInterpolated(target, null, m);
3235   }
3236
3237   public void showRNAInterpolated(RNA target, VARNAConfig cfg, Mapping m)
3238   {
3239     _interpolator.addTarget(target, cfg, m);
3240   }
3241
3242   /**
3243    * When comparison mode is ON, sets the two RNA secondary structure to be
3244    * drawn in this panel, using a given layout algorithm. In addition to the raw
3245    * nucleotides sequence, the secondary structure is given in the so-called
3246    * "Dot-bracket notation" (DBN) format. This format is a well-parenthesized
3247    * word over the alphabet '(',')','.'.<br/>
3248    * Ex: <code>((((((((....))))..(((((...))).))))))</code><br />
3249    * 
3250    * @param firstSeq
3251    *          The first RNA raw nucleotides sequence
3252    * @param firstStruct
3253    *          The first RNA secondary structure
3254    * @param secondSeq
3255    *          The second RNA raw nucleotides sequence
3256    * @param secondStruct
3257    *          The second RNA secondary structure
3258    * @param drawMode
3259    *          The drawing algorithm
3260    */
3261   public void drawRNA(String firstSeq, String firstStruct, String secondSeq,
3262           String secondStruct, int drawMode)
3263   {
3264     _RNA.setDrawMode(drawMode);
3265     /**
3266      * Checking the sequences and structures validities...
3267      */
3268
3269     // This is a comparison, so the two RNA alignment past in parameters
3270     // must
3271     // have the same sequence and structure length.
3272     if (firstSeq.length() == secondSeq.length()
3273             && firstStruct.length() == secondStruct.length())
3274     {
3275       // First RNA
3276       if (firstSeq.length() != firstStruct.length())
3277       {
3278         if (_conf._showWarnings)
3279         {
3280           emitWarning("First sequence length " + firstSeq.length()
3281                   + " differs from that of it's secondary structure "
3282                   + firstStruct.length()
3283                   + ". \nAdapting first sequence length ...");
3284         }
3285         if (firstSeq.length() < firstStruct.length())
3286         {
3287           while (firstSeq.length() < firstStruct.length())
3288           {
3289             firstSeq += " ";
3290           }
3291         }
3292         else
3293         {
3294           firstSeq = firstSeq.substring(0, firstStruct.length());
3295         }
3296       }
3297
3298       // Second RNA
3299       if (secondSeq.length() != secondStruct.length())
3300       {
3301         if (_conf._showWarnings)
3302         {
3303           emitWarning("Second sequence length " + secondSeq.length()
3304                   + " differs from that of it's secondary structure "
3305                   + secondStruct.length()
3306                   + ". \nAdapting second sequence length ...");
3307         }
3308         if (secondSeq.length() < secondStruct.length())
3309         {
3310           while (secondSeq.length() < secondStruct.length())
3311           {
3312             secondSeq += " ";
3313           }
3314         }
3315         else
3316         {
3317           secondSeq = secondSeq.substring(0, secondStruct.length());
3318         }
3319       }
3320
3321       int RNALength = firstSeq.length();
3322       String string_superStruct = new String("");
3323       String string_superSeq = new String("");
3324       /**
3325        * In this array, we'll have for each indexes of each characters of the
3326        * final super-structure, the RNA number which is own it.
3327        */
3328       ArrayList<Integer> array_rnaOwn = new ArrayList<>();
3329
3330       /**
3331        * Generating super-structure sequences and structures...
3332        */
3333
3334       firstStruct = firstStruct.replace('-', '.');
3335       secondStruct = secondStruct.replace('-', '.');
3336       // First of all, we make the structure
3337       for (int i = 0; i < RNALength; i++)
3338       {
3339         // If both characters are the same, so it'll be in the super
3340         // structure
3341         if (firstStruct.charAt(i) == secondStruct.charAt(i))
3342         {
3343           string_superStruct = string_superStruct + firstStruct.charAt(i);
3344           array_rnaOwn.add(0);
3345         }
3346         // Else if one of the characters is an opening parenthese, so
3347         // it'll be an opening parenthese in the super structure
3348         else if (firstStruct.charAt(i) == '('
3349                 || secondStruct.charAt(i) == '(')
3350         {
3351           string_superStruct = string_superStruct + '(';
3352           array_rnaOwn.add((firstStruct.charAt(i) == '(') ? 1 : 2);
3353         }
3354         // Else if one of the characters is a closing parenthese, so
3355         // it'll be a closing parenthese in the super structure
3356         else if (firstStruct.charAt(i) == ')'
3357                 || secondStruct.charAt(i) == ')')
3358         {
3359           string_superStruct = string_superStruct + ')';
3360           array_rnaOwn.add((firstStruct.charAt(i) == ')') ? 1 : 2);
3361         }
3362         else
3363         {
3364           string_superStruct = string_superStruct + '.';
3365           array_rnaOwn.add(-1);
3366         }
3367       }
3368
3369       // Next, we make the sequence taking the characters at the same
3370       // index in the first and second sequence
3371       for (int i = 0; i < RNALength; i++)
3372       {
3373         string_superSeq = string_superSeq + firstSeq.charAt(i)
3374                 + secondSeq.charAt(i);
3375       }
3376
3377       // Now, we need to create the super-structure RNA with the owning
3378       // bases array
3379       // in order to color bases outer depending on the owning statement
3380       // of each bases.
3381       if (!string_superSeq.equals("") && !string_superStruct.equals(""))
3382       {
3383         try
3384         {
3385           _RNA.setRNA(string_superSeq, string_superStruct, array_rnaOwn);
3386         } catch (ExceptionUnmatchedClosingParentheses e)
3387         {
3388           errorDialog(e);
3389         } catch (ExceptionFileFormatOrSyntax e)
3390         {
3391           errorDialog(e);
3392         }
3393       }
3394       else
3395       {
3396         emitWarning("ERROR : The super-structure is NULL.");
3397       }
3398
3399       switch (_RNA.get_drawMode())
3400       {
3401       case RNA.DRAW_MODE_RADIATE:
3402         _RNA.drawRNARadiate(_conf);
3403         break;
3404       case RNA.DRAW_MODE_CIRCULAR:
3405         _RNA.drawRNACircle(_conf);
3406         break;
3407       case RNA.DRAW_MODE_LINEAR:
3408         _RNA.drawRNALine(_conf);
3409         break;
3410       case RNA.DRAW_MODE_NAVIEW:
3411         try
3412         {
3413           _RNA.drawRNANAView(_conf);
3414         } catch (ExceptionNAViewAlgorithm e)
3415         {
3416           errorDialog(e);
3417         }
3418         break;
3419       default:
3420         break;
3421       }
3422
3423     }
3424   }
3425
3426   /**
3427    * Returns the currently selected base index, obtained through a mouse-left
3428    * click
3429    * 
3430    * @return Selected base
3431    * 
3432    *         public int getSelectedBaseIndex() { return _selectedBase; }
3433    * 
3434    *         /** Returns the currently selected base, obtained through a
3435    *         mouse-left click
3436    * 
3437    * @return Selected base
3438    * 
3439    *         public ModeleBase getSelectedBase() { return
3440    *         _RNA.get_listeBases().get(_selectedBase); }
3441    * 
3442    *         /** Sets the selected base index
3443    * 
3444    * @param base
3445    *          New selected base index
3446    * 
3447    *          public void setSelectedBase(int base) { _selectedBase = base; }
3448    */
3449
3450   /**
3451    * Returns the coordinates of the currently displayed RNA
3452    * 
3453    * @return Coordinates array
3454    */
3455   public Point2D.Double[] getRealCoords()
3456   {
3457     return _realCoords;
3458   }
3459
3460   /**
3461    * Sets the coordinates of the currently displayed RNA
3462    * 
3463    * @param coords
3464    *          New coordinates
3465    */
3466   public void setRealCoords(Point2D.Double[] coords)
3467   {
3468     _realCoords = coords;
3469   }
3470
3471   /**
3472    * Returns the popup menu used for user mouse iteractions
3473    * 
3474    * @return Popup menu
3475    */
3476   public VueMenu getPopup()
3477   {
3478     return _popup;
3479   }
3480
3481   /**
3482    * Sets the color used to display hydrogen bonds (base pairings)
3483    * 
3484    * @param bond_color
3485    *          The color of hydrogen bonds
3486    */
3487   public void setBondColor(Color bond_color)
3488   {
3489     _conf._bondColor = bond_color;
3490   }
3491
3492   /**
3493    * Returns the color used to draw the title
3494    * 
3495    * @return The color used to draw the title
3496    */
3497   public Color getTitleColor()
3498   {
3499     return _conf._titleColor;
3500   }
3501
3502   /**
3503    * Sets the color used to draw the title
3504    * 
3505    * @param title_color
3506    *          The new color used to draw the title
3507    */
3508   public void setTitleColor(Color title_color)
3509   {
3510     _conf._titleColor = title_color;
3511   }
3512
3513   /**
3514    * Returns the height taken by the title
3515    * 
3516    * @return The height taken by the title
3517    */
3518   private int getTitleHeight()
3519   {
3520     return _titleHeight;
3521   }
3522
3523   /**
3524    * Sets the height taken by the title
3525    * 
3526    * @param title_height
3527    *          The height taken by the title
3528    */
3529   @SuppressWarnings("unused")
3530   private void setTitleHeight(int title_height)
3531   {
3532     _titleHeight = title_height;
3533   }
3534
3535   /**
3536    * Returns the current state of auto centering mode.
3537    * 
3538    * @return True if autocentered, false otherwise
3539    */
3540   public boolean isAutoCentered()
3541   {
3542     return _conf._autoCenter;
3543   }
3544
3545   /**
3546    * Sets the current state of auto centering mode.
3547    * 
3548    * @param center
3549    *          New auto-centered state
3550    */
3551   public void setAutoCenter(boolean center)
3552   {
3553     _conf._autoCenter = center;
3554   }
3555
3556   /**
3557    * Returns the font currently used for rendering the title.
3558    * 
3559    * @return Current title font
3560    */
3561   public Font getTitleFont()
3562   {
3563     return _conf._titleFont;
3564   }
3565
3566   /**
3567    * Sets the font used for rendering the title.
3568    * 
3569    * @param font
3570    *          New title font
3571    */
3572   public void setTitleFont(Font font)
3573   {
3574     _conf._titleFont = font;
3575     updateTitleHeight();
3576   }
3577
3578   /**
3579    * For the LINE_MODE drawing algorithm, sets the base pair height increment,
3580    * i.e. the vertical distance between two nested arcs.
3581    * 
3582    * @return The current base pair increment
3583    */
3584   public double getBPHeightIncrement()
3585   {
3586     return _RNA._bpHeightIncrement;
3587   }
3588
3589   /**
3590    * Sets the base pair height increment, i.e. the vertical distance between two
3591    * arcs to be used in LINE_MODE.
3592    * 
3593    * @param inc
3594    *          New height increment
3595    */
3596   public void setBPHeightIncrement(double inc)
3597   {
3598     _RNA._bpHeightIncrement = inc;
3599   }
3600
3601   /**
3602    * Returns the shifting of the origin of the Panel in zoom mode
3603    * 
3604    * @return The logical coordinate of the top-left panel point
3605    */
3606   public Point2D.Double getOffsetPanel()
3607   {
3608     return _offsetPanel;
3609   }
3610
3611   /**
3612    * Returns the vector bringing the logical coordinate of left-top-most point
3613    * in the panel to the left-top-most point of the RNA.
3614    * 
3615    * @return The logical coordinate of the top-left panel point
3616    */
3617   private Point2D.Double getRNAOffset()
3618   {
3619     return _offsetRNA;
3620   }
3621
3622   /**
3623    * Returns this panel's UI menu
3624    * 
3625    * @return Applet's UI popupmenu
3626    */
3627   public VueMenu getPopupMenu()
3628   {
3629     return _popup;
3630   }
3631
3632   /**
3633    * Returns the atomic zoom factor step, or increment.
3634    * 
3635    * @return Atomic zoom factor increment
3636    */
3637   public double getZoomIncrement()
3638   {
3639     return _conf._zoomAmount;
3640   }
3641
3642   /**
3643    * Sets the atomic zoom factor step, or increment.
3644    * 
3645    * @param amount
3646    *          Atomic zoom factor increment
3647    */
3648   public void setZoomIncrement(Object amount)
3649   {
3650     setZoomIncrement(Float.valueOf(amount.toString()));
3651   }
3652
3653   /**
3654    * Sets the atomic zoom factor step, or increment.
3655    * 
3656    * @param amount
3657    *          Atomic zoom factor increment
3658    */
3659   public void setZoomIncrement(double amount)
3660   {
3661     _conf._zoomAmount = amount;
3662   }
3663
3664   /**
3665    * Returns the current zoom factor
3666    * 
3667    * @return Current zoom factor
3668    */
3669   public double getZoom()
3670   {
3671     return _conf._zoom;
3672   }
3673
3674   /**
3675    * Sets the current zoom factor
3676    * 
3677    * @param _zoom
3678    *          New zoom factor
3679    */
3680   public void setZoom(Object _zoom)
3681   {
3682     double d = Float.valueOf(_zoom.toString());
3683     if (_conf._zoom != d)
3684     {
3685       _conf._zoom = d;
3686       fireZoomLevelChanged(d);
3687     }
3688   }
3689
3690   /**
3691    * Returns the translation used for zooming in and out
3692    * 
3693    * @return A vector describing the translation
3694    */
3695   public Point getTranslation()
3696   {
3697     return _translation;
3698   }
3699
3700   /**
3701    * Sets the translation used for zooming in and out
3702    * 
3703    * @param trans
3704    *          A vector describing the new translation
3705    */
3706   public void setTranslation(Point trans)
3707   {
3708     _translation = trans;
3709     checkTranslation();
3710     fireTranslationChanged();
3711   }
3712
3713   /**
3714    * Returns the current RNA model
3715    * 
3716    * @return Current RNA model
3717    */
3718   public RNA getRNA()
3719   {
3720     return _RNA;
3721   }
3722
3723   /**
3724    * Checks whether the drawn RNA is too large to be displayed, allowing for
3725    * shifting mouse interactions.
3726    * 
3727    * @return true if the RNA is too large to be displayed, false otherwise
3728    */
3729   public boolean isOutOfFrame()
3730   {
3731     return _horsCadre;
3732   }
3733
3734   /**
3735    * Pops up an error Dialog displaying an exception in an human-readable way.
3736    * 
3737    * @param error
3738    *          The exception to display within the Dialog
3739    */
3740   public void errorDialog(Exception error)
3741   {
3742     errorDialog(error, this);
3743   }
3744
3745   /**
3746    * Pops up an error Dialog displaying an exception in an human-readable way if
3747    * errors are set to be displayed.
3748    * 
3749    * @see #setErrorsOn(boolean)
3750    * @param error
3751    *          The exception to display within the Dialog
3752    * @param c
3753    *          Parent component for the dialog box
3754    */
3755   public void errorDialog(Exception error, Component c)
3756   {
3757     if (isErrorsOn())
3758     {
3759       JOptionPane.showMessageDialog(c, error.getMessage(), "VARNA Error",
3760               JOptionPane.ERROR_MESSAGE);
3761     }
3762   }
3763
3764   /**
3765    * Pops up an error Dialog displaying an exception in an human-readable way.
3766    * 
3767    * @param error
3768    *          The exception to display within the Dialog
3769    * @param c
3770    *          Parent component for the dialog box
3771    */
3772   public static void errorDialogStatic(Exception error, Component c)
3773   {
3774     if (c != null)
3775     {
3776       JOptionPane.showMessageDialog(c, error.getMessage(),
3777               "VARNA Critical Error", JOptionPane.ERROR_MESSAGE);
3778     }
3779     else
3780     {
3781       System.err.println("Error: " + error.getMessage());
3782     }
3783   }
3784
3785   /**
3786    * Displays a warning message through a modal dialog if warnings are set to be
3787    * displayed.
3788    * 
3789    * @see #setShowWarnings(boolean)
3790    * @param warning
3791    *          A message expliciting the warning
3792    */
3793   public void emitWarning(String warning)
3794   {
3795     if (_conf._showWarnings)
3796     {
3797       JOptionPane.showMessageDialog(this, warning, "VARNA Warning",
3798               JOptionPane.WARNING_MESSAGE);
3799     }
3800   }
3801
3802   public static void emitWarningStatic(Exception e, Component c)
3803   {
3804     emitWarningStatic(e.getMessage(), c);
3805   }
3806
3807   public static void emitWarningStatic(String warning, Component c)
3808   {
3809     if (c != null)
3810     {
3811       JOptionPane.showMessageDialog(c, warning, "VARNA Warning",
3812               JOptionPane.WARNING_MESSAGE);
3813     }
3814     else
3815     {
3816       System.err.println("Error: " + warning);
3817     }
3818   }
3819
3820   /**
3821    * Toggles modifications on and off
3822    * 
3823    * @param modifiable
3824    *          Modification status
3825    */
3826   public void setModifiable(boolean modifiable)
3827   {
3828     _conf._modifiable = modifiable;
3829   }
3830
3831   /**
3832    * Returns current modification status
3833    * 
3834    * @return current modification status
3835    */
3836   public boolean isModifiable()
3837   {
3838     return _conf._modifiable;
3839   }
3840
3841   /**
3842    * Resets the visual aspects (Zoom factor, shift) for the Panel.
3843    */
3844   public void reset()
3845   {
3846     this.setBorderSize(new Dimension(0, 0));
3847     this.setTranslation(new Point(0, (int) (-getTitleHeight() / 2.0)));
3848     this.setZoom(VARNAConfig.DEFAULT_ZOOM);
3849     this.setZoomIncrement(VARNAConfig.DEFAULT_AMOUNT);
3850   }
3851
3852   /**
3853    * Returns the color used to draw non-standard bases
3854    * 
3855    * @return The color used to draw non-standard bases
3856    */
3857   public Color getNonStandardBasesColor()
3858   {
3859     return _conf._specialBasesColor;
3860   }
3861
3862   /**
3863    * Sets the color used to draw non-standard bases
3864    * 
3865    * @param basesColor
3866    *          The color used to draw non-standard bases
3867    */
3868   public void setNonStandardBasesColor(Color basesColor)
3869   {
3870     _conf._specialBasesColor = basesColor;
3871   }
3872
3873   /**
3874    * Checks if the current translation doesn't "kick" the whole RNA out of the
3875    * panel, and corrects the situation if necessary.
3876    */
3877   public void checkTranslation()
3878   {
3879     // verification pour un zoom < 1
3880     if (this.getZoom() <= 1)
3881     {
3882       // verification sortie gauche
3883       if (this.getTranslation().x < -(int) ((this.getWidth()
3884               - this.getInnerWidth()) / 2.0))
3885       {
3886         this.setTranslation(new Point(
3887                 -(int) ((this.getWidth() - this.getInnerWidth()) / 2.0),
3888                 this.getTranslation().y));
3889       }
3890       // verification sortie droite
3891       if (this.getTranslation().x > (int) ((this.getWidth()
3892               - this.getInnerWidth()) / 2.0))
3893       {
3894         this.setTranslation(new Point(
3895                 (int) ((this.getWidth() - this.getInnerWidth()) / 2.0),
3896                 this.getTranslation().y));
3897       }
3898       // verification sortie bas
3899       if (this.getTranslation().y > (int) ((this.getHeight()
3900               - getTitleHeight() * 2 - this.getInnerHeight()) / 2.0))
3901       {
3902         this.setTranslation(new Point(this.getTranslation().x,
3903                 (int) ((this.getHeight() - getTitleHeight() * 2
3904                         - this.getInnerHeight()) / 2.0)));
3905       }
3906       // verification sortie haut
3907       if (this.getTranslation().y < -(int) ((this.getHeight()
3908               - this.getInnerHeight()) / 2.0))
3909       {
3910         this.setTranslation(new Point(this.getTranslation().x,
3911                 -(int) ((this.getHeight() - this.getInnerHeight()) / 2.0)));
3912       }
3913     }
3914     else
3915     {
3916       // zoom > 1
3917       Rectangle r2 = getZoomedInTranslationBox();
3918       int LBoundX = r2.x;
3919       int UBoundX = r2.x + r2.width;
3920       int LBoundY = r2.y;
3921       int UBoundY = r2.y + r2.height;
3922       if (this.getTranslation().x < LBoundX)
3923       {
3924         this.setTranslation(new Point(LBoundX, getTranslation().y));
3925       }
3926       else if (this.getTranslation().x > UBoundX)
3927       {
3928         this.setTranslation(new Point(UBoundX, getTranslation().y));
3929       }
3930       if (this.getTranslation().y < LBoundY)
3931       {
3932         this.setTranslation(new Point(getTranslation().x, LBoundY));
3933       }
3934       else if (this.getTranslation().y > UBoundY)
3935       {
3936         this.setTranslation(new Point(getTranslation().x, UBoundY));
3937       }
3938     }
3939   }
3940
3941   public Rectangle getZoomedInTranslationBox()
3942   {
3943     int LBoundX = -(int) ((this.getInnerWidth()) / 2.0);
3944     int UBoundX = (int) ((this.getInnerWidth()) / 2.0);
3945     int LBoundY = -(int) ((this.getInnerHeight()) / 2.0);
3946     int UBoundY = (int) ((this.getInnerHeight()) / 2.0);
3947     return new Rectangle(LBoundX, LBoundY, UBoundX - LBoundX,
3948             UBoundY - LBoundY);
3949
3950   }
3951
3952   /**
3953    * Returns the "real pixels" x-coordinate of the RNA.
3954    * 
3955    * @return X-coordinate of the translation
3956    */
3957   public int getLeftOffset()
3958   {
3959     return _border.width + ((this.getWidth() - 2 * _border.width)
3960             - this.getInnerWidth()) / 2 + _translation.x;
3961   }
3962
3963   /**
3964    * Returns the "real pixels" width of the drawing surface for our RNA.
3965    * 
3966    * @return Width of the drawing surface for our RNA
3967    */
3968   public int getInnerWidth()
3969   {
3970     // Largeur du dessin
3971     return (int) Math
3972             .round((this.getWidth() - 2 * _border.width) * _conf._zoom);
3973   }
3974
3975   /**
3976    * Returns the "real pixels" y-coordinate of the RNA.
3977    * 
3978    * @return Y-coordinate of the translation
3979    */
3980   public int getTopOffset()
3981   {
3982     return _border.height + ((this.getHeight() - 2 * _border.height)
3983             - this.getInnerHeight()) / 2 + _translation.y;
3984   }
3985
3986   /**
3987    * Returns the "real pixels" height of the drawing surface for our RNA.
3988    * 
3989    * @return Height of the drawing surface for our RNA
3990    */
3991   public int getInnerHeight()
3992   {
3993     // Hauteur du dessin
3994     return (int) Math.round((this.getHeight()) * _conf._zoom
3995             - 2 * _border.height - getTitleHeight());
3996   }
3997
3998   /**
3999    * Checks if the current mode is the "comparison" mode
4000    * 
4001    * @return True if comparison, false otherwise
4002    */
4003   public boolean isComparisonMode()
4004   {
4005     return _conf._comparisonMode;
4006   }
4007
4008   /**
4009    * Rotates the RNA coordinates by a certain angle
4010    * 
4011    * @param angleDegres
4012    *          Rotation angle, in degrees
4013    */
4014   public void globalRotation(Double angleDegres)
4015   {
4016     _RNA.globalRotation(angleDegres);
4017     fireLayoutChanged();
4018     repaint();
4019   }
4020
4021   /**
4022    * Returns the index of the currently selected base, defaulting to the closest
4023    * base to the last mouse-click.
4024    * 
4025    * @return Index of the currently selected base
4026    */
4027   public Integer getNearestBase()
4028   {
4029     return _nearestBase;
4030   }
4031
4032   /**
4033    * Sets the index of the currently selected base.
4034    * 
4035    * @param base
4036    *          Index of the new selected base
4037    */
4038   public void setNearestBase(Integer base)
4039   {
4040     _nearestBase = base;
4041   }
4042
4043   /**
4044    * Returns the color used to draw 'Gaps' bases in comparison mode
4045    * 
4046    * @return Color used for 'Gaps'
4047    */
4048   public Color getGapsBasesColor()
4049   {
4050     return _conf._dashBasesColor;
4051   }
4052
4053   /**
4054    * Sets the color to use for 'Gaps' bases in comparison mode
4055    * 
4056    * @param c
4057    *          Color used for 'Gaps'
4058    */
4059   public void setGapsBasesColor(Color c)
4060   {
4061     _conf._dashBasesColor = c;
4062   }
4063
4064   @SuppressWarnings("unused")
4065   private void imprimer()
4066   {
4067     // PrintPanel canvas;
4068     // canvas = new PrintPanel();
4069     PrintRequestAttributeSet attributes;
4070     attributes = new HashPrintRequestAttributeSet();
4071     try
4072     {
4073       PrinterJob job = PrinterJob.getPrinterJob();
4074       // job.setPrintable(this);
4075       if (job.printDialog(attributes))
4076       {
4077         job.print(attributes);
4078       }
4079     } catch (PrinterException exception)
4080     {
4081       errorDialog(exception);
4082     }
4083   }
4084
4085   /**
4086    * Checks whether errors are to be displayed
4087    * 
4088    * @return Error display status
4089    */
4090   public boolean isErrorsOn()
4091   {
4092     return _conf._errorsOn;
4093   }
4094
4095   /**
4096    * Sets whether errors are to be displayed
4097    * 
4098    * @param on
4099    *          New error display status
4100    */
4101   public void setErrorsOn(boolean on)
4102   {
4103     _conf._errorsOn = on;
4104   }
4105
4106   /**
4107    * Returns the view associated with user interactions
4108    * 
4109    * @return A view associated with user interactions
4110    */
4111   public VueUI getVARNAUI()
4112   {
4113     return _UI;
4114   }
4115
4116   /**
4117    * Toggles on/off using base inner color for drawing base-pairs
4118    * 
4119    * @param on
4120    *          True for using base inner color for drawing base-pairs, false for
4121    *          classic mode
4122    */
4123   public void setUseBaseColorsForBPs(boolean on)
4124   {
4125     _conf._useBaseColorsForBPs = on;
4126   }
4127
4128   /**
4129    * Returns true if current base color is used as inner color for drawing
4130    * base-pairs
4131    * 
4132    * @return True for using base inner color for drawing base-pairs, false for
4133    *         classic mode
4134    */
4135   public boolean getUseBaseColorsForBPs()
4136   {
4137     return _conf._useBaseColorsForBPs;
4138   }
4139
4140   /**
4141    * Toggles on/off using a special color used for drawing "non-standard" bases
4142    * 
4143    * @param on
4144    *          True for using a special color used for drawing "non-standard"
4145    *          bases, false for classic mode
4146    */
4147   public void setColorNonStandardBases(boolean on)
4148   {
4149     _conf._colorSpecialBases = on;
4150   }
4151
4152   /**
4153    * Returns true if a special color is used as inner color for non-standard
4154    * base
4155    * 
4156    * @return True for using a special color used for drawing "non-standard"
4157    *         bases, false for classic mode
4158    */
4159   public boolean getColorSpecialBases()
4160   {
4161     return _conf._colorSpecialBases;
4162   }
4163
4164   /**
4165    * Toggles on/off using a special color used for drawing "Gaps" bases in
4166    * comparison mode
4167    * 
4168    * @param on
4169    *          True for using a special color used for drawing "Gaps" bases in
4170    *          comparison mode, false for classic mode
4171    */
4172   public void setColorGapsBases(boolean on)
4173   {
4174     _conf._colorDashBases = on;
4175   }
4176
4177   /**
4178    * Returns true if a special color is used for drawing "Gaps" bases in
4179    * comparison mode
4180    * 
4181    * @return True for using a special color used for drawing "Gaps" bases in
4182    *         comparison mode, false for classic mode
4183    */
4184   public boolean getColorGapsBases()
4185   {
4186     return _conf._colorDashBases;
4187   }
4188
4189   /**
4190    * Toggles on/off displaying warnings
4191    * 
4192    * @param on
4193    *          True to display warnings, false otherwise
4194    */
4195   public void setShowWarnings(boolean on)
4196   {
4197     _conf._showWarnings = on;
4198   }
4199
4200   /**
4201    * Get current warning display status
4202    * 
4203    * @return True to display warnings, false otherwise
4204    */
4205   public boolean getShowWarnings()
4206   {
4207     return _conf._showWarnings;
4208   }
4209
4210   /**
4211    * Toggles on/off displaying non-canonical base-pairs
4212    * 
4213    * @param on
4214    *          True to display NC base-pairs, false otherwise
4215    */
4216   public void setShowNonCanonicalBP(boolean on)
4217   {
4218     _conf._drawnNonCanonicalBP = on;
4219   }
4220
4221   /**
4222    * Return the current display status for non-canonical base-pairs
4223    * 
4224    * @return True if NC base-pairs are displayed, false otherwise
4225    */
4226   public boolean getShowNonCanonicalBP()
4227   {
4228     return _conf._drawnNonCanonicalBP;
4229   }
4230
4231   /**
4232    * Toggles on/off displaying "non-planar" base-pairs
4233    * 
4234    * @param on
4235    *          True to display "non-planar" base-pairs, false otherwise
4236    */
4237   public void setShowNonPlanarBP(boolean on)
4238   {
4239     _conf._drawnNonPlanarBP = on;
4240   }
4241
4242   /**
4243    * Return the current display status for non-planar base-pairs
4244    * 
4245    * @return True if non-planars base-pairs are displayed, false otherwise
4246    */
4247   public boolean getShowNonPlanarBP()
4248   {
4249     return _conf._drawnNonPlanarBP;
4250   }
4251
4252   /**
4253    * Sets the base-pair representation style
4254    * 
4255    * @param st
4256    *          The new base-pair style
4257    */
4258   public void setBPStyle(VARNAConfig.BP_STYLE st)
4259   {
4260     _conf._mainBPStyle = st;
4261   }
4262
4263   /**
4264    * Returns the base-pair representation style
4265    * 
4266    * @return The current base-pair style
4267    */
4268   public VARNAConfig.BP_STYLE getBPStyle()
4269   {
4270     return _conf._mainBPStyle;
4271   }
4272
4273   /**
4274    * Returns the current VARNA Panel configuration. The returned instance should
4275    * not be modified directly, but rather through the getters/setters from the
4276    * VARNAPanel class.
4277    * 
4278    * @return Current configuration
4279    */
4280   public VARNAConfig getConfig()
4281   {
4282     return _conf;
4283   }
4284
4285   /**
4286    * Sets the background color
4287    * 
4288    * @param c
4289    *          New background color
4290    */
4291   @Override
4292   public void setBackground(Color c)
4293   {
4294     if (_conf != null)
4295     {
4296       if (c != null)
4297       {
4298         _conf._backgroundColor = c;
4299         _conf._drawBackground = (!c
4300                 .equals(VARNAConfig.DEFAULT_BACKGROUND_COLOR));
4301       }
4302       else
4303       {
4304         _conf._backgroundColor = VARNAConfig.DEFAULT_BACKGROUND_COLOR;
4305         _conf._drawBackground = false;
4306       }
4307     }
4308
4309   }
4310
4311   /**
4312    * Starts highlighting the selected base.
4313    */
4314   public void highlightSelectedBase(ModeleBase m)
4315   {
4316     ArrayList<Integer> v = new ArrayList<>();
4317     int sel = m.getIndex();
4318     if (sel != -1)
4319     {
4320       v.add(sel);
4321     }
4322     setSelection(v);
4323   }
4324
4325   /**
4326    * Starts highlighting the selected base.
4327    */
4328   public void highlightSelectedStem(ModeleBase m)
4329   {
4330     ArrayList<Integer> v = new ArrayList<>();
4331     int sel = m.getIndex();
4332     if (sel != -1)
4333     {
4334       ArrayList<Integer> r = _RNA.findStem(sel);
4335       v.addAll(r);
4336     }
4337     setSelection(v);
4338   }
4339
4340   public BaseList getSelection()
4341   {
4342     return _selectedBases;
4343   }
4344
4345   public ArrayList<Integer> getSelectionIndices()
4346   {
4347     return _selectedBases.getIndices();
4348   }
4349
4350   public void setSelection(ArrayList<Integer> indices)
4351   {
4352     setSelection(_RNA.getBasesAt(indices));
4353   }
4354
4355   public void setSelection(Collection<? extends ModeleBase> mbs)
4356   {
4357     BaseList bck = new BaseList(_selectedBases);
4358     _selectedBases.clear();
4359     _selectedBases.addBases(mbs);
4360     _blink.setActive(true);
4361     fireSelectionChanged(bck, _selectedBases);
4362   }
4363
4364   public ArrayList<Integer> getBasesInRectangleDiff(Rectangle recIn,
4365           Rectangle recOut)
4366   {
4367     ArrayList<Integer> result = new ArrayList<>();
4368     for (int i = 0; i < _realCoords.length; i++)
4369     {
4370       if (recIn.contains(_realCoords[i]) ^ recOut.contains(_realCoords[i]))
4371       {
4372         result.add(i);
4373       }
4374     }
4375     return result;
4376   }
4377
4378   public ArrayList<Integer> getBasesInRectangle(Rectangle rec)
4379   {
4380     ArrayList<Integer> result = new ArrayList<>();
4381     for (int i = 0; i < _realCoords.length; i++)
4382     {
4383       if (rec.contains(_realCoords[i]))
4384       {
4385         result.add(i);
4386       }
4387     }
4388     return result;
4389   }
4390
4391   public void setSelectionRectangle(Rectangle rec)
4392   {
4393     ArrayList<Integer> result = new ArrayList<>();
4394     if (_selectionRectangle != null)
4395     {
4396       result = getBasesInRectangleDiff(_selectionRectangle, rec);
4397     }
4398     else
4399     {
4400       result = getBasesInRectangle(rec);
4401     }
4402     _selectionRectangle = new Rectangle(rec);
4403     toggleSelection(result);
4404     repaint();
4405   }
4406
4407   public void removeSelectionRectangle()
4408   {
4409     _selectionRectangle = null;
4410   }
4411
4412   public void addToSelection(Collection<? extends Integer> indices)
4413   {
4414     for (int i : indices)
4415     {
4416       addToSelection(i);
4417     }
4418   }
4419
4420   public void addToSelection(int i)
4421   {
4422     BaseList bck = new BaseList(_selectedBases);
4423     ModeleBase mb = _RNA.getBaseAt(i);
4424     _selectedBases.addBase(mb);
4425     _blink.setActive(true);
4426     fireSelectionChanged(bck, _selectedBases);
4427   }
4428
4429   public void removeFromSelection(int i)
4430   {
4431     BaseList bck = new BaseList(_selectedBases);
4432     ModeleBase mb = _RNA.getBaseAt(i);
4433     _selectedBases.removeBase(mb);
4434     if (_selectedBases.size() == 0)
4435     {
4436       _blink.setActive(false);
4437     }
4438     else
4439     {
4440       _blink.setActive(true);
4441     }
4442     fireSelectionChanged(bck, _selectedBases);
4443   }
4444
4445   public boolean isInSelection(int i)
4446   {
4447     return _selectedBases.contains(_RNA.getBaseAt(i));
4448   }
4449
4450   public void toggleSelection(int i)
4451   {
4452     if (isInSelection(i))
4453     {
4454       removeFromSelection(i);
4455     }
4456     else
4457     {
4458       addToSelection(i);
4459     }
4460   }
4461
4462   public void toggleSelection(Collection<? extends Integer> indices)
4463   {
4464     for (int i : indices)
4465     {
4466       toggleSelection(i);
4467     }
4468   }
4469
4470   /**
4471    * Stops highlighting bases
4472    */
4473   public void clearSelection()
4474   {
4475     BaseList bck = new BaseList(_selectedBases);
4476     _selectedBases.clear();
4477     _blink.setActive(false);
4478     repaint();
4479     fireSelectionChanged(bck, _selectedBases);
4480   }
4481
4482   public void saveSelection()
4483   {
4484     _backupSelection.clear();
4485     _backupSelection.addAll(_selectedBases.getBases());
4486   }
4487
4488   public void restoreSelection()
4489   {
4490     setSelection(_backupSelection);
4491   }
4492
4493   /**
4494    * Stops highlighting bases
4495    */
4496   public void resetAnnotationHighlight()
4497   {
4498     _highlightAnnotation = false;
4499     repaint();
4500   }
4501
4502   /**
4503    * Toggles on/off a rectangular outline of the bounding box.
4504    * 
4505    * @param on
4506    *          True to draw the bounding box, false otherwise
4507    */
4508   public void drawBBox(boolean on)
4509   {
4510     _drawBBox = on;
4511   }
4512
4513   /**
4514    * Toggles on/off a rectangular outline of the border.
4515    * 
4516    * @param on
4517    *          True to draw the bounding box, false otherwise
4518    */
4519   public void drawBorder(boolean on)
4520   {
4521     _drawBorder = on;
4522   }
4523
4524   public void setBaseInnerColor(Color c)
4525   {
4526     _RNA.setBaseInnerColor(c);
4527   }
4528
4529   public void setBaseNumbersColor(Color c)
4530   {
4531     _RNA.setBaseNumbersColor(c);
4532   }
4533
4534   public void setBaseNameColor(Color c)
4535   {
4536     _RNA.setBaseNameColor(c);
4537   }
4538
4539   public void setBaseOutlineColor(Color c)
4540   {
4541     _RNA.setBaseOutlineColor(c);
4542   }
4543
4544   public ArrayList<TextAnnotation> getListeAnnotations()
4545   {
4546     return _RNA.getAnnotations();
4547   }
4548
4549   public void resetListeAnnotations()
4550   {
4551     _RNA.clearAnnotations();
4552     repaint();
4553   }
4554
4555   public void addAnnotation(TextAnnotation textAnnotation)
4556   {
4557     _RNA.addAnnotation(textAnnotation);
4558     repaint();
4559   }
4560
4561   public boolean removeAnnotation(TextAnnotation textAnnotation)
4562   {
4563     boolean done = _RNA.removeAnnotation(textAnnotation);
4564     repaint();
4565     return done;
4566   }
4567
4568   public TextAnnotation get_selectedAnnotation()
4569   {
4570     return _selectedAnnotation;
4571   }
4572
4573   public void set_selectedAnnotation(TextAnnotation annotation)
4574   {
4575     _selectedAnnotation = annotation;
4576   }
4577
4578   public void removeSelectedAnnotation()
4579   {
4580     _highlightAnnotation = false;
4581     _selectedAnnotation = null;
4582   }
4583
4584   public void highlightSelectedAnnotation()
4585   {
4586     _highlightAnnotation = true;
4587   }
4588
4589   public boolean getFlatExteriorLoop()
4590   {
4591     return _conf._flatExteriorLoop;
4592   }
4593
4594   public void setFlatExteriorLoop(boolean on)
4595   {
4596     _conf._flatExteriorLoop = on;
4597   }
4598
4599   public void setLastSelectedPosition(Point2D.Double p)
4600   {
4601     _lastSelectedCoord.x = p.x;
4602     _lastSelectedCoord.y = p.y;
4603   }
4604
4605   public Point2D.Double getLastSelectedPosition()
4606   {
4607     return _lastSelectedCoord;
4608   }
4609
4610   public void setSequence(String s)
4611   {
4612     _RNA.setSequence(s);
4613     repaint();
4614   }
4615
4616   public void setColorMapVisible(boolean b)
4617   {
4618     _conf._drawColorMap = b;
4619     repaint();
4620   }
4621
4622   public boolean getColorMapVisible()
4623   {
4624     return _conf._drawColorMap;
4625   }
4626
4627   public void removeColorMap()
4628   {
4629     _conf._drawColorMap = false;
4630     repaint();
4631   }
4632
4633   public void saveSession(String path)
4634   {
4635     /*
4636      * FileOutputStream fos = null; ObjectOutputStream out = null; try { fos
4637      * = new FileOutputStream(path); out = new ObjectOutputStream(fos);
4638      * out.writeObject(new FullBackup(_conf, _RNA, _conf._title));
4639      * out.close(); } catch (Exception ex) { ex.printStackTrace(); }
4640      */
4641     toXML(path);
4642   }
4643
4644   /** Added for Jalview */
4645
4646   public FullBackup loadSession(String path) throws ExceptionLoadingFailed
4647   {
4648     return loadSession(new File(path));
4649   }
4650
4651   public FullBackup loadSession(File path) throws ExceptionLoadingFailed
4652   {
4653
4654     FullBackup bck = importSession(path);
4655     Mapping map = Mapping.DefaultOutermostMapping(getRNA().getSize(),
4656             bck.rna.getSize());
4657     showRNAInterpolated(bck.rna, map);
4658     _conf = bck.config;
4659     repaint();
4660     return bck;
4661   }
4662
4663   public static String VARNA_SESSION_EXTENSION = "varna";
4664
4665   public static FullBackup importSession(Object path) // BH was String
4666           throws ExceptionLoadingFailed
4667   {
4668     try
4669     {
4670       FileInputStream fis = (path instanceof File
4671               ? new FileInputStream((File) path)
4672               : new FileInputStream(path.toString()));
4673       // ZipInputStream zis = new
4674       // ZipInputStream(new BufferedInputStream(fis));
4675       // zis.getNextEntry();
4676       FullBackup h = importSession(fis, path.toString());
4677       // zis.close();
4678       return h;
4679     } catch (FileNotFoundException e)
4680     {
4681       throw (new ExceptionLoadingFailed("File not found.",
4682               path.toString()));
4683     } catch (IOException e)
4684     {
4685       // TODO Auto-generated catch block
4686       throw (new ExceptionLoadingFailed("I/O error while loading session.",
4687               path.toString()));
4688     }
4689   }
4690
4691   public static FullBackup importSession(InputStream fis, String path)
4692           throws ExceptionLoadingFailed
4693   {
4694     System.setProperty("javax.xml.parsers.SAXParserFactory",
4695             "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
4696     SAXParserFactory saxFact = javax.xml.parsers.SAXParserFactory
4697             .newInstance();
4698     saxFact.setValidating(false);
4699     saxFact.setXIncludeAware(false);
4700     saxFact.setNamespaceAware(false);
4701     try
4702     {
4703       SAXParser sp = saxFact.newSAXParser();
4704       VARNASessionParser sessionData = new VARNASessionParser();
4705       sp.parse(fis, sessionData);
4706       FullBackup res = new FullBackup(sessionData.getVARNAConfig(),
4707               sessionData.getRNA(), "test");
4708       return res;
4709     } catch (ParserConfigurationException e)
4710     {
4711       throw new ExceptionLoadingFailed("Bad XML parser configuration",
4712               path);
4713     } catch (SAXException e)
4714     {
4715       throw new ExceptionLoadingFailed("XML parser Exception", path);
4716     } catch (IOException e)
4717     {
4718       throw new ExceptionLoadingFailed("I/O error", path);
4719     }
4720   }
4721
4722   public void loadFile(File path)
4723   {
4724     loadFile(path, false);
4725   }
4726
4727   public boolean getDrawBackbone()
4728   {
4729     return _conf._drawBackbone;
4730   }
4731
4732   public void setDrawBackbone(boolean b)
4733   {
4734     _conf._drawBackbone = b;
4735   }
4736
4737   public void addHighlightRegion(HighlightRegionAnnotation n)
4738   {
4739     _RNA.addHighlightRegion(n);
4740   }
4741
4742   public void removeHighlightRegion(HighlightRegionAnnotation n)
4743   {
4744     _RNA.removeHighlightRegion(n);
4745   }
4746
4747   public void addHighlightRegion(int i, int j)
4748   {
4749     _RNA.addHighlightRegion(i, j);
4750   }
4751
4752   public void addHighlightRegion(int i, int j, Color fill, Color outline,
4753           double radius)
4754   {
4755     _RNA.addHighlightRegion(i, j, fill, outline, radius);
4756   }
4757
4758   public void loadRNA(String path)
4759   {
4760     loadRNA(path, false);
4761   }
4762
4763   public void loadRNA(Object path, boolean interpolate)
4764   { // BH was String
4765     try
4766     {
4767       Collection<RNA> rnas = (path instanceof File
4768               ? RNAFactory.loadSecStr(new FileReader((File) path))
4769               : RNAFactory.loadSecStr(path.toString()));
4770       if (rnas.isEmpty())
4771       {
4772         throw new ExceptionFileFormatOrSyntax(
4773                 "No RNA could be parsed from that source.");
4774       }
4775       RNA rna = rnas.iterator().next();
4776       try
4777       {
4778         rna.drawRNA(_conf);
4779       } catch (ExceptionNAViewAlgorithm e)
4780       {
4781         e.printStackTrace();
4782       }
4783       if (!interpolate)
4784       {
4785         showRNA(rna);
4786       }
4787       else
4788       {
4789         this.showRNAInterpolated(rna);
4790       }
4791
4792     } catch (FileNotFoundException e)
4793     {
4794       e.printStackTrace();
4795     } catch (ExceptionFileFormatOrSyntax e)
4796     {
4797       e.printStackTrace();
4798     } catch (Exception e)
4799     {
4800       e.printStackTrace();
4801     }
4802   }
4803
4804   public void loadFile(File path, boolean interpolate)
4805   { // was String BH StringJS
4806     try
4807     {
4808       loadSession(path);
4809     } catch (Exception e1)
4810     {
4811       loadRNA(path, interpolate);
4812     }
4813   }
4814
4815   public void setConfig(VARNAConfig cfg)
4816   {
4817     _conf = cfg;
4818   }
4819
4820   public void toggleDrawOutlineBases()
4821   {
4822     _conf._drawOutlineBases = !_conf._drawOutlineBases;
4823   }
4824
4825   public void toggleFillBases()
4826   {
4827     _conf._fillBases = !_conf._fillBases;
4828   }
4829
4830   public void setDrawOutlineBases(boolean drawn)
4831   {
4832     _conf._drawOutlineBases = drawn;
4833   }
4834
4835   public void setFillBases(boolean drawn)
4836   {
4837     _conf._fillBases = drawn;
4838   }
4839
4840   public void readValues(Reader r)
4841   {
4842     this._RNA.readValues(r, _conf._cm);
4843   }
4844
4845   public void addVARNAListener(InterfaceVARNAListener v)
4846   {
4847     _VARNAListeners.add(v);
4848   }
4849
4850   public void fireLayoutChanged()
4851   {
4852     for (InterfaceVARNAListener v : _VARNAListeners)
4853     {
4854       v.onStructureRedrawn();
4855     }
4856   }
4857
4858   public void fireUINewStructure(RNA r)
4859   {
4860     for (InterfaceVARNAListener v : _VARNAListeners)
4861     {
4862       v.onUINewStructure(_conf, r);
4863     }
4864   }
4865
4866   public void fireZoomLevelChanged(double d)
4867   {
4868     for (InterfaceVARNAListener v : _VARNAListeners)
4869     {
4870       v.onZoomLevelChanged();
4871     }
4872   }
4873
4874   public void fireTranslationChanged()
4875   {
4876     for (InterfaceVARNAListener v2 : _VARNAListeners)
4877     {
4878       v2.onTranslationChanged();
4879     }
4880   }
4881
4882   public void addSelectionListener(InterfaceVARNASelectionListener v)
4883   {
4884     _selectionListeners.add(v);
4885   }
4886
4887   public void fireSelectionChanged(BaseList mold, BaseList mnew)
4888   {
4889     BaseList addedBases = mnew.removeAll(mold);
4890     BaseList removedBases = mold.removeAll(mnew);
4891     for (InterfaceVARNASelectionListener v2 : _selectionListeners)
4892     {
4893       v2.onSelectionChanged(mnew, addedBases, removedBases);
4894     }
4895   }
4896
4897   public void fireHoverChanged(ModeleBase mold, ModeleBase mnew)
4898   {
4899     for (InterfaceVARNASelectionListener v2 : _selectionListeners)
4900     {
4901       v2.onHoverChanged(mold, mnew);
4902     }
4903   }
4904
4905   public void addRNAListener(InterfaceVARNARNAListener v)
4906   {
4907     _RNAListeners.add(v);
4908   }
4909
4910   public void addVARNABasesListener(InterfaceVARNABasesListener l)
4911   {
4912     _basesListeners.add(l);
4913   }
4914
4915   public void fireSequenceChanged(int index, String oldseq, String newseq)
4916   {
4917     for (InterfaceVARNARNAListener v2 : _RNAListeners)
4918     {
4919       v2.onSequenceModified(index, oldseq, newseq);
4920     }
4921   }
4922
4923   public void fireStructureChanged(Set<ModeleBP> current,
4924           Set<ModeleBP> addedBasePairs, Set<ModeleBP> removedBasePairs)
4925   {
4926     for (InterfaceVARNARNAListener v2 : _RNAListeners)
4927     {
4928       v2.onStructureModified(current, addedBasePairs, removedBasePairs);
4929     }
4930   }
4931
4932   public void fireLayoutChanged(
4933           Hashtable<Integer, Point2D.Double> movedPositions)
4934   {
4935     for (InterfaceVARNARNAListener v2 : _RNAListeners)
4936     {
4937       v2.onRNALayoutChanged(movedPositions);
4938     }
4939   }
4940
4941   public void fireBaseClicked(ModeleBase mb, MouseEvent me)
4942   {
4943     if (mb != null)
4944     {
4945       for (InterfaceVARNABasesListener v2 : _basesListeners)
4946       {
4947         v2.onBaseClicked(mb, me);
4948       }
4949     }
4950   }
4951
4952   public double getOrientation()
4953   {
4954     return _RNA.getOrientation();
4955   }
4956
4957   public ModeleBase _hoveredBase = null;
4958
4959   public void setHoverBase(ModeleBase m)
4960   {
4961     if (m != _hoveredBase)
4962     {
4963       ModeleBase bck = _hoveredBase;
4964       _hoveredBase = m;
4965       repaint();
4966       fireHoverChanged(bck, m);
4967     }
4968   }
4969
4970   public void toXML(String path)
4971   {
4972     FileOutputStream fis;
4973     try
4974     {
4975       fis = new FileOutputStream(path);
4976       // ZipOutputStream zis = new ZipOutputStream(new
4977       // BufferedOutputStream(fis));
4978       // ZipEntry entry = new ZipEntry("VARNASession");
4979       // zis.putNextEntry(entry);
4980       PrintWriter pw = new PrintWriter(fis);
4981       toXML(pw);
4982       pw.flush();
4983       // zis.closeEntry();
4984       // zis.close();
4985       fis.close();
4986     } catch (FileNotFoundException e)
4987     {
4988       // TODO Auto-generated catch block
4989       e.printStackTrace();
4990     } catch (IOException e)
4991     {
4992       // TODO Auto-generated catch block
4993       e.printStackTrace();
4994     }
4995   }
4996
4997   public void toXML(PrintWriter out)
4998   {
4999     try
5000     {
5001
5002       // out = new PrintWriter(System.out);
5003       StreamResult streamResult = new StreamResult(out);
5004       SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory
5005               .newInstance();
5006       // SAX2.0 ContentHandler.
5007       TransformerHandler hd = tf.newTransformerHandler();
5008       Transformer serializer = hd.getTransformer();
5009       serializer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
5010       serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "users.dtd");
5011       serializer.setOutputProperty(OutputKeys.INDENT, "yes");
5012       hd.setResult(streamResult);
5013       hd.startDocument();
5014       toXML(hd);
5015       hd.endDocument();
5016     } catch (TransformerConfigurationException e)
5017     {
5018       // TODO Auto-generated catch block
5019       e.printStackTrace();
5020     } catch (SAXException e)
5021     {
5022       // TODO Auto-generated catch block
5023       e.printStackTrace();
5024     }
5025
5026   }
5027
5028   public static String XML_ELEMENT_NAME = "VARNASession";
5029
5030   public void toXML(TransformerHandler hd) throws SAXException
5031   {
5032     AttributesImpl atts = new AttributesImpl();
5033     hd.startElement("", "", XML_ELEMENT_NAME, atts);
5034     _RNA.toXML(hd);
5035     _conf.toXML(hd);
5036     hd.endElement("", "", XML_ELEMENT_NAME);
5037   }
5038
5039   public TextAnnotation getNearestAnnotation(int x, int y)
5040   {
5041     TextAnnotation t = null;
5042     if (getListeAnnotations().size() != 0)
5043     {
5044       double dist = Double.MAX_VALUE;
5045       double d2;
5046       Point2D.Double position;
5047       for (TextAnnotation textAnnot : getListeAnnotations())
5048       {
5049         // calcul de la distance
5050         position = textAnnot.getCenterPosition();
5051         position = transformCoord(position);
5052         d2 = Math.sqrt(Math.pow((position.x - x), 2)
5053                 + Math.pow((position.y - y), 2));
5054         // si la valeur est inferieur au minimum actuel
5055         if ((dist > d2) && (d2 < getScaleFactor()
5056                 * ControleurClicMovement.MIN_SELECTION_DISTANCE))
5057         {
5058           t = textAnnot;
5059           dist = d2;
5060         }
5061       }
5062     }
5063     return t;
5064   }
5065
5066   public ModeleBase getNearestBase(int x, int y, boolean always,
5067           boolean onlyPaired)
5068   {
5069     int i = getNearestBaseIndex(x, y, always, onlyPaired);
5070     if (i == -1)
5071     {
5072       return null;
5073     }
5074     return getRNA().get_listeBases().get(i);
5075   }
5076
5077   public ModeleBase getNearestBase(int x, int y)
5078   {
5079     return getNearestBase(x, y, false, false);
5080   }
5081
5082   public int getNearestBaseIndex(int x, int y, boolean always,
5083           boolean onlyPaired)
5084   {
5085     double d2, dist = Double.MAX_VALUE;
5086     int mb = -1;
5087     for (int i = 0; i < getRealCoords().length; i++)
5088     {
5089       if (!onlyPaired || (getRNA().get_listeBases().get(i)
5090               .getElementStructure() != -1))
5091       {
5092         d2 = Math.sqrt(Math.pow((getRealCoords()[i].x - x), 2)
5093                 + Math.pow((getRealCoords()[i].y - y), 2));
5094         if ((dist > d2) && ((d2 < getScaleFactor()
5095                 * ControleurClicMovement.MIN_SELECTION_DISTANCE) || always))
5096         {
5097           dist = d2;
5098           mb = i;
5099         }
5100       }
5101     }
5102     return mb;
5103   }
5104
5105   public void globalRescale(double factor)
5106   {
5107     _RNA.rescale(factor);
5108     fireLayoutChanged();
5109     repaint();
5110   }
5111
5112   public void setSpaceBetweenBases(double sp)
5113   {
5114     _conf._spaceBetweenBases = sp;
5115   }
5116
5117   public double getSpaceBetweenBases()
5118   {
5119     return _conf._spaceBetweenBases;
5120   }
5121
5122 }