JAL-3032 adds Java 8 functionality (2/2)
[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 j2s SwingJS Added PropertyChangeListener for returns from VueUI.  
739  * 
740  *  
741  *  
742  * 
743  * The RNA 2D Panel is a lightweight component that allows for an automatic
744  * basic drawing of an RNA secondary structures. The drawing algorithms do not
745  * ensure a non-overlapping drawing of helices, thus it is possible to "spin the
746  * helices" through a click-and-drag approach. A typical usage of the class from
747  * within the constructor of a <code>JFrame</code> would be the following:<br/>
748  * <code>
749  * &nbsp;&nbsp;VARNAPanel _rna = new VARNAPanel("CCCCAUAUGGGGACC","((((....))))...");<br />
750  * &nbsp;&nbsp;this.getContentPane().add(_rna);
751  * </code>
752  * 
753  * @version 3.4
754  * @author Yann Ponty & Kevin Darty
755  * 
756  */
757
758 public class VARNAPanel extends JPanel implements PropertyChangeListener {
759         
760         /**
761          * SwingJS uses a PropertyChangeEvent to signal that a pseudo-modal dialog has been closed.
762          *   
763          * @param event
764          */
765         @Override
766         public void propertyChange(PropertyChangeEvent event) {
767                 Object val = event.getNewValue();
768                 switch (event.getPropertyName()) {
769                 case "value":
770                         _UI.onDialogReturn(val == null ? JOptionPane.CLOSED_OPTION : ((Integer) val).intValue());
771                         return;
772                 case "SelectedFile":
773                 case "SelectedColor":
774                 case "inputValue":
775                         _UI.onDialogReturn(val);
776                         break;
777                 }
778         }
779
780  
781         
782         private static final long serialVersionUID = 8194421570308956001L;
783
784         private RNA _RNA = new RNA();
785
786         private boolean _debug = false;
787
788         private VARNAConfig _conf = new VARNAConfig();
789
790         private ArrayList<InterfaceVARNAListener> _VARNAListeners = new ArrayList<InterfaceVARNAListener>();
791         private ArrayList<InterfaceVARNASelectionListener> _selectionListeners = new ArrayList<InterfaceVARNASelectionListener>();
792         private ArrayList<InterfaceVARNARNAListener> _RNAListeners = new ArrayList<InterfaceVARNARNAListener>();
793         private ArrayList<InterfaceVARNABasesListener> _basesListeners = new ArrayList<InterfaceVARNABasesListener>();
794
795         UndoManager _manager;
796
797         // private boolean _foldMode = true;
798
799         private Point2D.Double[] _realCoords = new Point2D.Double[0];
800         private Point2D.Double[] _realCenters = new Point2D.Double[0];
801         private double _scaleFactor = 1.0;
802         private Point2D.Double _offsetPanel = new Point2D.Double();
803         private Point2D.Double _offsetRNA = new Point2D.Double();
804
805         private double _offX;
806         private double _offY;
807
808         private ControleurBlinkingThread _blink;
809         private BaseList _selectedBases = new BaseList("selection");
810         private ArrayList<ModeleBase> _backupSelection = new ArrayList<ModeleBase>();
811         private Integer _nearestBase = null;
812         private Point2D.Double _lastSelectedCoord = new Point2D.Double(0.0, 0.0);
813
814         private Point2D.Double _linkOrigin = null;
815         private Point2D.Double _linkDestination = null;
816
817         private Rectangle _selectionRectangle = null;
818
819         private boolean _highlightAnnotation = false;
820
821         private int _titleHeight;
822         private Dimension _border = new Dimension(0, 0);
823
824         private boolean _drawBBox = false;
825         private boolean _drawBorder = false;
826
827         // private Point _positionRelativeSouris;
828         private Point _translation;
829         private boolean _horsCadre;
830         private boolean _premierAffichage;
831
832         private ControleurInterpolator _interpolator;
833         /**
834          * If comparison mode is TRUE (ON), then the application will be used to
835          * display a super-structure resulting on an RNA secondary structure
836          * comparison. Else, the application is used by default.
837          */
838
839         private VueMenu _popup = new VueMenu(this);
840
841         private VueUI _UI = new VueUI(this);
842
843         private TextAnnotation _selectedAnnotation;
844
845         /**
846          * Creates an RNA 2D panel with initially displays the empty structure.
847          * 
848          * @throws ExceptionNonEqualLength
849          * 
850          */
851         public VARNAPanel() {
852                 init();
853                 drawRNA();
854         }
855
856         /**
857          * Creates an RNA 2D panel, and creates and displays an RNA coupled with its
858          * secondary structure formatted as a well-balanced parenthesis with dots
859          * word (DBN format).
860          * 
861          * @param seq
862          *            The raw nucleotide sequence
863          * @param str
864          *            The secondary structure in DBN format
865          * @throws ExceptionNonEqualLength
866          */
867
868         public VARNAPanel(String seq, String str) throws ExceptionNonEqualLength {
869                 this(seq, str, RNA.DRAW_MODE_RADIATE);
870         }
871
872         /**
873          * Creates a VARNAPanel instance, and creates and displays an RNA coupled
874          * with its secondary structure formatted as a well-balanced parenthesis
875          * with dots word (DBN format). Allows the user to choose the drawing
876          * algorithm to be used.
877          * 
878          * @param seq
879          *            The raw nucleotide sequence
880          * @param str
881          *            The secondary structure in DBN format
882          * @param drawMode
883          *            The drawing mode
884          * @throws ExceptionNonEqualLength
885          * @see RNA#DRAW_MODE_RADIATE
886          * @see RNA#DRAW_MODE_CIRCULAR
887          * @see RNA#DRAW_MODE_NAVIEW
888          */
889         public VARNAPanel(String seq, String str, int drawMode)
890                         throws ExceptionNonEqualLength {
891                 this(seq, str, drawMode, "");
892         }
893
894         public VARNAPanel(Reader r) throws ExceptionNonEqualLength,
895                         ExceptionFileFormatOrSyntax {
896                 this(r, RNA.DRAW_MODE_RADIATE);
897         }
898
899         public VARNAPanel(Reader r, int drawMode) throws ExceptionNonEqualLength,
900                         ExceptionFileFormatOrSyntax {
901                 this(r, drawMode, "");
902         }
903
904         public VARNAPanel(Reader r, int drawMode, String title)
905                         throws ExceptionNonEqualLength, ExceptionFileFormatOrSyntax {
906                 init();
907                 drawRNA(r, drawMode);
908                 setTitle(title);
909         }
910
911         public void setOriginLink(Point2D.Double p) {
912                 _linkOrigin = (p);
913         }
914
915         public void setDestinationLink(Point2D.Double p) {
916                 _linkDestination = (p);
917         }
918
919         public void removeLink() {
920                 _linkOrigin = null;
921                 _linkDestination = null;
922         }
923
924         /**
925          * Creates a VARNAPanel instance, and displays an RNA.
926          * 
927          * @param r
928          *            The RNA to be displayed within this panel
929          */
930
931         public VARNAPanel(RNA r) {
932                 showRNA(r);
933                 init();
934         }
935
936         /**
937          * Creates a VARNAPanel instance, and creates and displays an RNA coupled
938          * with its secondary structure formatted as a well-balanced parenthesis
939          * with dots word (DBN format). Allows the user to choose the drawing
940          * algorithm to be used. Additionally, sets the panel's title.
941          * 
942          * @param seq
943          *            The raw nucleotide sequence
944          * @param str
945          *            The secondary structure in DBN format
946          * @param drawMode
947          *            The drawing mode
948          * @param title
949          *            The panel title
950          * @throws ExceptionNonEqualLength
951          * @see RNA#DRAW_MODE_CIRCULAR
952          * @see RNA#DRAW_MODE_RADIATE
953          * @see RNA#DRAW_MODE_NAVIEW
954          */
955
956         public VARNAPanel(String seq, String str, int drawMode, String title)
957                         throws ExceptionNonEqualLength {
958                 drawRNA(seq, str, drawMode);
959                 init();
960                 setTitle(title);
961                 // VARNASecDraw._vp = this;
962         }
963
964         public VARNAPanel(String seq1, String struct1, String seq2, String struct2,
965                         int drawMode, String title) {
966                 _conf._comparisonMode = true;
967                 drawRNA(seq1, struct1, seq2, struct2, drawMode);
968                 init();
969                 setTitle(title);
970         }
971
972         private void init() {
973                 setBackground(VARNAConfig.DEFAULT_BACKGROUND_COLOR);
974                 _manager = new UndoManager();
975                 _manager.setLimit(10000);
976                 _UI.addUndoableEditListener(_manager);
977
978                 _blink = new ControleurBlinkingThread(this,
979                                 ControleurBlinkingThread.DEFAULT_FREQUENCY, 0, 1.0, 0.0, 0.2);
980                 _blink.start();
981
982                 _premierAffichage = true;
983                 _translation = new Point(0, 0);
984
985                 _horsCadre = false;
986                 this.setFont(_conf._fontBasesGeneral);
987
988                 // ajout des controleurs au VARNAPanel
989                 ControleurClicMovement controleurClicMovement = new ControleurClicMovement(
990                                 this);
991                 this.addMouseListener(controleurClicMovement);
992                 this.addMouseMotionListener(controleurClicMovement);
993                 this.addMouseWheelListener(new ControleurMolette(this));
994
995                 ControleurDraggedMolette ctrlDraggedMolette = new ControleurDraggedMolette(
996                                 this);
997                 this.addMouseMotionListener(ctrlDraggedMolette);
998                 this.addMouseListener(ctrlDraggedMolette);
999
1000                 ControleurVARNAPanelKeys ctrlKey = new ControleurVARNAPanelKeys(this);
1001                 this.addKeyListener(ctrlKey);
1002                 this.addFocusListener(ctrlKey);
1003
1004                 _interpolator = new ControleurInterpolator(this);
1005                 /**
1006                  * 
1007                  * BH SwingJS do not start this thread
1008                  * 
1009                  * @j2sNative 
1010                  */
1011                 {
1012                 _interpolator.start();
1013                 }
1014
1015         }
1016
1017         public void undo() {
1018                 if (_manager.canUndo())
1019                         _manager.undo();
1020         }
1021
1022         public void redo() {
1023                 if (_manager.canRedo())
1024                         _manager.redo();
1025         }
1026
1027         /**
1028          * Sets the new style of the title font.
1029          * 
1030          * @param newStyle
1031          *            An int that describes the new font style ("PLAIN","BOLD",
1032          *            "BOLDITALIC", or "ITALIC")
1033          */
1034         public void setTitleFontStyle(int newStyle) {
1035                 _conf._titleFont = _conf._titleFont.deriveFont(newStyle);
1036                 updateTitleHeight();
1037         }
1038
1039         /**
1040          * Sets the new size of the title font.
1041          * 
1042          * @param newSize
1043          *            The new size of the title font
1044          */
1045         public void setTitleFontSize(float newSize) {
1046                 //System.err.println("Applying title size "+newSize);
1047                 _conf._titleFont = _conf._titleFont.deriveFont(newSize);
1048                 updateTitleHeight();
1049         }
1050
1051         /**
1052          * Sets the new font family to be used for the title. Available fonts are
1053          * system-specific, yet it seems that "Arial", "Dialog", and "MonoSpaced"
1054          * are almost always available.
1055          * 
1056          * @param newFamily
1057          *            New font family used for the title
1058          */
1059         public void setTitleFontFamily(String newFamily) {
1060                 _conf._titleFont = new Font(newFamily, _conf._titleFont.getStyle(),
1061                                 _conf._titleFont.getSize());
1062                 updateTitleHeight();
1063         }
1064
1065         /**
1066          * Sets the color to be used for the title.
1067          * 
1068          * @param newColor
1069          *            A color used to draw the title
1070          */
1071         public void setTitleFontColor(Color newColor) {
1072                 _conf._titleColor = newColor;
1073                 updateTitleHeight();
1074         }
1075
1076         /**
1077          * Sets the font size for displaying bases
1078          * 
1079          * @param size
1080          *            Font size for base caption
1081          */
1082
1083         public void setBaseFontSize(Float size) {
1084                 _conf._fontBasesGeneral = _conf._fontBasesGeneral.deriveFont(size);
1085         }
1086
1087         /**
1088          * Sets the font size for displaying base numbers
1089          * 
1090          * @param size
1091          *            Font size for base numbers
1092          */
1093
1094         public void setNumbersFontSize(Float size) {
1095                 _conf._numbersFont = _conf._numbersFont.deriveFont(size);
1096         }
1097
1098         /**
1099          * Sets the font style for displaying bases
1100          * 
1101          * @param style
1102          *            An int that describes the new font style ("PLAIN","BOLD",
1103          *            "BOLDITALIC", or "ITALIC")
1104          */
1105
1106         public void setBaseFontStyle(int style) {
1107                 _conf._fontBasesGeneral = _conf._fontBasesGeneral.deriveFont(style);
1108         }
1109
1110         private void updateTitleHeight() {
1111                 if (!getTitle().equals("")) {
1112                         _titleHeight = (int) (_conf._titleFont.getSize() * 1.5);
1113                 } else {
1114                         _titleHeight = 0;
1115                 }
1116                 if (Math.abs(this.getZoom() - 1) < .02) {
1117                         _translation.y = (int) (-getTitleHeight() / 2.0);
1118                 }
1119         }
1120
1121         /**
1122          * Sets the panel's title, giving a short description of the RNA secondary
1123          * structure.
1124          * 
1125          * @param title
1126          *            The new title
1127          */
1128         public void setTitle(String title) {
1129                 _RNA.setName(title);
1130                 updateTitleHeight();
1131         }
1132
1133         /**
1134          * Sets the distance between consecutive base numbers. Please notice that :
1135          * <ul>
1136          * <li>The first and last base are always numbered</li>
1137          * <li>The numbering is based on the base numbers, not on the indices. So
1138          * base numbers may appear more frequently than expected if bases are
1139          * skipped</li>
1140          * <li>The periodicity is measured starting from 0. This means that for a
1141          * period of 10 and bases numbered from 1 to 52, the base numbers
1142          * [1,10,20,30,40,50,52] will be drawn.</li>
1143          * </ul>
1144          * 
1145          * @param n
1146          *            New numbering period
1147          */
1148         public void setNumPeriod(int n) {
1149                 _conf._numPeriod = n;
1150         }
1151
1152         /**
1153          * Returns the current numbering period. Please notice that :
1154          * <ul>
1155          * <li>The first and last base are always numbered</li>
1156          * <li>The numbering is based on the base numbers, not on the indices. So
1157          * base numbers may appear more frequently than expected if bases are
1158          * skipped</li>
1159          * <li>The periodicity is measured starting from 0. This means that for a
1160          * period of 10 and bases numbered from 1 to 52, the base numbers
1161          * [1,10,20,30,40,50,52] will be drawn.</li>
1162          * </ul>
1163          * 
1164          * @return Current numbering period
1165          */
1166         public int getNumPeriod() {
1167                 return _conf._numPeriod;
1168         }
1169
1170         private void setScaleFactor(double d) {
1171                 _scaleFactor = d;
1172         }
1173
1174         private double getScaleFactor() {
1175                 return _scaleFactor;
1176         }
1177
1178         private void setAutoFit(boolean fit) {
1179                 _conf._autoFit = fit;
1180                 repaint();
1181         }
1182
1183         public void lockScrolling() {
1184                 setAutoFit(false);
1185                 setAutoCenter(false);
1186         }
1187
1188         public void unlockScrolling() {
1189                 setAutoFit(true);
1190                 setAutoCenter(true);
1191         }
1192
1193         private void drawStringOutline(VueVARNAGraphics g2D, String res, double x,
1194                         double y, double margin) {
1195                 Dimension d = g2D.getStringDimension(res);
1196                 x -= (double) d.width / 2.0;
1197                 y += (double) d.height / 2.0;
1198                 g2D.setColor(Color.GRAY);
1199                 g2D.setSelectionStroke();
1200                 g2D.drawRect((x - margin), (y - d.height - margin),
1201                                 (d.width + 2.0 * margin), (d.height + 2.0 * margin));
1202         }
1203
1204         private void drawSymbol(VueVARNAGraphics g2D, double posx, double posy,
1205                         double normx, double normy, double radius, boolean isCIS,
1206                         ModeleBP.Edge e) {
1207                 Color bck = g2D.getColor();
1208                 switch (e) {
1209                 case WC:
1210                         if (isCIS) {
1211                                 g2D.setColor(bck);
1212                                 g2D.fillCircle((posx - (radius) / 2.0),
1213                                                 (posy - (radius) / 2.0), radius);
1214                                 g2D.drawCircle((posx - (radius) / 2.0),
1215                                                 (posy - (radius) / 2.0), radius);
1216                         } else {
1217                                 g2D.setColor(Color.white);
1218                                 g2D.fillCircle(posx - (radius) / 2.0, (posy - (radius) / 2.0),
1219                                                 (radius));
1220                                 g2D.setColor(bck);
1221                                 g2D.drawCircle((posx - (radius) / 2.0),
1222                                                 (posy - (radius) / 2.0), (radius));
1223                         }
1224                         break;
1225                 case HOOGSTEEN: {
1226                         GeneralPath p2 = new GeneralPath();
1227                         radius /= 1.05;
1228                         p2.moveTo((float) (posx - radius * normx / 2.0 - radius * normy
1229                                         / 2.0), (float) (posy - radius * normy / 2.0 + radius
1230                                         * normx / 2.0));
1231                         p2.lineTo((float) (posx + radius * normx / 2.0 - radius * normy
1232                                         / 2.0), (float) (posy + radius * normy / 2.0 + radius
1233                                         * normx / 2.0));
1234                         p2.lineTo((float) (posx + radius * normx / 2.0 + radius * normy
1235                                         / 2.0), (float) (posy + radius * normy / 2.0 - radius
1236                                         * normx / 2.0));
1237                         p2.lineTo((float) (posx - radius * normx / 2.0 + radius * normy
1238                                         / 2.0), (float) (posy - radius * normy / 2.0 - radius
1239                                         * normx / 2.0));
1240                         p2.closePath();
1241
1242                         if (isCIS) {
1243                                 g2D.setColor(bck);
1244                                 g2D.fill(p2);
1245                                 g2D.draw(p2);
1246                         } else {
1247                                 g2D.setColor(Color.white);
1248                                 g2D.fill(p2);
1249                                 g2D.setColor(bck);
1250                                 g2D.draw(p2);
1251                         }
1252                 }
1253                         break;
1254                 case SUGAR: {
1255                         double ix = radius * normx / 2.0;
1256                         double iy = radius * normy / 2.0;
1257                         double jx = radius * normy / 2.0;
1258                         double jy = -radius * normx / 2.0;
1259
1260                         GeneralPath p2 = new GeneralPath();
1261                         p2.moveTo((float) (posx - ix + jx), (float) (posy - iy + jy));
1262                         p2.lineTo((float) (posx + ix + jx), (float) (posy + iy + jy));
1263                         p2.lineTo((float) (posx - jx), (float) (posy - jy));
1264                         p2.closePath();
1265
1266                         if (isCIS) {
1267                                 g2D.setColor(bck);
1268                                 g2D.fill(p2);
1269                                 g2D.draw(p2);
1270                         } else {
1271                                 g2D.setColor(Color.white);
1272                                 g2D.fill(p2);
1273                                 g2D.setColor(bck);
1274                                 g2D.draw(p2);
1275                         }
1276                 }
1277                         break;
1278                 }
1279                 g2D.setColor(bck);
1280         }
1281
1282         private void drawBasePairArc(VueVARNAGraphics g2D, int i, int j,
1283                         Point2D.Double orig, Point2D.Double dest, double scaleFactor,
1284                         ModeleBP style, double newRadius) {
1285                 double distance, coef;
1286                 if (j - i == 1)
1287                         coef = getBPHeightIncrement() * 1.75;
1288                 else
1289                         coef = getBPHeightIncrement();
1290                 distance = dest.x - orig.x;
1291                 switch (_conf._mainBPStyle) {
1292                 case LW: {
1293                         double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS) / 5.0)
1294                                         * scaleFactor;
1295                         if (style.isCanonical()) {
1296                                 if (style.isCanonicalGC()) {
1297                                         if ((orig.x != dest.x) || (orig.y != dest.y)) {
1298                                                 g2D.drawArc((dest.x + orig.x) / 2., dest.y
1299                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1300                                                                 (distance - scaleFactor * _RNA.BASE_RADIUS
1301                                                                                 / 3.0), (distance * coef - scaleFactor
1302                                                                                 * _RNA.BASE_RADIUS / 3.0), 0, 180);
1303                                                 g2D.drawArc((dest.x + orig.x) / 2., dest.y
1304                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1305                                                                 (distance + scaleFactor * _RNA.BASE_RADIUS
1306                                                                                 / 3.0), (distance * coef + scaleFactor
1307                                                                                 * _RNA.BASE_RADIUS / 3.0), 0, 180);
1308                                         }
1309                                 } else if (style.isCanonicalAU()) {
1310                                         g2D.drawArc((dest.x + orig.x) / 2., dest.y - scaleFactor
1311                                                         * _RNA.BASE_RADIUS / 2.0, (distance),
1312                                                         (distance * coef), 0, 180);
1313                                 } else if (style.isWobbleUG()) {
1314                                         Point2D.Double midtop = new Point2D.Double(
1315                                                         (dest.x + orig.x) / 2., dest.y - distance * coef
1316                                                                         / 2. - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1317                                         g2D.drawArc(midtop.x, dest.y - scaleFactor
1318                                                         * _RNA.BASE_RADIUS / 2.0, (distance),
1319                                                         (distance * coef), 0, 180);
1320                                         drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle,
1321                                                         false, ModeleBP.Edge.WC);
1322                                 } else {
1323                                         Point2D.Double midtop = new Point2D.Double(
1324                                                         (dest.x + orig.x) / 2., dest.y - distance * coef
1325                                                                         / 2. - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1326                                         g2D.drawArc(midtop.x, dest.y - scaleFactor
1327                                                         * _RNA.BASE_RADIUS / 2.0, (distance),
1328                                                         (distance * coef), 0, 180);
1329                                         drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle,
1330                                                         style.isCIS(), style.getEdgePartner5());
1331                                 }
1332                         } else {
1333                                 ModeleBP.Edge p1 = style.getEdgePartner5();
1334                                 ModeleBP.Edge p2 = style.getEdgePartner3();
1335                                 Point2D.Double midtop = new Point2D.Double(
1336                                                 (dest.x + orig.x) / 2., dest.y - distance * coef / 2.
1337                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1338                                 g2D.drawArc(midtop.x, dest.y - scaleFactor * _RNA.BASE_RADIUS
1339                                                 / 2.0, (distance), (distance * coef), 0, 180);
1340                                 if (p1 == p2) {
1341                                         drawSymbol(g2D, midtop.x, midtop.y, 1., 0., radiusCircle,
1342                                                         false, style.getEdgePartner5());
1343                                 } else {
1344                                         drawSymbol(g2D, midtop.x - scaleFactor * _RNA.BASE_RADIUS,
1345                                                         midtop.y, 1., 0., radiusCircle, style.isCIS(), p1);
1346                                         drawSymbol(g2D, midtop.x + scaleFactor * _RNA.BASE_RADIUS,
1347                                                         midtop.y, -1., 0., radiusCircle, style.isCIS(), p2);
1348                                 }
1349                         }
1350                 }
1351                         break;
1352                 case LW_ALT: {
1353                         double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS) / 5.0)
1354                                         * scaleFactor;
1355                         double distFromBaseCenter = DISTANCE_FACT*scaleFactor;
1356                         orig = new Point2D.Double(orig.x,orig.y-(distFromBaseCenter+newRadius));
1357                         dest = new Point2D.Double(dest.x,dest.y-(distFromBaseCenter+newRadius));
1358                         if (style.isCanonical()) {
1359                                 if (style.isCanonicalGC()) {
1360                                         if ((orig.x != dest.x) || (orig.y != dest.y)) {
1361                                                 g2D.drawArc((dest.x + orig.x) / 2., dest.y
1362                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1363                                                                 (distance - scaleFactor * _RNA.BASE_RADIUS
1364                                                                                 / 3.0), (distance * coef - scaleFactor
1365                                                                                 * _RNA.BASE_RADIUS / 3.0), 0, 180);
1366                                                 g2D.drawArc((dest.x + orig.x) / 2., dest.y
1367                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0,
1368                                                                 (distance + scaleFactor * _RNA.BASE_RADIUS
1369                                                                                 / 3.0), (distance * coef + scaleFactor
1370                                                                                 * _RNA.BASE_RADIUS / 3.0), 0, 180);
1371                                         }
1372                                 } else if (style.isCanonicalAU()) {
1373                                         g2D.drawArc((dest.x + orig.x) / 2., dest.y - scaleFactor
1374                                                         * _RNA.BASE_RADIUS / 2.0, (distance),
1375                                                         (distance * coef), 0, 180);
1376                                 }
1377                         } else {
1378                                 ModeleBP.Edge p1 = style.getEdgePartner5();
1379                                 ModeleBP.Edge p2 = style.getEdgePartner3();
1380                                 Point2D.Double midtop = new Point2D.Double(
1381                                                 (dest.x + orig.x) / 2., dest.y - distance * coef / 2.
1382                                                                 - scaleFactor * _RNA.BASE_RADIUS / 2.0);
1383                                 g2D.drawArc(midtop.x, dest.y - scaleFactor * _RNA.BASE_RADIUS
1384                                                 / 2.0, (distance), (distance * coef), 0, 180);
1385                                 drawSymbol(g2D, orig.x,
1386                                                         orig.y-radiusCircle*.95, 1., 0., radiusCircle, style.isCIS(), p1);
1387                                 drawSymbol(g2D, dest.x,
1388                                                         dest.y-radiusCircle*.95, -1., 0., radiusCircle, style.isCIS(), p2);
1389                         }
1390                 }
1391                         break;
1392                 default:
1393                         g2D.drawArc((dest.x + orig.x) / 2., dest.y - scaleFactor
1394                                         * _RNA.BASE_RADIUS / 2.0, (distance), (distance * coef), 0,
1395                                         180);
1396                         break;
1397                 }
1398
1399         }
1400
1401         public static double DISTANCE_FACT = 2.;
1402
1403         
1404         private void drawBasePair(VueVARNAGraphics g2D, Point2D.Double orig,
1405                         Point2D.Double dest, ModeleBP style, double newRadius,
1406                         double scaleFactor) {
1407
1408                 double dx = dest.x - orig.x;
1409                 double dy = dest.y - orig.y;
1410                 double dist = Math.sqrt((dest.x - orig.x) * (dest.x - orig.x)
1411                                 + (dest.y - orig.y) * (dest.y - orig.y));
1412                 dx /= dist;
1413                 dy /= dist;
1414                 double nx = -dy;
1415                 double ny = dx;
1416                 orig = new Point2D.Double(orig.x + newRadius * dx, orig.y + newRadius
1417                                 * dy);
1418                 dest = new Point2D.Double(dest.x - newRadius * dx, dest.y - newRadius
1419                                 * dy);
1420                 switch (_conf._mainBPStyle) {
1421                 case LW: {
1422                         double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS) / 5.0)
1423                                         * scaleFactor;
1424                         if (style.isCanonical()) {
1425                                 if (style.isCanonicalGC()) {
1426                                         if ((orig.x != dest.x) || (orig.y != dest.y)) {
1427                                                 nx *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1428                                                 ny *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1429                                                 g2D.drawLine((orig.x + nx), (orig.y + ny),
1430                                                                 (dest.x + nx), (dest.y + ny));
1431                                                 g2D.drawLine((orig.x - nx), (orig.y - ny),
1432                                                                 (dest.x - nx), (dest.y - ny));
1433                                         }
1434                                 } else if (style.isCanonicalAU()) {
1435                                         g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1436                                 } else if (style.isWobbleUG()) {
1437                                         double cx = (dest.x + orig.x) / 2.0;
1438                                         double cy = (dest.y + orig.y) / 2.0;
1439                                         g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1440                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, false,
1441                                                         ModeleBP.Edge.WC);
1442                                 } else {
1443                                         double cx = (dest.x + orig.x) / 2.0;
1444                                         double cy = (dest.y + orig.y) / 2.0;
1445                                         g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1446                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle,
1447                                                         style.isCIS(), style.getEdgePartner5());
1448                                 }
1449                         } else {
1450                                 ModeleBP.Edge p1 = style.getEdgePartner5();
1451                                 ModeleBP.Edge p2 = style.getEdgePartner3();
1452                                 double cx = (dest.x + orig.x) / 2.0;
1453                                 double cy = (dest.y + orig.y) / 2.0;
1454                                 g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1455                                 if (p1 == p2) {
1456                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle,
1457                                                         style.isCIS(), p1);
1458
1459                                 } else {
1460                                         double vdx = (dest.x - orig.x);
1461                                         double vdy = (dest.y - orig.y);
1462                                         vdx /= 6.0;
1463                                         vdy /= 6.0;
1464                                         drawSymbol(g2D, cx + vdx, cy + vdy, -nx, -ny, radiusCircle,
1465                                                         style.isCIS(), p2);
1466                                         drawSymbol(g2D, cx - vdx, cy - vdy, nx, ny, radiusCircle,
1467                                                         style.isCIS(), p1);
1468                                 }
1469                         }
1470                 }
1471                         break;
1472                 case LW_ALT: {
1473                         double radiusCircle = ((RNA.BASE_PAIR_DISTANCE - _RNA.BASE_RADIUS) / 5.0)
1474                                         * scaleFactor;
1475                         double distFromBaseCenter = DISTANCE_FACT*scaleFactor;
1476                         Point2D.Double norig = new Point2D.Double(orig.x+(distFromBaseCenter+.5*newRadius)*dx,orig.y+(distFromBaseCenter+.5*newRadius)*dy);
1477                         Point2D.Double ndest = new Point2D.Double(dest.x-(distFromBaseCenter+.5*newRadius)*dx,dest.y-(distFromBaseCenter+.5*newRadius)*dy);
1478                         if (style.isCanonical()) {
1479                                 if (style.isCanonicalGC()) {
1480                                         if ((norig.x != ndest.x) || (norig.y != ndest.y)) {
1481                                                 nx *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1482                                                 ny *= scaleFactor * _RNA.BASE_RADIUS / 4.0;
1483                                                 g2D.drawLine((norig.x + nx), (norig.y + ny),
1484                                                                 (ndest.x + nx), (ndest.y + ny));
1485                                                 g2D.drawLine((norig.x - nx), (norig.y - ny),
1486                                                                 (ndest.x - nx), (ndest.y - ny));
1487                                         }
1488                                 } else if (style.isCanonicalAU()) {
1489                                         g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1490                                 } else if (style.isWobbleUG()) {
1491                                         double cx = (ndest.x + norig.x) / 2.0;
1492                                         double cy = (ndest.y + norig.y) / 2.0;
1493                                         g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1494                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle, false,
1495                                                         ModeleBP.Edge.WC);
1496                                 } else {
1497                                         double cx = (ndest.x + norig.x) / 2.0;
1498                                         double cy = (ndest.y + norig.y) / 2.0;
1499                                         g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1500                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle,
1501                                                         style.isCIS(), style.getEdgePartner5());
1502                                 }
1503                         } else {
1504                                 ModeleBP.Edge p1 = style.getEdgePartner5();
1505                                 ModeleBP.Edge p2 = style.getEdgePartner3();
1506                                 double cx = (ndest.x + norig.x) / 2.0;
1507                                 double cy = (ndest.y + norig.y) / 2.0;
1508                                 g2D.drawLine(norig.x, norig.y, ndest.x, ndest.y);
1509                                 if (p1 == p2) {
1510                                         drawSymbol(g2D, cx, cy, nx, ny, radiusCircle,
1511                                                         style.isCIS(), p1);
1512
1513                                 } else {
1514                                         double fac = .4;
1515                                         drawSymbol(g2D, ndest.x - fac*radiusCircle*dx, ndest.y - fac*radiusCircle*dy, -nx, -ny, radiusCircle,
1516                                                         style.isCIS(), p2);
1517                                         drawSymbol(g2D, norig.x + fac*radiusCircle*dx, norig.y + fac*radiusCircle*dy, nx, ny, radiusCircle,
1518                                                         style.isCIS(), p1);
1519                                 }
1520                         }
1521                 }
1522                         break;
1523                 case SIMPLE:
1524                         g2D.drawLine(orig.x, orig.y, dest.x, dest.y);
1525                         break;
1526                 case RNAVIZ:
1527                         double xcenter = (orig.x + dest.x) / 2.0;
1528                         double ycenter = (orig.y + dest.y) / 2.0;
1529                         double radius = Math.max(4.0 * scaleFactor, 1.0);
1530                         g2D.fillCircle((xcenter - radius), (ycenter - radius),
1531                                         (2.0 * radius));
1532                         break;
1533                 case NONE:
1534                         break;
1535                 }
1536         }
1537
1538         private Color getHighlightedVersion(Color c1, Color c2) {
1539                 int r1 = c1.getRed();
1540                 int g1 = c1.getGreen();
1541                 int b1 = c1.getBlue();
1542                 int r2 = c2.getRed();
1543                 int g2 = c2.getGreen();
1544                 int b2 = c2.getBlue();
1545                 double val = _blink.getVal();
1546                 int nr = Math.max(0,
1547                                 Math.min((int) ((r1 * val + r2 * (1.0 - val))), 255));
1548                 int ng = Math.max(0,
1549                                 Math.min((int) ((g1 * val + g2 * (1.0 - val))), 255));
1550                 int nb = Math.max(0,
1551                                 Math.min((int) ((b1 * val + b2 * (1.0 - val))), 255));
1552                 return new Color(nr, ng, nb);
1553         }
1554
1555         private Color highlightFilter(int index, Color initialColor, Color c1,
1556                         Color c2, boolean localView) {
1557                 if (_selectedBases.contains(_RNA.getBaseAt(index)) && localView) {
1558                         return getHighlightedVersion(c1, c2);
1559                 } else
1560                         return initialColor;
1561         }
1562
1563         public static Point2D.Double computeExcentricUnitVector(int i,
1564                         Point2D.Double[] points, Point2D.Double[] centers) {
1565                 double dist = points[i].distance(centers[i]);
1566                 Point2D.Double byCenter = new Point2D.Double(
1567                                 (points[i].x - centers[i].x) / dist,
1568                                 (points[i].y - centers[i].y) / dist);
1569                 if ((i > 0) && (i < points.length - 1)) {
1570                         Point2D.Double p0 = points[i - 1];
1571                         Point2D.Double p1 = points[i];
1572                         Point2D.Double p2 = points[i + 1];
1573                         double dist1 = p2.distance(p1);
1574                         Point2D.Double v1 = new Point2D.Double((p2.x - p1.x) / dist1,
1575                                         (p2.y - p1.y) / dist1);
1576                         Point2D.Double vn1 = new Point2D.Double(v1.y, -v1.x);
1577                         double dist2 = p1.distance(p0);
1578                         Point2D.Double v2 = new Point2D.Double((p1.x - p0.x) / dist2,
1579                                         (p1.y - p0.y) / dist2);
1580                         Point2D.Double vn2 = new Point2D.Double(v2.y, -v2.x);
1581                         Point2D.Double vn = new Point2D.Double((vn1.x + vn2.x) / 2.0,
1582                                         (vn1.y + vn2.y) / 2.0);
1583                         double D = vn.distance(new Point2D.Double(0.0, 0.0));
1584                         vn.x /= D;
1585                         vn.y /= D;
1586                         if (byCenter.x * vn.x + byCenter.y * vn.y < 0) {
1587                                 vn.x = -vn.x;
1588                                 vn.y = -vn.y;
1589                         }
1590                         return vn;
1591                 } 
1592                 else if (((i==0) || (i==points.length-1)) && (points.length>1)) {
1593                         int a = (i==0)?0:points.length-1;
1594                         int b = (i==0)?1:points.length-2;
1595                         double D = points[a].distance(points[b]);
1596                         return new Point2D.Double(
1597                                         (points[a].x - points[b].x) / D,
1598                                         (points[a].y - points[b].y) / D);
1599                 }
1600                 else {
1601                         return byCenter;
1602                 }
1603         }
1604
1605         private void drawBase(VueVARNAGraphics g2D, int i, Point2D.Double[] points,
1606                         Point2D.Double[] centers, double newRadius, double _scaleFactor,
1607                         boolean localView) {
1608                 Point2D.Double p = points[i];
1609                 ModeleBase mb = _RNA.get_listeBases().get(i);
1610                 g2D.setFont(_conf._fontBasesGeneral);
1611                 Color baseInnerColor = highlightFilter(i,
1612                                 _RNA.getBaseInnerColor(i, _conf), Color.white,
1613                                 _RNA.getBaseInnerColor(i, _conf), localView);
1614                 Color baseOuterColor = highlightFilter(i,
1615                                 _RNA.getBaseOuterColor(i, _conf),
1616                                 _RNA.getBaseOuterColor(i, _conf), Color.white, localView);
1617                 Color baseNameColor = highlightFilter(i,
1618                                 _RNA.getBaseNameColor(i, _conf),
1619                                 _RNA.getBaseNameColor(i, _conf), Color.white, localView);
1620                 if ( RNA.whiteLabelPreferrable(baseInnerColor))
1621                 {
1622                         baseNameColor=Color.white;
1623                 }
1624
1625                 if (mb instanceof ModeleBaseNucleotide) {
1626                         ModeleBaseNucleotide mbn = (ModeleBaseNucleotide) mb;
1627                         String res = mbn.getBase();
1628                         if (_hoveredBase == mb && localView && isModifiable()) {
1629                                 g2D.setColor(_conf._hoverColor);
1630                                 g2D.fillCircle(p.getX() - 1.5 * newRadius, p.getY() - 1.5
1631                                                 * newRadius, 3.0 * newRadius);
1632                                 g2D.setColor(_conf._hoverColor.darker());
1633                                 g2D.drawCircle(p.getX() - 1.5 * newRadius, p.getY() - 1.5
1634                                                 * newRadius, 3.0 * newRadius);
1635                                 g2D.setPlainStroke();
1636                         }
1637                         if (_conf._fillBases) {
1638                                 // Filling inner circle
1639                                 g2D.setColor(baseInnerColor);
1640                                 g2D.fillCircle(p.getX() - newRadius, p.getY() - newRadius,
1641                                                 2.0 * newRadius);
1642                         }
1643
1644                         if (_conf._drawOutlineBases) {
1645                                 // Drawing outline
1646                                 g2D.setColor(baseOuterColor);
1647                                 g2D.setStrokeThickness(_conf._baseThickness * _scaleFactor);
1648                                 g2D.drawCircle(p.getX() - newRadius, p.getY() - newRadius,
1649                                                 2.0 * newRadius);
1650                         }
1651                         // Drawing label
1652                         g2D.setColor(baseNameColor);
1653                         g2D.drawStringCentered(String.valueOf(res), p.getX(), p.getY());
1654                 } else if (mb instanceof ModeleBasesComparison) {
1655
1656                         ModeleBasesComparison mbc = (ModeleBasesComparison) mb;
1657
1658                         // On lui donne l'aspect voulue (on a un trait droit)
1659                         g2D.setPlainStroke(); // On doit avoir un trait droit, sans arrondit
1660                         g2D.setStrokeThickness(_conf._baseThickness * _scaleFactor);
1661
1662                         // On dessine l'étiquette, rectangle aux bords arrondies.
1663                         g2D.setColor(baseInnerColor);
1664                         g2D.fillRoundRect((p.getX() - 1.5 * newRadius),
1665                                         (p.getY() - newRadius), (3.0 * newRadius),
1666                                         (2.0 * newRadius), 10 * _scaleFactor, 10 * _scaleFactor);
1667
1668                         /* Dessin du rectangle exterieur (bords) */
1669                         g2D.setColor(baseOuterColor);
1670                         g2D.drawRoundRect((p.getX() - 1.5 * newRadius),
1671                                         (p.getY() - newRadius), (3 * newRadius), (2 * newRadius),
1672                                         10 * _scaleFactor, 10 * _scaleFactor);
1673
1674                         // On le dessine au centre de l'étiquette.
1675                         g2D.drawLine((p.getX()), (p.getY() + newRadius) - 1, (p.getX()),
1676                                         (p.getY() - newRadius) + 1);
1677
1678                         /* Dessin du nom de la base (A,C,G,U,etc...) */
1679                         // On créer le texte des étiquettes
1680                         String label1 = String.valueOf(mbc.getBase1());
1681                         String label2 = String.valueOf(mbc.getBase2());
1682
1683                         // On leur donne une couleur
1684                         g2D.setColor(getRNA().get_listeBases().get(i).getStyleBase()
1685                                         .getBaseNameColor());
1686
1687                         // Et on les dessine.
1688                         g2D.drawStringCentered(label1, p.getX() - (.75 * newRadius),
1689                                         p.getY());
1690                         g2D.drawStringCentered(label2, p.getX() + (.75 * newRadius),
1691                                         p.getY());
1692                 }
1693
1694                 // Drawing base number
1695                 if (_RNA.isNumberDrawn(mb, getNumPeriod())) {
1696
1697                         Point2D.Double vn = computeExcentricUnitVector(i, points, centers);
1698                         g2D.setColor(mb.getStyleBase().getBaseNumberColor());
1699                         g2D.setFont(_conf._numbersFont);
1700                         double factorMin = Math.min(.5, _conf._distNumbers);
1701                         double factorMax = Math.min(_conf._distNumbers - 1.5,
1702                                         _conf._distNumbers);
1703                         g2D.drawLine(p.x + vn.x * ((1 + factorMin) * newRadius), p.y + vn.y
1704                                         * ((1 + factorMin) * newRadius), p.x + vn.x
1705                                         * ((1 + factorMax) * newRadius), p.y + vn.y
1706                                         * ((1 + factorMax) * newRadius));
1707                         g2D.drawStringCentered(mb.getLabel(), p.x + vn.x
1708                                         * ((1 + _conf._distNumbers) * newRadius), p.y + vn.y
1709                                         * ((1 + _conf._distNumbers) * newRadius));
1710
1711                 }
1712         }
1713
1714         void drawChemProbAnnotation(VueVARNAGraphics g2D, ChemProbAnnotation cpa,
1715                         Point2D.Double anchor, double scaleFactor) {
1716                 g2D.setColor(cpa.getColor());
1717                 g2D.setStrokeThickness(RNA.CHEM_PROB_ARROW_THICKNESS * scaleFactor
1718                                 * cpa.getIntensity());
1719                 g2D.setPlainStroke();
1720                 Point2D.Double v = cpa.getDirVector();
1721                 Point2D.Double vn = cpa.getNormalVector();
1722                 Point2D.Double base = new Point2D.Double(
1723                                 (anchor.x + _RNA.CHEM_PROB_DIST * scaleFactor * v.x),
1724                                 (anchor.y + _RNA.CHEM_PROB_DIST * scaleFactor * v.y));
1725                 Point2D.Double edge = new Point2D.Double(
1726                                 (base.x + _RNA.CHEM_PROB_BASE_LENGTH * cpa.getIntensity()
1727                                                 * scaleFactor * v.x),
1728                                 (base.y + _RNA.CHEM_PROB_BASE_LENGTH * cpa.getIntensity()
1729                                                 * scaleFactor * v.y));
1730                 switch (cpa.getType()) {
1731                 case ARROW: {
1732                         Point2D.Double arrowTip1 = new Point2D.Double(
1733                                         (base.x + cpa.getIntensity()
1734                                                         * scaleFactor
1735                                                         * (_RNA.CHEM_PROB_ARROW_WIDTH * vn.x + _RNA.CHEM_PROB_ARROW_HEIGHT
1736                                                                         * v.x)),
1737                                         (base.y + cpa.getIntensity()
1738                                                         * scaleFactor
1739                                                         * (_RNA.CHEM_PROB_ARROW_WIDTH * vn.y + _RNA.CHEM_PROB_ARROW_HEIGHT
1740                                                                         * v.y)));
1741                         Point2D.Double arrowTip2 = new Point2D.Double(
1742                                         (base.x + cpa.getIntensity()
1743                                                         * scaleFactor
1744                                                         * (-_RNA.CHEM_PROB_ARROW_WIDTH * vn.x + _RNA.CHEM_PROB_ARROW_HEIGHT
1745                                                                         * v.x)),
1746                                         (base.y + cpa.getIntensity()
1747                                                         * scaleFactor
1748                                                         * (-_RNA.CHEM_PROB_ARROW_WIDTH * vn.y + _RNA.CHEM_PROB_ARROW_HEIGHT
1749                                                                         * v.y)));
1750                         g2D.drawLine(base.x, base.y, edge.x, edge.y);
1751                         g2D.drawLine(base.x, base.y, arrowTip1.x, arrowTip1.y);
1752                         g2D.drawLine(base.x, base.y, arrowTip2.x, arrowTip2.y);
1753                 }
1754                         break;
1755                 case PIN: {
1756                         Point2D.Double side1 = new Point2D.Double(
1757                                         (edge.x - cpa.getIntensity() * scaleFactor
1758                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.x)),
1759                                         (edge.y - cpa.getIntensity() * scaleFactor
1760                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.y)));
1761                         Point2D.Double side2 = new Point2D.Double(
1762                                         (edge.x - cpa.getIntensity() * scaleFactor
1763                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1764                                         (edge.y - cpa.getIntensity() * scaleFactor
1765                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1766                         Point2D.Double side3 = new Point2D.Double(
1767                                         (edge.x + cpa.getIntensity() * scaleFactor
1768                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.x)),
1769                                         (edge.y + cpa.getIntensity() * scaleFactor
1770                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * v.y)));
1771                         Point2D.Double side4 = new Point2D.Double(
1772                                         (edge.x + cpa.getIntensity() * scaleFactor
1773                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1774                                         (edge.y + cpa.getIntensity() * scaleFactor
1775                                                         * (_RNA.CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1776                         GeneralPath p2 = new GeneralPath();
1777                         p2.moveTo((float) side1.x, (float) side1.y);
1778                         p2.lineTo((float) side2.x, (float) side2.y);
1779                         p2.lineTo((float) side3.x, (float) side3.y);
1780                         p2.lineTo((float) side4.x, (float) side4.y);
1781                         p2.closePath();
1782                         g2D.fill(p2);
1783                         g2D.drawLine(base.x, base.y, edge.x, edge.y);
1784                 }
1785                         break;
1786                 case TRIANGLE: {
1787                         Point2D.Double arrowTip1 = new Point2D.Double(
1788                                         (edge.x + cpa.getIntensity() * scaleFactor
1789                                                         * (_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1790                                         (edge.y + cpa.getIntensity() * scaleFactor
1791                                                         * (_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1792                         Point2D.Double arrowTip2 = new Point2D.Double(
1793                                         (edge.x + cpa.getIntensity() * scaleFactor
1794                                                         * (-_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1795                                         (edge.y + cpa.getIntensity() * scaleFactor
1796                                                         * (-_RNA.CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1797                         GeneralPath p2 = new GeneralPath();
1798                         p2.moveTo((float) base.x, (float) base.y);
1799                         p2.lineTo((float) arrowTip1.x, (float) arrowTip1.y);
1800                         p2.lineTo((float) arrowTip2.x, (float) arrowTip2.y);
1801                         p2.closePath();
1802                         g2D.fill(p2);
1803                 }
1804                         break;
1805                 case DOT: {
1806                         Double radius = scaleFactor * _RNA.CHEM_PROB_DOT_RADIUS
1807                                         * cpa.getIntensity();
1808                         Point2D.Double center = new Point2D.Double((base.x + radius * v.x),
1809                                         (base.y + radius * v.y));
1810                         g2D.fillCircle((center.x - radius), (center.y - radius),
1811                                         (2 * radius));
1812                 }
1813                         break;
1814                 }
1815         }
1816
1817         Point2D.Double buildCaptionPosition(ModeleBase mb, double scaleFactor,
1818                         double heightEstimate) {
1819                 double radius = 2.0;
1820                 if (_RNA.isNumberDrawn(mb, getNumPeriod())) {
1821                         radius += _conf._distNumbers;
1822                 }
1823                 Point2D.Double center = mb.getCenter();
1824                 Point2D.Double p = mb.getCoords();
1825                 double realDistance = _RNA.BASE_RADIUS * radius + heightEstimate;
1826                 return new Point2D.Double(center.getX() + (p.getX() - center.getX())
1827                                 * ((p.distance(center) + realDistance) / p.distance(center)),
1828                                 center.getY()
1829                                                 + (p.getY() - center.getY())
1830                                                 * ((p.distance(center) + realDistance) / p
1831                                                                 .distance(center)));
1832         }
1833
1834         private void renderAnnotations(VueVARNAGraphics g2D, double offX,
1835                         double offY, double rnaBBoxX, double rnaBBoxY, double scaleFactor) {
1836                 for (TextAnnotation textAnnotation : _RNA.getAnnotations()) {
1837                         g2D.setColor(textAnnotation.getColor());
1838                         g2D.setFont(textAnnotation
1839                                         .getFont()
1840                                         .deriveFont(
1841                                                         (float) (2.0 * textAnnotation.getFont().getSize() * scaleFactor)));
1842                         Point2D.Double position = textAnnotation.getCenterPosition();
1843                         if (textAnnotation.getType() == TextAnnotation.AnchorType.BASE) {
1844                                 ModeleBase mb = (ModeleBase) textAnnotation.getAncrage();
1845                                 double fontHeight = Math.ceil(textAnnotation.getFont()
1846                                                 .getSize());
1847                                 position = buildCaptionPosition(mb, scaleFactor, fontHeight);
1848                         }
1849                         position = transformCoord(position, offX, offY, rnaBBoxX, rnaBBoxY,
1850                                         scaleFactor);
1851                         g2D.drawStringCentered(textAnnotation.getTexte(), position.x,
1852                                         position.y);
1853                         if ((_selectedAnnotation == textAnnotation)
1854                                         && (_highlightAnnotation)) {
1855                                 drawStringOutline(g2D, textAnnotation.getTexte(), position.x,
1856                                                 position.y, 5);
1857                         }
1858                 }
1859                 for (ChemProbAnnotation cpa : _RNA.getChemProbAnnotations()) {
1860                         Point2D.Double anchor = transformCoord(cpa.getAnchorPosition(),
1861                                         offX, offY, rnaBBoxX, rnaBBoxY, scaleFactor);
1862                         drawChemProbAnnotation(g2D, cpa, anchor, scaleFactor);
1863                 }
1864
1865         }
1866
1867         public Rectangle2D.Double getExtendedRNABBox() {
1868                 // We get the logical bounding box
1869                 Rectangle2D.Double rnabbox = _RNA.getBBox();
1870                 rnabbox.y -= _conf._distNumbers * _RNA.BASE_RADIUS;
1871                 rnabbox.height += 2.0 * _conf._distNumbers * _RNA.BASE_RADIUS;
1872                 rnabbox.x -= _conf._distNumbers * _RNA.BASE_RADIUS;
1873                 rnabbox.width += 2.0 * _conf._distNumbers * _RNA.BASE_RADIUS;
1874                 if (_RNA.hasVirtualLoops()) {
1875                         rnabbox.y -= RNA.VIRTUAL_LOOP_RADIUS;
1876                         rnabbox.height += 2.0 * RNA.VIRTUAL_LOOP_RADIUS;
1877                         rnabbox.x -= RNA.VIRTUAL_LOOP_RADIUS;
1878                         rnabbox.width += 2.0 * RNA.VIRTUAL_LOOP_RADIUS;
1879                 }
1880                 return rnabbox;
1881         }
1882
1883         public void drawBackbone(VueVARNAGraphics g2D, Point2D.Double[] newCoords,
1884                         double newRadius, double _scaleFactor) {
1885                 // Drawing backbone
1886                 if (getDrawBackbone()) {
1887                         g2D.setStrokeThickness(1.5 * _scaleFactor);
1888                         g2D.setColor(_conf._backboneColor);
1889                         
1890                         ModeleBackbone bck = _RNA.getBackbone();
1891
1892
1893                         for (int i = 1; i < _RNA.get_listeBases().size(); i++) {
1894                                 Point2D.Double p1 = newCoords[i - 1];
1895                                 Point2D.Double p2 = newCoords[i];
1896                                 double dist = p1.distance(p2);
1897                                 int a = _RNA.getBaseAt(i - 1).getElementStructure();
1898                                 int b = _RNA.getBaseAt(i).getElementStructure();
1899                                 boolean consecutivePair = (a == i) && (b == i - 1);
1900
1901                                 if ((dist > 0)) {
1902                                         Point2D.Double vbp = new Point2D.Double();
1903                                         vbp.x = (p2.x - p1.x) / dist;
1904                                         vbp.y = (p2.y - p1.y) / dist;
1905                                         
1906                                         BackboneType bt = bck.getTypeBefore(i);
1907                                         if (bt!=BackboneType.DISCONTINUOUS_TYPE)
1908                                         {
1909                                                 if (bt==BackboneType.MISSING_PART_TYPE) {
1910                                                         g2D.setSelectionStroke();
1911                                                 } else {
1912                                                         g2D.setPlainStroke();
1913                                                 }
1914                                                 g2D.setColor(bck.getColorBefore(i, _conf._backboneColor));
1915                                                 
1916                                                 if (consecutivePair
1917                                                                 && (_RNA.getDrawMode() != RNA.DRAW_MODE_LINEAR)
1918                                                                 && (_RNA.getDrawMode() != RNA.DRAW_MODE_CIRCULAR)) {
1919                                                         int dir = 0;
1920                                                         if (i + 1 < newCoords.length) {
1921                                                                 dir = (_RNA.testDirectionality(i - 1, i, i + 1) ? -1
1922                                                                                 : 1);
1923                                                         } else if (i - 2 >= 0) {
1924                                                                 dir = (_RNA.testDirectionality(i - 2, i - 1, i) ? -1
1925                                                                                 : 1);
1926                                                         }
1927                                                         Point2D.Double vn = new Point2D.Double(dir * vbp.y,
1928                                                                         -dir * vbp.x);
1929                                                         Point2D.Double centerSeg = new Point2D.Double(
1930                                                                         (p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0);
1931                                                         double distp1CenterSeq = p1.distance(centerSeg);
1932                                                         double centerDist = Math
1933                                                                         .sqrt((RNA.VIRTUAL_LOOP_RADIUS * _scaleFactor
1934                                                                                         * RNA.VIRTUAL_LOOP_RADIUS * _scaleFactor)
1935                                                                                         - distp1CenterSeq * distp1CenterSeq);
1936                                                         Point2D.Double centerLoop = new Point2D.Double(
1937                                                                         centerSeg.x + centerDist * vn.x, centerSeg.y
1938                                                                                         + centerDist * vn.y);
1939                                                         double radius = centerLoop.distance(p1);
1940                                                         double a1 = 360.
1941                                                                         * (Math.atan2(-(p1.y - centerLoop.y),
1942                                                                                         (p1.x - centerLoop.x)))
1943                                                                         / (2. * Math.PI);
1944                                                         double a2 = 360.
1945                                                                         * (Math.atan2(-(p2.y - centerLoop.y),
1946                                                                                         (p2.x - centerLoop.x)))
1947                                                                         / (2. * Math.PI);
1948                                                         double angle = (a2 - a1);
1949                                                         if (-dir * angle < 0) {
1950                                                                 angle += -dir * 360.;
1951                                                         }
1952                                                         // if (angle<0.) angle += 360.;
1953                                                         // angle = -dir*(360-dir*angle);
1954                                                         g2D.drawArc(centerLoop.x + .8 * newRadius * vn.x,
1955                                                                         centerLoop.y + .8 * newRadius * vn.y,
1956                                                                         2 * radius, 2 * radius, a1, angle);
1957                                                 } else {
1958                                                         g2D.drawLine((newCoords[i - 1].x + newRadius * vbp.x),
1959                                                                         (newCoords[i - 1].y + newRadius * vbp.y),
1960                                                                         (newCoords[i].x - newRadius * vbp.x),
1961                                                                         (newCoords[i].y - newRadius * vbp.y));
1962                                                 }
1963                                         }
1964                                 }
1965                         }
1966                 }
1967         }
1968
1969         public Point2D.Double logicToPanel(Point2D.Double logicPoint) {
1970                 return new Point2D.Double(_offX
1971                                 + (getScaleFactor() * (logicPoint.x - _offsetRNA.x)), _offY
1972                                 + (getScaleFactor() * (logicPoint.y - _offsetRNA.y)));
1973
1974         }
1975
1976         public Rectangle2D.Double renderRNA(VueVARNAGraphics g2D,
1977                         Rectangle2D.Double bbox) {
1978                 return renderRNA(g2D, bbox, false, true);
1979         }
1980
1981         private double computeScaleFactor(Rectangle2D.Double bbox,
1982                         boolean localView, boolean autoCenter) {
1983                 Rectangle2D.Double rnabbox = getExtendedRNABBox();
1984                 double scaleFactor = Math.min((double) bbox.width
1985                                 / (double) rnabbox.width, (double) bbox.height
1986                                 / (double) rnabbox.height);
1987
1988                 // Use it to get an estimate of the font size for numbers ...
1989                 float newFontSize = Math.max(1,
1990                                 (int) ((1.7 * _RNA.BASE_RADIUS) * scaleFactor));
1991                 // ... and increase bounding box accordingly
1992                 rnabbox.y -= newFontSize;
1993                 rnabbox.height += newFontSize;
1994                 if (_conf._drawColorMap) {
1995                         rnabbox.height += getColorMapHeight();
1996                 }
1997                 rnabbox.x -= newFontSize;
1998                 rnabbox.width += newFontSize;
1999
2000                 // Now, compute the final scaling factor and corresponding font size
2001                 scaleFactor = Math.min((double) bbox.width / (double) rnabbox.width,
2002                                 (double) bbox.height / (double) rnabbox.height);
2003                 if (localView) {
2004                         if (_conf._autoFit)
2005                                 setScaleFactor(scaleFactor);
2006                         scaleFactor = getScaleFactor();
2007                 }
2008                 return scaleFactor;
2009         }
2010
2011         public synchronized Rectangle2D.Double renderRNA(VueVARNAGraphics g2D,
2012                         Rectangle2D.Double bbox, boolean localView, boolean autoCenter) {
2013                 Rectangle2D.Double rnaMultiBox = new Rectangle2D.Double(0, 0, 1, 1);
2014                 double scaleFactor = computeScaleFactor(bbox, localView, autoCenter);
2015                 float newFontSize = Math.max(1,
2016                                 (int) ((1.7 * _RNA.BASE_RADIUS) * scaleFactor));
2017                 double newRadius = Math.max(1.0, (scaleFactor * _RNA.BASE_RADIUS));
2018                 setBaseFontSize(newFontSize);
2019                 setNumbersFontSize(newFontSize);
2020                 double offX = bbox.x;
2021                 double offY = bbox.y;
2022                 Rectangle2D.Double rnabbox = getExtendedRNABBox();
2023
2024                 if (_RNA.getSize() != 0) {
2025
2026                         Point2D.Double offsetRNA = new Point2D.Double(rnabbox.x, rnabbox.y);
2027
2028                         if (autoCenter) {
2029                                 offX = (bbox.x + (bbox.width - Math.round(rnabbox.width
2030                                                 * scaleFactor)) / 2.0);
2031                                 offY = (bbox.y + (bbox.height - Math.round(rnabbox.height
2032                                                 * scaleFactor)) / 2.0);
2033                                 if (localView) {
2034                                         _offX = offX;
2035                                         _offY = offY;
2036                                         _offsetPanel = new Point2D.Double(_offX, _offY);
2037                                         _offsetRNA = new Point2D.Double(rnabbox.x, rnabbox.y);
2038                                 }
2039                         }
2040
2041                         if (localView) {
2042                                 offX = _offX;
2043                                 offY = _offY;
2044                                 offsetRNA = _offsetRNA;
2045                         }
2046
2047                         // Re-scaling once and for all
2048                         Point2D.Double[] newCoords = new Point2D.Double[_RNA
2049                                         .get_listeBases().size()];
2050                         Point2D.Double[] newCenters = new Point2D.Double[_RNA
2051                                         .get_listeBases().size()];
2052                         for (int i = 0; i < _RNA.get_listeBases().size(); i++) {
2053                                 ModeleBase mb = _RNA.getBaseAt(i);
2054                                 newCoords[i] = new Point2D.Double(offX
2055                                                 + (scaleFactor * (mb.getCoords().x - offsetRNA.x)),
2056                                                 offY + (scaleFactor * (mb.getCoords().y - offsetRNA.y)));
2057
2058                                 Point2D.Double centerBck = _RNA.getCenter(i);
2059                                 // si la base est dans un angle entre une boucle et une helice
2060                                 if (_RNA.get_drawMode() == RNA.DRAW_MODE_NAVIEW
2061                                                 || _RNA.get_drawMode() == RNA.DRAW_MODE_RADIATE) {
2062                                         if ((mb.getElementStructure() != -1)
2063                                                         && i < _RNA.get_listeBases().size() - 1 && i > 1) {
2064                                                 ModeleBase b1 = _RNA.get_listeBases().get(i - 1);
2065                                                 ModeleBase b2 = _RNA.get_listeBases().get(i + 1);
2066                                                 int j1 = b1.getElementStructure();
2067                                                 int j2 = b2.getElementStructure();
2068                                                 if ((j1 == -1) ^ (j2 == -1)) {
2069                                                         // alors la position du nombre associé doit etre
2070                                                         Point2D.Double a1 = b1.getCoords();
2071                                                         Point2D.Double a2 = b2.getCoords();
2072                                                         Point2D.Double c1 = b1.getCenter();
2073                                                         Point2D.Double c2 = b2.getCenter();
2074
2075                                                         centerBck.x = mb.getCoords().x + (c1.x - a1.x)
2076                                                                         / c1.distance(a1) + (c2.x - a2.x)
2077                                                                         / c2.distance(a2);
2078                                                         centerBck.y = mb.getCoords().y + (c1.y - a1.y)
2079                                                                         / c1.distance(a1) + (c2.y - a2.y)
2080                                                                         / c2.distance(a2);
2081                                                 }
2082                                         }
2083                                 }
2084                                 newCenters[i] = new Point2D.Double(offX
2085                                                 + (scaleFactor * (centerBck.x - offsetRNA.x)), offY
2086                                                 + (scaleFactor * (centerBck.y - offsetRNA.y)));
2087                         }
2088                         // Keep track of coordinates for mouse interactions
2089                         if (localView) {
2090                                 _realCoords = newCoords;
2091                                 _realCenters = newCenters;
2092                         }
2093
2094                         g2D.setStrokeThickness(1.5 * scaleFactor);
2095                         g2D.setPlainStroke();
2096                         g2D.setFont(_conf._fontBasesGeneral);
2097
2098                         // Drawing region highlights Annotation
2099                         drawRegionHighlightsAnnotation(g2D, _realCoords, _realCenters,
2100                                         scaleFactor);
2101                         drawBackbone(g2D, newCoords, newRadius, scaleFactor);
2102
2103                         // Drawing base-pairs
2104                         // pour chaque base
2105                         for (int i = 0; i < _RNA.get_listeBases().size(); i++) {
2106                                 int j = _RNA.get_listeBases().get(i).getElementStructure();
2107                                 // si c'est une parenthese ouvrante (premiere base du
2108                                 // couple)
2109                                 if (j > i) {
2110                                         ModeleBP msbp = _RNA.get_listeBases().get(i).getStyleBP();
2111                                         // System.err.println(msbp);
2112                                         if (msbp.isCanonical() || _conf._drawnNonCanonicalBP) {
2113                                                 if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR) {
2114                                                         g2D.setStrokeThickness(_RNA.getBasePairThickness(
2115                                                                         msbp, _conf)
2116                                                                         * 2.0
2117                                                                         * scaleFactor
2118                                                                         * _conf._bpThickness);
2119                                                 } else {
2120                                                         g2D.setStrokeThickness(_RNA.getBasePairThickness(
2121                                                                         msbp, _conf) * 1.5 * scaleFactor);
2122                                                 }
2123                                                 g2D.setColor(_RNA.getBasePairColor(msbp, _conf));
2124
2125                                                 if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR) {
2126                                                         drawBasePairArc(g2D, i, j, newCoords[i],
2127                                                                         newCoords[j], scaleFactor, msbp, newRadius);
2128                                                 } else {
2129                                                         drawBasePair(g2D, newCoords[i], newCoords[j], msbp,
2130                                                                         newRadius, scaleFactor);
2131                                                 }
2132                                         }
2133                                 }
2134                         }
2135
2136                         // Liaisons additionelles (non planaires)
2137                         if (_conf._drawnNonPlanarBP) {
2138                                 ArrayList<ModeleBP> bpaux = _RNA.getStructureAux();
2139                                 for (int k = 0; k < bpaux.size(); k++) {
2140                                         ModeleBP msbp = bpaux.get(k);
2141                                         if (msbp.isCanonical() || _conf._drawnNonCanonicalBP) {
2142                                                 int i = msbp.getPartner5().getIndex();
2143                                                 int j = msbp.getPartner3().getIndex();
2144                                                 if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR) {
2145                                                         g2D.setStrokeThickness(_RNA.getBasePairThickness(
2146                                                                         msbp, _conf)
2147                                                                         * 2.5
2148                                                                         * scaleFactor
2149                                                                         * _conf._bpThickness);
2150                                                         g2D.setPlainStroke();
2151                                                 } else {
2152                                                         g2D.setStrokeThickness(_RNA.getBasePairThickness(
2153                                                                         msbp, _conf) * 1.5 * scaleFactor);
2154                                                         g2D.setPlainStroke();
2155                                                 }
2156
2157                                                 g2D.setColor(_RNA.getBasePairColor(msbp, _conf));
2158                                                 if (j > i) {
2159                                                         if (_RNA.get_drawMode() == RNA.DRAW_MODE_LINEAR) {
2160                                                                 drawBasePairArc(g2D, i, j, newCoords[i],
2161                                                                                 newCoords[j], scaleFactor, msbp, newRadius);
2162                                                         } else {
2163                                                                 drawBasePair(g2D, newCoords[i], newCoords[j],
2164                                                                                 msbp, newRadius, scaleFactor);
2165                                                         }
2166                                                 }
2167                                         }
2168                                 }
2169                         }
2170
2171                         // Drawing bases
2172                         g2D.setPlainStroke();
2173                         for (int i = 0; i < Math.min(_RNA.get_listeBases().size(),
2174                                         newCoords.length); i++) {
2175                                 drawBase(g2D, i, newCoords, newCenters, newRadius, scaleFactor,
2176                                                 localView);
2177                         }
2178
2179                         rnaMultiBox = new Rectangle2D.Double(offX, offY,
2180                                         (scaleFactor * rnabbox.width) - 1,
2181                                         (scaleFactor * rnabbox.height) - 1);
2182
2183                         if (localView) {
2184                                 // Drawing bbox
2185                                 if (_debug || _drawBBox) {
2186                                         g2D.setColor(Color.RED);
2187                                         g2D.setSelectionStroke();
2188                                         g2D.drawRect(rnaMultiBox.x, rnaMultiBox.y,
2189                                                         rnaMultiBox.width, rnaMultiBox.height);
2190                                 }
2191
2192                                 // Draw color map
2193                                 if (_conf._drawColorMap) {
2194                                         drawColorMap(g2D, scaleFactor, rnabbox);
2195                                 }
2196
2197                                 if (_debug || _drawBBox) {
2198                                         g2D.setColor(Color.GRAY);
2199                                         g2D.setSelectionStroke();
2200                                         g2D.drawRect(0, 0, getWidth() - 1, getHeight()
2201                                                         - getTitleHeight() - 1);
2202                                 }
2203                         }
2204                         // Draw annotations
2205                         renderAnnotations(g2D, offX, offY, offsetRNA.x, offsetRNA.y,
2206                                         scaleFactor);
2207                         // Draw additional debug shape
2208                         if (_RNA._debugShape != null) {
2209                                 Color c = new Color(255, 0, 0, 50);
2210                                 g2D.setColor(c);
2211                                 AffineTransform at = new AffineTransform();
2212                                 at.translate(offX - scaleFactor * rnabbox.x, offY - scaleFactor
2213                                                 * rnabbox.y);
2214                                 at.scale(scaleFactor, scaleFactor);
2215                                 Shape s = at.createTransformedShape(_RNA._debugShape);
2216                                 if (s instanceof GeneralPath) {
2217                                         g2D.fill((GeneralPath) s);
2218                                 }
2219                         }
2220                 } else {
2221                         g2D.setColor(VARNAConfig.DEFAULT_MESSAGE_COLOR);
2222                         g2D.setFont(VARNAConfig.DEFAULT_MESSAGE_FONT);
2223                         rnaMultiBox = new Rectangle2D.Double(0,0,10,10);
2224                         g2D.drawStringCentered("No RNA here", bbox.getCenterX(),bbox.getCenterY());
2225                 }
2226                 return rnaMultiBox;
2227         }
2228
2229         public void centerViewOn(double x, double y) {
2230                 Rectangle2D.Double r = _RNA.getBBox();
2231                 _target = new Point2D.Double(x, y);
2232                 Point2D.Double q = logicToPanel(_target);
2233                 Point p = new Point((int) (-q.x), (int) (-q.y));
2234                 setTranslation(p);
2235                 repaint();
2236         }
2237
2238         Point2D.Double _target = new Point2D.Double(0, 0);
2239         Point2D.Double _target2 = new Point2D.Double(0, 0);
2240
2241         public ModeleBase getBaseAt(Point2D.Double po) {
2242                 ModeleBase mb = null;
2243                 Point2D.Double p = panelToLogicPoint(po);
2244                 double dist = Double.MAX_VALUE;
2245                 for (ModeleBase tmp : _RNA.get_listeBases()) {
2246                         double ndist = tmp.getCoords().distance(p);
2247                         if (dist > ndist) {
2248                                 mb = tmp;
2249                                 dist = ndist;
2250                         }
2251                 }
2252                 return mb;
2253         }
2254
2255         public void setColorMapValues(Double[] values) {
2256                 _RNA.setColorMapValues(values, _conf._cm, true);
2257                 _conf._drawColorMap = true;
2258                 repaint();
2259         }
2260
2261         public void setColorMapMaxValue(double d) {
2262                 _conf._cm.setMaxValue(d);
2263         }
2264
2265         public void setColorMapMinValue(double d) {
2266                 _conf._cm.setMinValue(d);
2267         }
2268
2269         public ModeleColorMap getColorMap() {
2270                 return _conf._cm;
2271         }
2272
2273         public void setColorMap(ModeleColorMap cm) {
2274                 //_RNA.adaptColorMapToValues(cm);
2275                 _conf._cm = cm;
2276                 repaint();
2277         }
2278
2279         public void setColorMapCaption(String caption) {
2280                 _conf._colorMapCaption = caption;
2281                 repaint();
2282         }
2283
2284         public String getColorMapCaption() {
2285                 return _conf._colorMapCaption;
2286         }
2287
2288         public void drawColorMap(boolean draw) {
2289                 _conf._drawColorMap = draw;
2290         }
2291
2292         private double getColorMapHeight() {
2293                 double result = VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE
2294                                 + _conf._colorMapHeight;
2295                 if (!_conf._colorMapCaption.equals(""))
2296                         result += VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE;
2297                 return result;
2298         }
2299
2300         private void drawColorMap(VueVARNAGraphics g2D, double scaleFactor,
2301                         Rectangle2D.Double rnabbox) {
2302                 double v1 = _conf._cm.getMinValue();
2303                 double v2 = _conf._cm.getMaxValue();
2304                 double x, y;
2305                 g2D.setPlainStroke();
2306
2307                 double xSpaceAvail = 0;
2308                 double ySpaceAvail = Math
2309                                 .min((getHeight() - rnabbox.height * scaleFactor - getTitleHeight()) / 2.0,
2310                                                 scaleFactor
2311                                                                 * (_conf._colorMapHeight + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE));
2312                 if ((int) ySpaceAvail == 0) {
2313                         xSpaceAvail = Math.min(
2314                                         (getWidth() - rnabbox.width * scaleFactor) / 2, scaleFactor
2315                                                         * (_conf._colorMapWidth)
2316                                                         + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH);
2317                 }
2318                 double xBase = (xSpaceAvail + _offX + scaleFactor
2319                                 * (rnabbox.width - _conf._colorMapWidth - _conf._colorMapXOffset));
2320                 double hcaption = VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE;
2321                 double yBase = (ySpaceAvail + _offY + scaleFactor
2322                                 * (rnabbox.height - _conf._colorMapHeight
2323                                                 - _conf._colorMapYOffset - hcaption));
2324
2325                 for (int i = 0; i < _conf._colorMapWidth; i++) {
2326                         double ratio = (((double) i) / ((double) _conf._colorMapWidth));
2327                         double val = v1 + (v2 - v1) * ratio;
2328                         g2D.setColor(_conf._cm.getColorForValue(val));
2329                         x = (xBase + scaleFactor * i);
2330                         y = yBase;
2331                         g2D.fillRect(x, y, scaleFactor
2332                                         * VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH,
2333                                         (scaleFactor * _conf._colorMapHeight));
2334                 }
2335                 g2D.setColor(VARNAConfig.DEFAULT_COLOR_MAP_OUTLINE);
2336                 g2D.drawRect(xBase, yBase,
2337                                 (VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH - 1 + scaleFactor
2338                                                 * _conf._colorMapWidth),
2339                                 ((scaleFactor * _conf._colorMapHeight)));
2340                 g2D.setFont(getFont()
2341                                 .deriveFont(
2342                                                 (float) (scaleFactor * VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE)));
2343                 g2D.setColor(VARNAConfig.DEFAULT_COLOR_MAP_FONT_COLOR);
2344                 NumberFormat nf = NumberFormat.getInstance();
2345                 nf.setMaximumFractionDigits(2);
2346                 nf.setMinimumFractionDigits(0);
2347                 g2D.drawStringCentered(nf.format(_conf._cm.getMinValue()), xBase, 
2348                                 yBase
2349                                 + scaleFactor * (_conf._colorMapHeight+(VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7)));
2350                 g2D.drawStringCentered(nf.format(_conf._cm.getMaxValue()), xBase
2351                                 + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH + scaleFactor
2352                                 * _conf._colorMapWidth, 
2353                                 yBase
2354                                 + scaleFactor * (_conf._colorMapHeight+(VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7)));
2355                 if (!_conf._colorMapCaption.equals(""))
2356                         g2D.drawStringCentered(
2357                                         "" + _conf._colorMapCaption,
2358                                         xBase + scaleFactor * _conf._colorMapWidth / 2.0,
2359                                         yBase
2360                                                         + scaleFactor
2361                                                         * (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7 + _conf._colorMapHeight));
2362
2363         }
2364
2365         public Point2D.Double panelToLogicPoint(Point2D.Double p) {
2366                 return new Point2D.Double(
2367                                 ((p.x - getOffsetPanel().x) / getScaleFactor())
2368                                                 + getRNAOffset().x,
2369                                 ((p.y - getOffsetPanel().y) / getScaleFactor())
2370                                                 + getRNAOffset().y);
2371         }
2372
2373         public Point2D.Double transformCoord(Point2D.Double coordDebut,
2374                         double offX, double offY, double rnaBBoxX, double rnaBBoxY,
2375                         double scaleFactor) {
2376                 return new Point2D.Double(offX
2377                                 + (scaleFactor * (coordDebut.x - rnaBBoxX)), offY
2378                                 + (scaleFactor * (coordDebut.y - rnaBBoxY)));
2379         }
2380
2381         public void eraseSequence() {
2382                 _RNA.eraseSequence();
2383         }
2384
2385         public Point2D.Double transformCoord(Point2D.Double coordDebut) {
2386                 Rectangle2D.Double rnabbox = getExtendedRNABBox();
2387                 return new Point2D.Double(_offX
2388                                 + (getScaleFactor() * (coordDebut.x - rnabbox.x)), _offY
2389                                 + (getScaleFactor() * (coordDebut.y - rnabbox.y)));
2390         }
2391
2392         public void paintComponent(Graphics g) {
2393                 paintComponent(g, false);
2394         }
2395
2396         public void paintComponent(Graphics g, boolean transparentBackground) {
2397                 if (_premierAffichage) {
2398                         // _border = new Dimension(0, 0);
2399                         _translation.x = 0;
2400                         _translation.y = (int) (-getTitleHeight() / 2.0);
2401                         _popup.buildPopupMenu();
2402                         this.add(_popup);
2403                         _premierAffichage = false;
2404                 }
2405
2406                 Graphics2D g2 = (Graphics2D) g;
2407                 Stroke dflt = g2.getStroke();
2408                 VueVARNAGraphics g2D = new SwingGraphics(g2);
2409                 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
2410                                 RenderingHints.VALUE_ANTIALIAS_ON);
2411                 this.removeAll();
2412                 super.paintComponent(g2);
2413                 renderComponent(g2D, transparentBackground, getScaleFactor());
2414                 if (isFocusOwner()) {
2415                         g2.setStroke(new BasicStroke(1.5f));
2416                         g2.setColor(Color.decode("#C0C0C0"));
2417                         g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
2418
2419                 }
2420                 g2.setStroke(dflt);
2421                 /*
2422                  * PSExport e = new PSExport(); SecStrProducerGraphics export = new
2423                  * SecStrProducerGraphics(e); renderRNA(export, getExtendedRNABBox());
2424                  * try { export.saveToDisk("./out.ps"); } catch
2425                  * (ExceptionWritingForbidden e1) { e1.printStackTrace(); }
2426                  */
2427         }
2428
2429         /**
2430          * Draws current RNA structure in a given Graphics "device".
2431          * 
2432          * @param g2D
2433          *            A graphical device
2434          * @param transparentBackground
2435          *            Whether the background should be transparent, or drawn.
2436          */
2437         public synchronized void renderComponent(VueVARNAGraphics g2D,
2438                         boolean transparentBackground, double scaleFactor) {
2439
2440                 updateTitleHeight();
2441
2442                 if (_debug || _drawBorder) {
2443                         g2D.setColor(Color.BLACK);
2444                         g2D.setPlainStroke();
2445                         g2D.drawRect(getLeftOffset(), getTopOffset(), getInnerWidth(),
2446                                         getInnerHeight());
2447
2448                 }
2449
2450                 
2451                 if (!transparentBackground) {
2452                         super.setBackground(_conf._backgroundColor);
2453                 } else {
2454                         super.setBackground(new Color(0, 0, 0, 120));
2455                 }
2456
2457                 // BH 2018 was lt, not lteq here
2458                 // SwingJS sets the minimum panel size -- probably incorrectly -- to the size for VARNAPanel
2459                 if (getMinimumSize().height <= getSize().height
2460                                 && getMinimumSize().width <= getSize().width) {
2461                         // Draw Title
2462                         if (!getTitle().equals("")) {
2463                                 g2D.setColor(_conf._titleColor);
2464                                 g2D.setFont(_conf._titleFont);
2465                                 g2D.drawStringCentered(getTitle(), this.getWidth() / 2,
2466                                                 this.getHeight() - getTitleHeight() / 2.0);
2467                         }
2468                         // Draw RNA
2469                         renderRNA(g2D, getClip(), true, _conf._autoCenter);
2470                 }
2471                 if (_selectionRectangle != null) {
2472                         g2D.setColor(Color.BLACK);
2473                         g2D.setSelectionStroke();
2474                         g2D.drawRect(_selectionRectangle.x, _selectionRectangle.y,
2475                                         _selectionRectangle.width, _selectionRectangle.height);
2476                 }
2477                 if ((_linkOrigin != null) && (_linkDestination != null)) {
2478                         g2D.setColor(_conf._bondColor);
2479                         g2D.setPlainStroke();
2480                         g2D.setStrokeThickness(3.0 * scaleFactor);
2481                         Point2D.Double linkOrigin = (_linkOrigin);
2482                         Point2D.Double linkDestination = (_linkDestination);
2483                         g2D.drawLine(linkOrigin.x, linkOrigin.y, linkDestination.x,
2484                                         linkDestination.y);
2485                         for (int i : getSelection().getIndices())
2486                                 drawBase(g2D, i, _realCoords, _realCenters, scaleFactor
2487                                                 * _RNA.BASE_RADIUS, scaleFactor, true);
2488                 }
2489
2490                 if (_debug) {
2491                         g2D.setStrokeThickness(3.0 * scaleFactor);
2492                         g2D.setColor(Color.black);
2493                         Point2D.Double t = this.logicToPanel(_target);
2494                         g2D.drawLine(t.x - 3, t.y - 3, t.x + 3, t.y + 3);
2495                         g2D.drawLine(t.x - 3, t.y + 3, t.x + 3, t.y - 3);
2496                         g2D.setColor(Color.red);
2497                         t = this.logicToPanel(_target2);
2498                         g2D.drawLine(t.x - 3, t.y - 3, t.x + 3, t.y + 3);
2499                         g2D.drawLine(t.x - 3, t.y + 3, t.x + 3, t.y - 3);
2500                 }
2501         }
2502
2503         public void drawRegionHighlightsAnnotation(VueVARNAGraphics g2D,
2504                         Point2D.Double[] realCoords, Point2D.Double[] realCenters,
2505                         double scaleFactor) {
2506                 g2D.setStrokeThickness(2.0 * scaleFactor);
2507                 g2D.setPlainStroke();
2508                 for (HighlightRegionAnnotation r : _RNA.getHighlightRegion()) {
2509                         GeneralPath s = r.getShape(realCoords, realCenters, scaleFactor);
2510                         g2D.setColor(r.getFillColor());
2511                         g2D.fill(s);
2512                         g2D.setColor(r.getOutlineColor());
2513                         g2D.draw(s);
2514                 }
2515         }
2516
2517         private Rectangle2D.Double getClip() {
2518                 return new Rectangle2D.Double(getLeftOffset(), getTopOffset(),
2519                                 this.getInnerWidth(), this.getInnerHeight());
2520         }
2521
2522         public Rectangle2D.Double getViewClip() {
2523                 return new Rectangle2D.Double(this.getLeftOffset(),
2524                                 this.getTopOffset(), this.getInnerWidth(),
2525                                 this.getInnerHeight());
2526         }
2527
2528         /**
2529          * Returns the color used to draw backbone bounds.
2530          * 
2531          * @return The color used to draw backbone bounds
2532          */
2533         public Color getBackboneColor() {
2534                 return _conf._backboneColor;
2535         }
2536
2537         /**
2538          * Sets the color to be used for drawing backbone interactions.
2539          * 
2540          * @param backbone_color
2541          *            The new color for the backbone bounds
2542          */
2543         public void setBackboneColor(Color backbone_color) {
2544                 _conf._backboneColor = backbone_color;
2545         }
2546
2547         /**
2548          * Returns the color used to display hydrogen bonds (base pairings)
2549          * 
2550          * @return The color of hydrogen bonds
2551          */
2552         public Color getBondColor() {
2553                 return _conf._bondColor;
2554         }
2555
2556         /**
2557          * Returns the title of this panel
2558          * 
2559          * @return The title
2560          */
2561         public String getTitle() {
2562                 return _RNA.getName();
2563         }
2564
2565         /**
2566          * Sets the new color to be used for hydrogen bonds (base pairings)
2567          * 
2568          * @param bond_color
2569          *            The new color for hydrogen bonds
2570          */
2571         public void setDefaultBPColor(Color bond_color) {
2572                 _conf._bondColor = bond_color;
2573         }
2574
2575         /**
2576          * Sets the size of the border, i.e. the empty space between the end of the
2577          * drawing area and the actual border.
2578          * 
2579          * @param b
2580          *            The new border size
2581          */
2582         public void setBorderSize(Dimension b) {
2583                 _border = b;
2584         }
2585
2586         /**
2587          * Returns the size of the border, i.e. the empty space between the end of
2588          * the drawing area
2589          * 
2590          * @return The border size
2591          */
2592         public Dimension getBorderSize() {
2593                 return _border;
2594         }
2595
2596         /**
2597          * Sets the RNA to be displayed within this Panel. This method does not use
2598          * a drawing algorithm to reassigns base coordinates, rather assuming that
2599          * the RNA was previously drawn.
2600          * 
2601          * @param r
2602          *            An already drawn RNA to display in this panel
2603          */
2604         public synchronized void showRNA(RNA r) {
2605                 fireUINewStructure(r);
2606                 _RNA = r;
2607         }
2608
2609         /**
2610          * Sets the RNA secondary structure to be drawn in this panel, using the
2611          * default layout algorithm. In addition to the raw nucleotides sequence,
2612          * the secondary structure is given in the so-called "Dot-bracket notation"
2613          * (DBN) format. This format is a well-parenthesized word over the alphabet
2614          * '(',')','.'.<br/>
2615          * Ex:<code>((((((((....))))..(((((...))).))))))</code><br />
2616          * Returns <code>true</code> if the sequence/structure couple could be
2617          * parsed into a valid secondary structure, and <code>false</code>
2618          * otherwise.
2619          * 
2620          * @param seq
2621          *            The raw nucleotides sequence
2622          * @param str
2623          *            The secondary structure
2624          * @throws ExceptionNonEqualLength
2625          */
2626         public void drawRNA(String seq, String str) throws ExceptionNonEqualLength {
2627                 drawRNA(seq, str, _RNA.get_drawMode());
2628         }
2629
2630         /**
2631          * Sets the RNA secondary structure to be drawn in this panel, using a given
2632          * layout algorithm.
2633          * 
2634          * @param r
2635          *            The new secondary structure
2636          * @param drawMode
2637          *            The drawing algorithm
2638          */
2639         public void drawRNA(RNA r, int drawMode) {
2640                 r.setDrawMode(drawMode);
2641                 drawRNA(r);
2642         }
2643
2644         /**
2645          * Redraws the current RNA. This reassigns base coordinates to their default
2646          * value using the current drawing algorithm.
2647          */
2648
2649         public void drawRNA() {
2650                 try {
2651                         _RNA.drawRNA(_RNA.get_drawMode(), _conf);
2652                 } catch (ExceptionNAViewAlgorithm e) {
2653                         errorDialog(e);
2654                         e.printStackTrace();
2655                 }
2656                 repaint();
2657         }
2658
2659         /**
2660          * Sets the RNA secondary structure to be drawn in this panel, using the
2661          * current drawing algorithm.
2662          * 
2663          * @param r
2664          *            The new secondary structure
2665          */
2666         public void drawRNA(RNA r) {
2667                 if (r != null) {
2668                         _RNA = r;
2669                         drawRNA();
2670                 }
2671         }
2672
2673         /**
2674          * Sets the RNA secondary structure to be drawn in this panel, using a given
2675          * layout algorithm. In addition to the raw nucleotides sequence, the
2676          * secondary structure is given in the so-called "Dot-bracket notation"
2677          * (DBN) format. This format is a well-parenthesized word over the alphabet
2678          * '(',')','.'.<br/>
2679          * Ex: <code>((((((((....))))..(((((...))).))))))</code><br />
2680          * Returns <code>true</code> if the sequence/structure couple could be
2681          * parsed into a valid secondary structure, and <code>false</code>
2682          * otherwise.
2683          * 
2684          * @param seq
2685          *            The raw nucleotides sequence
2686          * @param str
2687          *            The secondary structure
2688          * @param drawMode
2689          *            The drawing algorithm
2690          * @throws ExceptionNonEqualLength
2691          */
2692         public void drawRNA(String seq, String str, int drawMode)
2693                         throws ExceptionNonEqualLength {
2694                 _RNA.setDrawMode(drawMode);
2695                 try {
2696                         _RNA.setRNA(seq, str);
2697                         drawRNA();
2698                 } catch (ExceptionUnmatchedClosingParentheses e) {
2699                         errorDialog(e);
2700                 } catch (ExceptionFileFormatOrSyntax e1) {
2701                         errorDialog(e1);
2702                 }
2703         }
2704
2705         public void drawRNA(Reader r, int drawMode) throws ExceptionNonEqualLength,
2706                         ExceptionFileFormatOrSyntax {
2707                 _RNA.setDrawMode(drawMode);
2708                 Collection<RNA> rnas = RNAFactory.loadSecStr(r);
2709                 if (rnas.isEmpty()) {
2710                         throw new ExceptionFileFormatOrSyntax(
2711                                         "No RNA could be parsed from that source.");
2712                 }
2713                 _RNA = rnas.iterator().next();
2714                 drawRNA();
2715         }
2716
2717         /**
2718          * Draws a secondary structure of RNA using the default drawing algorithm
2719          * and displays it, using an interpolated transition between the previous
2720          * one and the new one. Extra bases, resulting from a size difference
2721          * between the two successive RNAs, are assumed to initiate from the middle
2722          * of the sequence. In other words, both prefixes and suffixes of the RNAs
2723          * are assumed to match, and what remains is an insertion.
2724          * 
2725          * @param seq
2726          *            Sequence
2727          * @param str
2728          *            Structure in dot bracket notation
2729          * @throws ExceptionNonEqualLength
2730          *             If len(seq)!=len(str)
2731          */
2732         public void drawRNAInterpolated(String seq, String str)
2733                         throws ExceptionNonEqualLength {
2734                 drawRNAInterpolated(seq, str, _RNA.get_drawMode());
2735         }
2736
2737         /**
2738          * Draws a secondary structure of RNA using a given algorithm and displays
2739          * it, using an interpolated transition between the previous one and the new
2740          * one. Extra bases, resulting from a size difference between the two
2741          * successive RNAs, are assumed to initiate from the middle of the sequence.
2742          * In other words, both prefixes and suffixes of the RNAs are assumed to
2743          * match, and what remains is an insertion.
2744          * 
2745          * @param seq
2746          *            Sequence
2747          * @param str
2748          *            Structure in dot bracket notation
2749          * @param drawMode
2750          *            The drawing algorithm to be used for the initial placement
2751          * @throws ExceptionNonEqualLength
2752          *             If len(seq)!=len(str)
2753          */
2754         public void drawRNAInterpolated(String seq, String str, int drawMode) {
2755                 drawRNAInterpolated(seq, str, drawMode,
2756                                 Mapping.DefaultOutermostMapping(_RNA.get_listeBases().size(),
2757                                                 str.length()));
2758         }
2759
2760         /**
2761          * Draws a secondary structure of RNA using the default drawing algorithm
2762          * and displays it, using an interpolated transition between the previous
2763          * one and the new one. Here, a mapping between those bases of the new
2764          * structure and the previous one is explicitly provided.
2765          * 
2766          * @param seq
2767          *            Sequence
2768          * @param str
2769          *            Structure in dot bracket notation
2770          * @param m
2771          *            A mapping between the currently rendered structure and its
2772          *            successor (seq,str)
2773          * @throws ExceptionNonEqualLength
2774          *             If len(seq)!=len(str)
2775          */
2776         public void drawRNAInterpolated(String seq, String str, Mapping m) {
2777                 drawRNAInterpolated(seq, str, _RNA.get_drawMode(), m);
2778         }
2779
2780         /**
2781          * Draws a secondary structure of RNA using a given drawing algorithm and
2782          * displays it, using an interpolated transition between the previous one
2783          * and the new one. Here, a mapping between those bases of the new structure
2784          * and the previous one is provided.
2785          * 
2786          * @param seq
2787          *            Sequence
2788          * @param str
2789          *            Structure in dot bracket notation
2790          * @param drawMode
2791          *            The drawing algorithm to be used for the initial placement
2792          * @param m
2793          *            A mapping between the currently rendered structure and its
2794          *            successor (seq,str)
2795          */
2796         public void drawRNAInterpolated(String seq, String str, int drawMode,
2797                         Mapping m) {
2798                 RNA target = new RNA();
2799                 try {
2800                         target.setRNA(seq, str);
2801                         drawRNAInterpolated(target, drawMode, m);
2802                 } catch (ExceptionUnmatchedClosingParentheses e) {
2803                         errorDialog(e);
2804                 } catch (ExceptionFileFormatOrSyntax e) {
2805                         errorDialog(e);
2806                 }
2807         }
2808
2809         /**
2810          * Draws a secondary structure of RNA using the default drawing algorithm
2811          * and displays it, using an interpolated transition between the previous
2812          * one and the new one. Here, a mapping between those bases of the new
2813          * structure and the previous one is explicitly provided.
2814          * 
2815          * @param target
2816          *            Secondary structure
2817          */
2818         public void drawRNAInterpolated(RNA target) {
2819                 drawRNAInterpolated(target, target.get_drawMode(),
2820                                 Mapping.DefaultOutermostMapping(_RNA.get_listeBases().size(),
2821                                                 target.getSize()));
2822         }
2823
2824         /**
2825          * Draws a secondary structure of RNA using the default drawing algorithm
2826          * and displays it, using an interpolated transition between the previous
2827          * one and the new one. Here, a mapping between those bases of the new
2828          * structure and the previous one is explicitly provided.
2829          * 
2830          * @param target
2831          *            Secondary structure
2832          * @param m
2833          *            A mapping between the currently rendered structure and its
2834          *            successor (seq,str)
2835          */
2836         public void drawRNAInterpolated(RNA target, Mapping m) {
2837                 drawRNAInterpolated(target, target.get_drawMode(), m);
2838         }
2839
2840         /**
2841          * Draws a secondary structure of RNA using a given drawing algorithm and
2842          * displays it, using an interpolated transition between the previous one
2843          * and the new one. Here, a mapping between those bases of the new structure
2844          * and the previous one is provided.
2845          * 
2846          * @param target
2847          *            Secondary structure of RNA
2848          * @param drawMode
2849          *            The drawing algorithm to be used for the initial placement
2850          * @param m
2851          *            A mapping between the currently rendered structure and its
2852          *            successor (seq,str)
2853          */
2854         public void drawRNAInterpolated(RNA target, int drawMode, Mapping m) {
2855                 try {
2856                         target.drawRNA(drawMode, _conf);
2857                         _conf._drawColorMap = false;
2858                         _interpolator.addTarget(target, m);
2859                 } catch (ExceptionNAViewAlgorithm e) {
2860                         errorDialog(e);
2861                         e.printStackTrace();
2862                 }
2863         }
2864
2865         /**
2866          * Returns the current algorithm used for drawing the structure
2867          * 
2868          * @return The current drawing algorithm
2869          */
2870         public int getDrawMode() {
2871                 return this._RNA.getDrawMode();
2872         }
2873
2874         public void showRNA(RNA t, VARNAConfig cfg) {
2875                 showRNA(t);
2876                 if (cfg != null) {
2877                         this.setConfig(cfg);
2878                 }
2879                 repaint();
2880         }
2881
2882         /**
2883          * Checks whether an interpolated transition bewteen two RNAs is occurring.
2884          * 
2885          * @return True if an interpolated transition is occurring, false otherwise
2886          */
2887
2888         public boolean isInterpolationInProgress() {
2889                 if (_interpolator == null) {
2890                         return false;
2891                 } else
2892                         return _interpolator.isInterpolationInProgress();
2893         }
2894
2895         /**
2896          * Simply displays (does not redraw) a secondary structure , using an
2897          * interpolated transition between the previous one and the new one. A
2898          * default mapping between those bases of the new structure and the previous
2899          * one is used.
2900          * 
2901          * @param target
2902          *            Secondary structure of RNA
2903          */
2904         public void showRNAInterpolated(RNA target) {
2905                 showRNAInterpolated(target, Mapping.DefaultOutermostMapping(_RNA
2906                                 .get_listeBases().size(), target.getSize()));
2907         }
2908
2909         /**
2910          * Simply displays (does not redraw) a secondary structure , using an
2911          * interpolated transition between the previous one and the new one. Here, a
2912          * mapping between bases of the new structure and the previous one is given.
2913          * 
2914          * @param target
2915          *            Secondary structure of RNA
2916          * @param m
2917          *            A mapping between the currently rendered structure and its
2918          *            successor (seq,str)
2919          * @throws ExceptionNonEqualLength
2920          *             If len(seq)!=len(str)
2921          */
2922         public void showRNAInterpolated(RNA target, Mapping m) {
2923                 showRNAInterpolated(target, null, m);
2924         }
2925
2926         public void showRNAInterpolated(RNA target, VARNAConfig cfg, Mapping m) {
2927                 _interpolator.addTarget(target, cfg, m);
2928         }
2929
2930         /**
2931          * When comparison mode is ON, sets the two RNA secondary structure to be
2932          * drawn in this panel, using a given layout algorithm. In addition to the
2933          * raw nucleotides sequence, the secondary structure is given in the
2934          * so-called "Dot-bracket notation" (DBN) format. This format is a
2935          * well-parenthesized word over the alphabet '(',')','.'.<br/>
2936          * Ex: <code>((((((((....))))..(((((...))).))))))</code><br />
2937          * 
2938          * @param firstSeq
2939          *            The first RNA raw nucleotides sequence
2940          * @param firstStruct
2941          *            The first RNA secondary structure
2942          * @param secondSeq
2943          *            The second RNA raw nucleotides sequence
2944          * @param secondStruct
2945          *            The second RNA secondary structure
2946          * @param drawMode
2947          *            The drawing algorithm
2948          */
2949         public void drawRNA(String firstSeq, String firstStruct, String secondSeq,
2950                         String secondStruct, int drawMode) {
2951                 _RNA.setDrawMode(drawMode);
2952                 /**
2953                  * Checking the sequences and structures validities...
2954                  */
2955
2956                 // This is a comparison, so the two RNA alignment past in parameters
2957                 // must
2958                 // have the same sequence and structure length.
2959                 if (firstSeq.length() == secondSeq.length()
2960                                 && firstStruct.length() == secondStruct.length()) {
2961                         // First RNA
2962                         if (firstSeq.length() != firstStruct.length()) {
2963                                 if (_conf._showWarnings) {
2964                                         emitWarning("First sequence length " + firstSeq.length()
2965                                                         + " differs from that of it's secondary structure "
2966                                                         + firstStruct.length()
2967                                                         + ". \nAdapting first sequence length ...");
2968                                 }
2969                                 if (firstSeq.length() < firstStruct.length()) {
2970                                         while (firstSeq.length() < firstStruct.length()) {
2971                                                 firstSeq += " ";
2972                                         }
2973                                 } else {
2974                                         firstSeq = firstSeq.substring(0, firstStruct.length());
2975                                 }
2976                         }
2977
2978                         // Second RNA
2979                         if (secondSeq.length() != secondStruct.length()) {
2980                                 if (_conf._showWarnings) {
2981                                         emitWarning("Second sequence length " + secondSeq.length()
2982                                                         + " differs from that of it's secondary structure "
2983                                                         + secondStruct.length()
2984                                                         + ". \nAdapting second sequence length ...");
2985                                 }
2986                                 if (secondSeq.length() < secondStruct.length()) {
2987                                         while (secondSeq.length() < secondStruct.length()) {
2988                                                 secondSeq += " ";
2989                                         }
2990                                 } else {
2991                                         secondSeq = secondSeq.substring(0, secondStruct.length());
2992                                 }
2993                         }
2994
2995                         int RNALength = firstSeq.length();
2996                         String string_superStruct = new String("");
2997                         String string_superSeq = new String("");
2998                         /**
2999                          * In this array, we'll have for each indexes of each characters of
3000                          * the final super-structure, the RNA number which is own it.
3001                          */
3002                         ArrayList<Integer> array_rnaOwn = new ArrayList<Integer>();
3003
3004                         /**
3005                          * Generating super-structure sequences and structures...
3006                          */
3007
3008                         firstStruct = firstStruct.replace('-', '.');
3009                         secondStruct = secondStruct.replace('-', '.');
3010                         // First of all, we make the structure
3011                         for (int i = 0; i < RNALength; i++) {
3012                                 // If both characters are the same, so it'll be in the super
3013                                 // structure
3014                                 if (firstStruct.charAt(i) == secondStruct.charAt(i)) {
3015                                         string_superStruct = string_superStruct
3016                                                         + firstStruct.charAt(i);
3017                                         array_rnaOwn.add(0);
3018                                 }
3019                                 // Else if one of the characters is an opening parenthese, so
3020                                 // it'll be an opening parenthese in the super structure
3021                                 else if (firstStruct.charAt(i) == '('
3022                                                 || secondStruct.charAt(i) == '(') {
3023                                         string_superStruct = string_superStruct + '(';
3024                                         array_rnaOwn.add((firstStruct.charAt(i) == '(') ? 1 : 2);
3025                                 }
3026                                 // Else if one of the characters is a closing parenthese, so
3027                                 // it'll be a closing parenthese in the super structure
3028                                 else if (firstStruct.charAt(i) == ')'
3029                                                 || secondStruct.charAt(i) == ')') {
3030                                         string_superStruct = string_superStruct + ')';
3031                                         array_rnaOwn.add((firstStruct.charAt(i) == ')') ? 1 : 2);
3032                                 } else {
3033                                         string_superStruct = string_superStruct + '.';
3034                                         array_rnaOwn.add(-1);
3035                                 }
3036                         }
3037
3038                         // Next, we make the sequence taking the characters at the same
3039                         // index in the first and second sequence
3040                         for (int i = 0; i < RNALength; i++) {
3041                                 string_superSeq = string_superSeq + firstSeq.charAt(i)
3042                                                 + secondSeq.charAt(i);
3043                         }
3044
3045                         // Now, we need to create the super-structure RNA with the owning
3046                         // bases array
3047                         // in order to color bases outer depending on the owning statement
3048                         // of each bases.
3049                         if (!string_superSeq.equals("") && !string_superStruct.equals("")) {
3050                                 try {
3051                                         _RNA.setRNA(string_superSeq, string_superStruct,
3052                                                         array_rnaOwn);
3053                                 } catch (ExceptionUnmatchedClosingParentheses e) {
3054                                         errorDialog(e);
3055                                 } catch (ExceptionFileFormatOrSyntax e) {
3056                                         errorDialog(e);
3057                                 }
3058                         } else {
3059                                 emitWarning("ERROR : The super-structure is NULL.");
3060                         }
3061
3062                         switch (_RNA.get_drawMode()) {
3063                         case RNA.DRAW_MODE_RADIATE:
3064                                 _RNA.drawRNARadiate(_conf);
3065                                 break;
3066                         case RNA.DRAW_MODE_CIRCULAR:
3067                                 _RNA.drawRNACircle(_conf);
3068                                 break;
3069                         case RNA.DRAW_MODE_LINEAR:
3070                                 _RNA.drawRNALine(_conf);
3071                                 break;
3072                         case RNA.DRAW_MODE_NAVIEW:
3073                                 try {
3074                                         _RNA.drawRNANAView(_conf);
3075                                 } catch (ExceptionNAViewAlgorithm e) {
3076                                         errorDialog(e);
3077                                 }
3078                                 break;
3079                         default:
3080                                 break;
3081                         }
3082
3083                 }
3084         }
3085
3086         /**
3087          * Returns the currently selected base index, obtained through a mouse-left
3088          * click
3089          * 
3090          * @return Selected base
3091          * 
3092          *         public int getSelectedBaseIndex() { return _selectedBase; }
3093          * 
3094          *         /** Returns the currently selected base, obtained through a
3095          *         mouse-left click
3096          * 
3097          * @return Selected base
3098          * 
3099          *         public ModeleBase getSelectedBase() { return
3100          *         _RNA.get_listeBases().get(_selectedBase); }
3101          * 
3102          *         /** Sets the selected base index
3103          * 
3104          * @param base
3105          *            New selected base index
3106          * 
3107          *            public void setSelectedBase(int base) { _selectedBase = base;
3108          *            }
3109          */
3110
3111         /**
3112          * Returns the coordinates of the currently displayed RNA
3113          * 
3114          * @return Coordinates array
3115          */
3116         public Point2D.Double[] getRealCoords() {
3117                 return _realCoords;
3118         }
3119
3120         /**
3121          * Sets the coordinates of the currently displayed RNA
3122          * 
3123          * @param coords
3124          *            New coordinates
3125          */
3126         public void setRealCoords(Point2D.Double[] coords) {
3127                 _realCoords = coords;
3128         }
3129
3130         /**
3131          * Returns the popup menu used for user mouse iteractions
3132          * 
3133          * @return Popup menu
3134          */
3135         public VueMenu getPopup() {
3136                 return _popup;
3137         }
3138
3139         /**
3140          * Sets the color used to display hydrogen bonds (base pairings)
3141          * 
3142          * @param bond_color
3143          *            The color of hydrogen bonds
3144          */
3145         public void setBondColor(Color bond_color) {
3146                 _conf._bondColor = bond_color;
3147         }
3148
3149         /**
3150          * Returns the color used to draw the title
3151          * 
3152          * @return The color used to draw the title
3153          */
3154         public Color getTitleColor() {
3155                 return _conf._titleColor;
3156         }
3157
3158         /**
3159          * Sets the color used to draw the title
3160          * 
3161          * @param title_color
3162          *            The new color used to draw the title
3163          */
3164         public void setTitleColor(Color title_color) {
3165                 _conf._titleColor = title_color;
3166         }
3167
3168         /**
3169          * Returns the height taken by the title
3170          * 
3171          * @return The height taken by the title
3172          */
3173         private int getTitleHeight() {
3174                 return _titleHeight;
3175         }
3176
3177         /**
3178          * Sets the height taken by the title
3179          * 
3180          * @param title_height
3181          *            The height taken by the title
3182          */
3183         @SuppressWarnings("unused")
3184         private void setTitleHeight(int title_height) {
3185                 _titleHeight = title_height;
3186         }
3187
3188         /**
3189          * Returns the current state of auto centering mode.
3190          * 
3191          * @return True if autocentered, false otherwise
3192          */
3193         public boolean isAutoCentered() {
3194                 return _conf._autoCenter;
3195         }
3196
3197         /**
3198          * Sets the current state of auto centering mode.
3199          * 
3200          * @param center
3201          *            New auto-centered state
3202          */
3203         public void setAutoCenter(boolean center) {
3204                 _conf._autoCenter = center;
3205         }
3206
3207         /**
3208          * Returns the font currently used for rendering the title.
3209          * 
3210          * @return Current title font
3211          */
3212         public Font getTitleFont() {
3213                 return _conf._titleFont;
3214         }
3215
3216         /**
3217          * Sets the font used for rendering the title.
3218          * 
3219          * @param font
3220          *            New title font
3221          */
3222         public void setTitleFont(Font font) {
3223                 _conf._titleFont = font;
3224                 updateTitleHeight();
3225         }
3226
3227         /**
3228          * For the LINE_MODE drawing algorithm, sets the base pair height increment,
3229          * i.e. the vertical distance between two nested arcs.
3230          * 
3231          * @return The current base pair increment
3232          */
3233         public double getBPHeightIncrement() {
3234                 return _RNA._bpHeightIncrement;
3235         }
3236
3237         /**
3238          * Sets the base pair height increment, i.e. the vertical distance between
3239          * two arcs to be used in LINE_MODE.
3240          * 
3241          * @param inc
3242          *            New height increment
3243          */
3244         public void setBPHeightIncrement(double inc) {
3245                 _RNA._bpHeightIncrement = inc;
3246         }
3247
3248         /**
3249          * Returns the shifting of the origin of the Panel in zoom mode
3250          * 
3251          * @return The logical coordinate of the top-left panel point
3252          */
3253         public Point2D.Double getOffsetPanel() {
3254                 return _offsetPanel;
3255         }
3256
3257         /**
3258          * Returns the vector bringing the logical coordinate of left-top-most point
3259          * in the panel to the left-top-most point of the RNA.
3260          * 
3261          * @return The logical coordinate of the top-left panel point
3262          */
3263         private Point2D.Double getRNAOffset() {
3264                 return _offsetRNA;
3265         }
3266
3267         /**
3268          * Returns this panel's UI menu
3269          * 
3270          * @return Applet's UI popupmenu
3271          */
3272         public VueMenu getPopupMenu() {
3273                 return _popup;
3274         }
3275
3276         /**
3277          * Returns the atomic zoom factor step, or increment.
3278          * 
3279          * @return Atomic zoom factor increment
3280          */
3281         public double getZoomIncrement() {
3282                 return _conf._zoomAmount;
3283         }
3284
3285         /**
3286          * Sets the atomic zoom factor step, or increment.
3287          * 
3288          * @param amount
3289          *            Atomic zoom factor increment
3290          */
3291         public void setZoomIncrement(Object amount) {
3292                 setZoomIncrement(Float.valueOf(amount.toString()));
3293         }
3294
3295         /**
3296          * Sets the atomic zoom factor step, or increment.
3297          * 
3298          * @param amount
3299          *            Atomic zoom factor increment
3300          */
3301         public void setZoomIncrement(double amount) {
3302                 _conf._zoomAmount = amount;
3303         }
3304
3305         /**
3306          * Returns the current zoom factor
3307          * 
3308          * @return Current zoom factor
3309          */
3310         public double getZoom() {
3311                 return _conf._zoom;
3312         }
3313
3314         /**
3315          * Sets the current zoom factor
3316          * 
3317          * @param _zoom
3318          *            New zoom factor
3319          */
3320         public void setZoom(Object _zoom) {
3321                 double d = Float.valueOf(_zoom.toString());
3322                 if (_conf._zoom != d) {
3323                         _conf._zoom = d;
3324                         fireZoomLevelChanged(d);
3325                 }
3326         }
3327
3328         /**
3329          * Returns the translation used for zooming in and out
3330          * 
3331          * @return A vector describing the translation
3332          */
3333         public Point getTranslation() {
3334                 return _translation;
3335         }
3336
3337         /**
3338          * Sets the translation used for zooming in and out
3339          * 
3340          * @param trans
3341          *            A vector describing the new translation
3342          */
3343         public void setTranslation(Point trans) {
3344                 _translation = trans;
3345                 checkTranslation();
3346                 fireTranslationChanged();
3347         }
3348
3349         /**
3350          * Returns the current RNA model
3351          * 
3352          * @return Current RNA model
3353          */
3354         public RNA getRNA() {
3355                 return _RNA;
3356         }
3357
3358         /**
3359          * Checks whether the drawn RNA is too large to be displayed, allowing for
3360          * shifting mouse interactions.
3361          * 
3362          * @return true if the RNA is too large to be displayed, false otherwise
3363          */
3364         public boolean isOutOfFrame() {
3365                 return _horsCadre;
3366         }
3367
3368         /**
3369          * Pops up an error Dialog displaying an exception in an human-readable way.
3370          * 
3371          * @param error
3372          *            The exception to display within the Dialog
3373          */
3374         public void errorDialog(Exception error) {
3375                 errorDialog(error, this);
3376         }
3377
3378         /**
3379          * Pops up an error Dialog displaying an exception in an human-readable way
3380          * if errors are set to be displayed.
3381          * 
3382          * @see #setErrorsOn(boolean)
3383          * @param error
3384          *            The exception to display within the Dialog
3385          * @param c
3386          *            Parent component for the dialog box
3387          */
3388         public void errorDialog(Exception error, Component c) {
3389                 if (isErrorsOn()) {
3390                         JOptionPane.showMessageDialog(c, error.getMessage(), "VARNA Error",
3391                                         JOptionPane.ERROR_MESSAGE);
3392                 }
3393         }
3394
3395         /**
3396          * Pops up an error Dialog displaying an exception in an human-readable way.
3397          * 
3398          * @param error
3399          *            The exception to display within the Dialog
3400          * @param c
3401          *            Parent component for the dialog box
3402          */
3403         public static void errorDialogStatic(Exception error, Component c) {
3404                 if (c != null) {
3405                         JOptionPane.showMessageDialog(c, error.getMessage(),
3406                                         "VARNA Critical Error", JOptionPane.ERROR_MESSAGE);
3407                 } else {
3408                         System.err.println("Error: " + error.getMessage());
3409                 }
3410         }
3411
3412         /**
3413          * Displays a warning message through a modal dialog if warnings are set to
3414          * be displayed.
3415          * 
3416          * @see #setShowWarnings(boolean)
3417          * @param warning
3418          *            A message expliciting the warning
3419          */
3420         public void emitWarning(String warning) {
3421                 if (_conf._showWarnings)
3422                         JOptionPane.showMessageDialog(this, warning, "VARNA Warning",
3423                                         JOptionPane.WARNING_MESSAGE);
3424         }
3425
3426         public static void emitWarningStatic(Exception e, Component c) {
3427                 emitWarningStatic(e.getMessage(), c);
3428         }
3429
3430         public static void emitWarningStatic(String warning, Component c) {
3431                 if (c != null) {
3432                         JOptionPane.showMessageDialog(c, warning, "VARNA Warning",
3433                                         JOptionPane.WARNING_MESSAGE);
3434                 } else {
3435                         System.err.println("Error: " + warning);
3436                 }
3437         }
3438
3439         /**
3440          * Toggles modifications on and off
3441          * 
3442          * @param modifiable
3443          *            Modification status
3444          */
3445         public void setModifiable(boolean modifiable) {
3446                 _conf._modifiable = modifiable;
3447         }
3448
3449         /**
3450          * Returns current modification status
3451          * 
3452          * @return current modification status
3453          */
3454         public boolean isModifiable() {
3455                 return _conf._modifiable;
3456         }
3457
3458         /**
3459          * Resets the visual aspects (Zoom factor, shift) for the Panel.
3460          */
3461         public void reset() {
3462                 this.setBorderSize(new Dimension(0, 0));
3463                 this.setTranslation(new Point(0, (int) (-getTitleHeight() / 2.0)));
3464                 this.setZoom(VARNAConfig.DEFAULT_ZOOM);
3465                 this.setZoomIncrement(VARNAConfig.DEFAULT_AMOUNT);
3466         }
3467
3468         /**
3469          * Returns the color used to draw non-standard bases
3470          * 
3471          * @return The color used to draw non-standard bases
3472          */
3473         public Color getNonStandardBasesColor() {
3474                 return _conf._specialBasesColor;
3475         }
3476
3477         /**
3478          * Sets the color used to draw non-standard bases
3479          * 
3480          * @param basesColor
3481          *            The color used to draw non-standard bases
3482          */
3483         public void setNonStandardBasesColor(Color basesColor) {
3484                 _conf._specialBasesColor = basesColor;
3485         }
3486
3487         /**
3488          * Checks if the current translation doesn't "kick" the whole RNA out of the
3489          * panel, and corrects the situation if necessary.
3490          */
3491         public void checkTranslation() {
3492                 // verification pour un zoom < 1
3493                 if (this.getZoom() <= 1) {
3494                         // verification sortie gauche
3495                         if (this.getTranslation().x < -(int) ((this.getWidth() - this
3496                                         .getInnerWidth()) / 2.0)) {
3497                                 this.setTranslation(new Point(-(int) ((this.getWidth() - this
3498                                                 .getInnerWidth()) / 2.0), this.getTranslation().y));
3499                         }
3500                         // verification sortie droite
3501                         if (this.getTranslation().x > (int) ((this.getWidth() - this
3502                                         .getInnerWidth()) / 2.0)) {
3503                                 this.setTranslation(new Point((int) ((this.getWidth() - this
3504                                                 .getInnerWidth()) / 2.0), this.getTranslation().y));
3505                         }
3506                         // verification sortie bas
3507                         if (this.getTranslation().y > (int) ((this.getHeight()
3508                                         - getTitleHeight() * 2 - this.getInnerHeight()) / 2.0)) {
3509                                 this.setTranslation(new Point(this.getTranslation().x,
3510                                                 (int) ((this.getHeight() - getTitleHeight() * 2 - this
3511                                                                 .getInnerHeight()) / 2.0)));
3512                         }
3513                         // verification sortie haut
3514                         if (this.getTranslation().y < -(int) ((this.getHeight() - this
3515                                         .getInnerHeight()) / 2.0)) {
3516                                 this.setTranslation(new Point(
3517                                                 this.getTranslation().x,
3518                                                 -(int) ((this.getHeight() - this.getInnerHeight()) / 2.0)));
3519                         }
3520                 } else {
3521                         // zoom > 1
3522                         Rectangle r2 = getZoomedInTranslationBox();
3523                         int LBoundX = r2.x;
3524                         int UBoundX = r2.x + r2.width;
3525                         int LBoundY = r2.y;
3526                         int UBoundY = r2.y + r2.height;
3527                         if (this.getTranslation().x < LBoundX) {
3528                                 this.setTranslation(new Point(LBoundX, getTranslation().y));
3529                         } else if (this.getTranslation().x > UBoundX) {
3530                                 this.setTranslation(new Point(UBoundX, getTranslation().y));
3531                         }
3532                         if (this.getTranslation().y < LBoundY) {
3533                                 this.setTranslation(new Point(getTranslation().x, LBoundY));
3534                         } else if (this.getTranslation().y > UBoundY) {
3535                                 this.setTranslation(new Point(getTranslation().x, UBoundY));
3536                         }
3537                 }
3538         }
3539
3540         public Rectangle getZoomedInTranslationBox() {
3541                 int LBoundX = -(int) ((this.getInnerWidth()) / 2.0);
3542                 int UBoundX = (int) ((this.getInnerWidth()) / 2.0);
3543                 int LBoundY = -(int) ((this.getInnerHeight()) / 2.0);
3544                 int UBoundY = (int) ((this.getInnerHeight()) / 2.0);
3545                 return new Rectangle(LBoundX, LBoundY, UBoundX - LBoundX, UBoundY
3546                                 - LBoundY);
3547
3548         }
3549
3550         /**
3551          * Returns the "real pixels" x-coordinate of the RNA.
3552          * 
3553          * @return X-coordinate of the translation
3554          */
3555         public int getLeftOffset() {
3556                 return _border.width
3557                                 + ((this.getWidth() - 2 * _border.width) - this.getInnerWidth())
3558                                 / 2 + _translation.x;
3559         }
3560
3561         /**
3562          * Returns the "real pixels" width of the drawing surface for our RNA.
3563          * 
3564          * @return Width of the drawing surface for our RNA
3565          */
3566         public int getInnerWidth() {
3567                 // Largeur du dessin
3568                 return (int) Math.round((this.getWidth() - 2 * _border.width)
3569                                 * _conf._zoom);
3570         }
3571
3572         /**
3573          * Returns the "real pixels" y-coordinate of the RNA.
3574          * 
3575          * @return Y-coordinate of the translation
3576          */
3577         public int getTopOffset() {
3578                 return _border.height
3579                                 + ((this.getHeight() - 2 * _border.height) - this
3580                                                 .getInnerHeight()) / 2 + _translation.y;
3581         }
3582
3583         /**
3584          * Returns the "real pixels" height of the drawing surface for our RNA.
3585          * 
3586          * @return Height of the drawing surface for our RNA
3587          */
3588         public int getInnerHeight() {
3589                 // Hauteur du dessin
3590                 return (int) Math.round((this.getHeight()) * _conf._zoom - 2
3591                                 * _border.height - getTitleHeight());
3592         }
3593
3594         /**
3595          * Checks if the current mode is the "comparison" mode
3596          * 
3597          * @return True if comparison, false otherwise
3598          */
3599         public boolean isComparisonMode() {
3600                 return _conf._comparisonMode;
3601         }
3602
3603         /**
3604          * Rotates the RNA coordinates by a certain angle
3605          * 
3606          * @param angleDegres
3607          *            Rotation angle, in degrees
3608          */
3609         public void globalRotation(Double angleDegres) {
3610                 _RNA.globalRotation(angleDegres);
3611                 fireLayoutChanged();
3612                 repaint();
3613         }
3614
3615         /**
3616          * Returns the index of the currently selected base, defaulting to the
3617          * closest base to the last mouse-click.
3618          * 
3619          * @return Index of the currently selected base
3620          */
3621         public Integer getNearestBase() {
3622                 return _nearestBase;
3623         }
3624
3625         /**
3626          * Sets the index of the currently selected base.
3627          * 
3628          * @param base
3629          *            Index of the new selected base
3630          */
3631         public void setNearestBase(Integer base) {
3632                 _nearestBase = base;
3633         }
3634
3635         /**
3636          * Returns the color used to draw 'Gaps' bases in comparison mode
3637          * 
3638          * @return Color used for 'Gaps'
3639          */
3640         public Color getGapsBasesColor() {
3641                 return _conf._dashBasesColor;
3642         }
3643
3644         /**
3645          * Sets the color to use for 'Gaps' bases in comparison mode
3646          * 
3647          * @param c
3648          *            Color used for 'Gaps'
3649          */
3650         public void setGapsBasesColor(Color c) {
3651                 _conf._dashBasesColor = c;
3652         }
3653
3654         @SuppressWarnings("unused")
3655         private void imprimer() {
3656                 // PrintPanel canvas;
3657                 // canvas = new PrintPanel();
3658                 PrintRequestAttributeSet attributes;
3659                 attributes = new HashPrintRequestAttributeSet();
3660                 try {
3661                         PrinterJob job = PrinterJob.getPrinterJob();
3662                         // job.setPrintable(this);
3663                         if (job.printDialog(attributes)) {
3664                                 job.print(attributes);
3665                         }
3666                 } catch (PrinterException exception) {
3667                         errorDialog(exception);
3668                 }
3669         }
3670
3671         /**
3672          * Checks whether errors are to be displayed
3673          * 
3674          * @return Error display status
3675          */
3676         public boolean isErrorsOn() {
3677                 return _conf._errorsOn;
3678         }
3679
3680         /**
3681          * Sets whether errors are to be displayed
3682          * 
3683          * @param on
3684          *            New error display status
3685          */
3686         public void setErrorsOn(boolean on) {
3687                 _conf._errorsOn = on;
3688         }
3689
3690         /**
3691          * Returns the view associated with user interactions
3692          * 
3693          * @return A view associated with user interactions
3694          */
3695         public VueUI getVARNAUI() {
3696                 return _UI;
3697         }
3698
3699         /**
3700          * Toggles on/off using base inner color for drawing base-pairs
3701          * 
3702          * @param on
3703          *            True for using base inner color for drawing base-pairs, false
3704          *            for classic mode
3705          */
3706         public void setUseBaseColorsForBPs(boolean on) {
3707                 _conf._useBaseColorsForBPs = on;
3708         }
3709
3710         /**
3711          * Returns true if current base color is used as inner color for drawing
3712          * base-pairs
3713          * 
3714          * @return True for using base inner color for drawing base-pairs, false for
3715          *         classic mode
3716          */
3717         public boolean getUseBaseColorsForBPs() {
3718                 return _conf._useBaseColorsForBPs;
3719         }
3720
3721         /**
3722          * Toggles on/off using a special color used for drawing "non-standard"
3723          * bases
3724          * 
3725          * @param on
3726          *            True for using a special color used for drawing "non-standard"
3727          *            bases, false for classic mode
3728          */
3729         public void setColorNonStandardBases(boolean on) {
3730                 _conf._colorSpecialBases = on;
3731         }
3732
3733         /**
3734          * Returns true if a special color is used as inner color for non-standard
3735          * base
3736          * 
3737          * @return True for using a special color used for drawing "non-standard"
3738          *         bases, false for classic mode
3739          */
3740         public boolean getColorSpecialBases() {
3741                 return _conf._colorSpecialBases;
3742         }
3743
3744         /**
3745          * Toggles on/off using a special color used for drawing "Gaps" bases in
3746          * comparison mode
3747          * 
3748          * @param on
3749          *            True for using a special color used for drawing "Gaps" bases
3750          *            in comparison mode, false for classic mode
3751          */
3752         public void setColorGapsBases(boolean on) {
3753                 _conf._colorDashBases = on;
3754         }
3755
3756         /**
3757          * Returns true if a special color is used for drawing "Gaps" bases in
3758          * comparison mode
3759          * 
3760          * @return True for using a special color used for drawing "Gaps" bases in
3761          *         comparison mode, false for classic mode
3762          */
3763         public boolean getColorGapsBases() {
3764                 return _conf._colorDashBases;
3765         }
3766
3767         /**
3768          * Toggles on/off displaying warnings
3769          * 
3770          * @param on
3771          *            True to display warnings, false otherwise
3772          */
3773         public void setShowWarnings(boolean on) {
3774                 _conf._showWarnings = on;
3775         }
3776
3777         /**
3778          * Get current warning display status
3779          * 
3780          * @return True to display warnings, false otherwise
3781          */
3782         public boolean getShowWarnings() {
3783                 return _conf._showWarnings;
3784         }
3785
3786         /**
3787          * Toggles on/off displaying non-canonical base-pairs
3788          * 
3789          * @param on
3790          *            True to display NC base-pairs, false otherwise
3791          */
3792         public void setShowNonCanonicalBP(boolean on) {
3793                 _conf._drawnNonCanonicalBP = on;
3794         }
3795
3796         /**
3797          * Return the current display status for non-canonical base-pairs
3798          * 
3799          * @return True if NC base-pairs are displayed, false otherwise
3800          */
3801         public boolean getShowNonCanonicalBP() {
3802                 return _conf._drawnNonCanonicalBP;
3803         }
3804
3805         /**
3806          * Toggles on/off displaying "non-planar" base-pairs
3807          * 
3808          * @param on
3809          *            True to display "non-planar" base-pairs, false otherwise
3810          */
3811         public void setShowNonPlanarBP(boolean on) {
3812                 _conf._drawnNonPlanarBP = on;
3813         }
3814
3815         /**
3816          * Return the current display status for non-planar base-pairs
3817          * 
3818          * @return True if non-planars base-pairs are displayed, false otherwise
3819          */
3820         public boolean getShowNonPlanarBP() {
3821                 return _conf._drawnNonPlanarBP;
3822         }
3823
3824         /**
3825          * Sets the base-pair representation style
3826          * 
3827          * @param st
3828          *            The new base-pair style
3829          */
3830         public void setBPStyle(VARNAConfig.BP_STYLE st) {
3831                 _conf._mainBPStyle = st;
3832         }
3833
3834         /**
3835          * Returns the base-pair representation style
3836          * 
3837          * @return The current base-pair style
3838          */
3839         public VARNAConfig.BP_STYLE getBPStyle() {
3840                 return _conf._mainBPStyle;
3841         }
3842
3843         /**
3844          * Returns the current VARNA Panel configuration. The returned instance
3845          * should not be modified directly, but rather through the getters/setters
3846          * from the VARNAPanel class.
3847          * 
3848          * @return Current configuration
3849          */
3850         public VARNAConfig getConfig() {
3851                 return _conf;
3852         }
3853
3854         /**
3855          * Sets the background color
3856          * 
3857          * @param c
3858          *            New background color
3859          */
3860         public void setBackground(Color c) {
3861                 if (_conf != null) {
3862                         if (c != null) {
3863                                 _conf._backgroundColor = c;
3864                                 _conf._drawBackground = (!c
3865                                                 .equals(VARNAConfig.DEFAULT_BACKGROUND_COLOR));
3866                         } else {
3867                                 _conf._backgroundColor = VARNAConfig.DEFAULT_BACKGROUND_COLOR;
3868                                 _conf._drawBackground = false;
3869                         }
3870                 }
3871
3872         }
3873
3874         /**
3875          * Starts highlighting the selected base.
3876          */
3877         public void highlightSelectedBase(ModeleBase m) {
3878                 ArrayList<Integer> v = new ArrayList<Integer>();
3879                 int sel = m.getIndex();
3880                 if (sel != -1) {
3881                         v.add(sel);
3882                 }
3883                 setSelection(v);
3884         }
3885
3886         /**
3887          * Starts highlighting the selected base.
3888          */
3889         public void highlightSelectedStem(ModeleBase m) {
3890                 ArrayList<Integer> v = new ArrayList<Integer>();
3891                 int sel = m.getIndex();
3892                 if (sel != -1) {
3893                         ArrayList<Integer> r = _RNA.findStem(sel);
3894                         v.addAll(r);
3895                 }
3896                 setSelection(v);
3897         }
3898
3899         public BaseList getSelection() {
3900                 return _selectedBases;
3901         }
3902
3903         public ArrayList<Integer> getSelectionIndices() {
3904                 return _selectedBases.getIndices();
3905         }
3906
3907         public void setSelection(ArrayList<Integer> indices) {
3908                 setSelection(_RNA.getBasesAt(indices));
3909         }
3910
3911         public void setSelection(Collection<? extends ModeleBase> mbs) {
3912                 BaseList bck = new BaseList(_selectedBases);
3913                 _selectedBases.clear();
3914                 _selectedBases.addBases(mbs);
3915                 _blink.setActive(true);
3916                 fireSelectionChanged(bck, _selectedBases);
3917         }
3918
3919         public ArrayList<Integer> getBasesInRectangleDiff(Rectangle recIn,
3920                         Rectangle recOut) {
3921                 ArrayList<Integer> result = new ArrayList<Integer>();
3922                 for (int i = 0; i < _realCoords.length; i++) {
3923                         if (recIn.contains(_realCoords[i])
3924                                         ^ recOut.contains(_realCoords[i]))
3925                                 result.add(i);
3926                 }
3927                 return result;
3928         }
3929
3930         public ArrayList<Integer> getBasesInRectangle(Rectangle rec) {
3931                 ArrayList<Integer> result = new ArrayList<Integer>();
3932                 for (int i = 0; i < _realCoords.length; i++) {
3933                         if (rec.contains(_realCoords[i]))
3934                                 result.add(i);
3935                 }
3936                 return result;
3937         }
3938
3939         public void setSelectionRectangle(Rectangle rec) {
3940                 ArrayList<Integer> result = new ArrayList<Integer>();
3941                 if (_selectionRectangle != null) {
3942                         result = getBasesInRectangleDiff(_selectionRectangle, rec);
3943                 } else {
3944                         result = getBasesInRectangle(rec);
3945                 }
3946                 _selectionRectangle = new Rectangle(rec);
3947                 toggleSelection(result);
3948                 repaint();
3949         }
3950
3951         public void removeSelectionRectangle() {
3952                 _selectionRectangle = null;
3953         }
3954
3955         public void addToSelection(Collection<? extends Integer> indices) {
3956                 for (int i : indices) {
3957                         addToSelection(i);
3958                 }
3959         }
3960
3961         public void addToSelection(int i) {
3962                 BaseList bck = new BaseList(_selectedBases);
3963                 ModeleBase mb = _RNA.getBaseAt(i);
3964                 _selectedBases.addBase(mb);
3965                 _blink.setActive(true);
3966                 fireSelectionChanged(bck, _selectedBases);
3967         }
3968
3969         public void removeFromSelection(int i) {
3970                 BaseList bck = new BaseList(_selectedBases);
3971                 ModeleBase mb = _RNA.getBaseAt(i);
3972                 _selectedBases.removeBase(mb);
3973                 if (_selectedBases.size() == 0) {
3974                         _blink.setActive(false);
3975                 } else {
3976                         _blink.setActive(true);
3977                 }
3978                 fireSelectionChanged(bck, _selectedBases);
3979         }
3980
3981         public boolean isInSelection(int i) {
3982                 return _selectedBases.contains(_RNA.getBaseAt(i));
3983         }
3984
3985         public void toggleSelection(int i) {
3986                 if (isInSelection(i))
3987                         removeFromSelection(i);
3988                 else
3989                         addToSelection(i);
3990         }
3991
3992         public void toggleSelection(Collection<? extends Integer> indices) {
3993                 for (int i : indices) {
3994                         toggleSelection(i);
3995                 }
3996         }
3997
3998         /**
3999          * Stops highlighting bases
4000          */
4001         public void clearSelection() {
4002                 BaseList bck = new BaseList(_selectedBases);
4003                 _selectedBases.clear();
4004                 _blink.setActive(false);
4005                 repaint();
4006                 fireSelectionChanged(bck, _selectedBases);
4007         }
4008
4009         public void saveSelection() {
4010                 _backupSelection.clear();
4011                 _backupSelection.addAll(_selectedBases.getBases());
4012         }
4013
4014         public void restoreSelection() {
4015                 setSelection(_backupSelection);
4016         }
4017
4018         /**
4019          * Stops highlighting bases
4020          */
4021         public void resetAnnotationHighlight() {
4022                 _highlightAnnotation = false;
4023                 repaint();
4024         }
4025
4026         /**
4027          * Toggles on/off a rectangular outline of the bounding box.
4028          * 
4029          * @param on
4030          *            True to draw the bounding box, false otherwise
4031          */
4032         public void drawBBox(boolean on) {
4033                 _drawBBox = on;
4034         }
4035
4036         /**
4037          * Toggles on/off a rectangular outline of the border.
4038          * 
4039          * @param on
4040          *            True to draw the bounding box, false otherwise
4041          */
4042         public void drawBorder(boolean on) {
4043                 _drawBorder = on;
4044         }
4045
4046         public void setBaseInnerColor(Color c) {
4047                 _RNA.setBaseInnerColor(c);
4048         }
4049
4050         public void setBaseNumbersColor(Color c) {
4051                 _RNA.setBaseNumbersColor(c);
4052         }
4053
4054         public void setBaseNameColor(Color c) {
4055                 _RNA.setBaseNameColor(c);
4056         }
4057
4058         public void setBaseOutlineColor(Color c) {
4059                 _RNA.setBaseOutlineColor(c);
4060         }
4061
4062         public ArrayList<TextAnnotation> getListeAnnotations() {
4063                 return _RNA.getAnnotations();
4064         }
4065
4066         public void resetListeAnnotations() {
4067                 _RNA.clearAnnotations();
4068                 repaint();
4069         }
4070
4071         public void addAnnotation(TextAnnotation textAnnotation) {
4072                 _RNA.addAnnotation(textAnnotation);
4073                 repaint();
4074         }
4075
4076         public boolean removeAnnotation(TextAnnotation textAnnotation) {
4077                 boolean done = _RNA.removeAnnotation(textAnnotation);
4078                 repaint();
4079                 return done;
4080         }
4081
4082         public TextAnnotation get_selectedAnnotation() {
4083                 return _selectedAnnotation;
4084         }
4085
4086         public void set_selectedAnnotation(TextAnnotation annotation) {
4087                 _selectedAnnotation = annotation;
4088         }
4089
4090         public void removeSelectedAnnotation() {
4091                 _highlightAnnotation = false;
4092                 _selectedAnnotation = null;
4093         }
4094
4095         public void highlightSelectedAnnotation() {
4096                 _highlightAnnotation = true;
4097         }
4098
4099         public boolean getFlatExteriorLoop() {
4100                 return _conf._flatExteriorLoop;
4101         }
4102
4103         public void setFlatExteriorLoop(boolean on) {
4104                 _conf._flatExteriorLoop = on;
4105         }
4106
4107         public void setLastSelectedPosition(Point2D.Double p) {
4108                 _lastSelectedCoord.x = p.x;
4109                 _lastSelectedCoord.y = p.y;
4110         }
4111
4112         public Point2D.Double getLastSelectedPosition() {
4113                 return _lastSelectedCoord;
4114         }
4115
4116         public void setSequence(String s) {
4117                 _RNA.setSequence(s);
4118                 repaint();
4119         }
4120
4121         public void setColorMapVisible(boolean b) {
4122                 _conf._drawColorMap = b;
4123                 repaint();
4124         }
4125
4126         public boolean getColorMapVisible() {
4127                 return _conf._drawColorMap;
4128         }
4129
4130         public void removeColorMap() {
4131                 _conf._drawColorMap = false;
4132                 repaint();
4133         }
4134
4135         public void saveSession(String path) {
4136                 /*
4137                  * FileOutputStream fos = null; ObjectOutputStream out = null; try { fos
4138                  * = new FileOutputStream(path); out = new ObjectOutputStream(fos);
4139                  * out.writeObject(new FullBackup(_conf, _RNA, _conf._title));
4140                  * out.close(); } catch (Exception ex) { ex.printStackTrace(); }
4141                  */
4142                 toXML(path);
4143         }
4144
4145         public FullBackup loadSession(String path) throws ExceptionLoadingFailed { 
4146           return loadSession(new File(path));
4147         }
4148         public FullBackup loadSession(File path) throws ExceptionLoadingFailed {
4149
4150                 FullBackup bck = importSession(path);
4151                 Mapping map = Mapping.DefaultOutermostMapping(getRNA().getSize(),
4152                                 bck.rna.getSize());
4153                 showRNAInterpolated(bck.rna, map);
4154                 _conf = bck.config;
4155                 repaint();
4156                 return bck;
4157         }
4158
4159         public static String VARNA_SESSION_EXTENSION = "varna";
4160
4161         public static FullBackup importSession(Object path) // BH was String
4162                         throws ExceptionLoadingFailed {
4163                 try {
4164                         FileInputStream fis = (path instanceof File ? new FileInputStream((File) path) : new FileInputStream(path.toString()));
4165                         // ZipInputStream zis = new
4166                         // ZipInputStream(new BufferedInputStream(fis));
4167                         // zis.getNextEntry();
4168                         FullBackup h = importSession(fis, path.toString());
4169                         // zis.close();
4170                         return h;
4171                 } catch (FileNotFoundException e) {
4172                         throw (new ExceptionLoadingFailed("File not found.", path.toString()));
4173                 } catch (IOException e) {
4174                         // TODO Auto-generated catch block
4175                         throw (new ExceptionLoadingFailed(
4176                                         "I/O error while loading session.", path.toString()));
4177                 }
4178         }
4179
4180         public static FullBackup importSession(InputStream fis, String path)
4181                         throws ExceptionLoadingFailed {
4182                 System.setProperty("javax.xml.parsers.SAXParserFactory",
4183                                 "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
4184                 SAXParserFactory saxFact = javax.xml.parsers.SAXParserFactory
4185                                 .newInstance();
4186                 saxFact.setValidating(false);
4187                 saxFact.setXIncludeAware(false);
4188                 saxFact.setNamespaceAware(false);
4189                 try {
4190                         SAXParser sp = saxFact.newSAXParser();
4191                         VARNASessionParser sessionData = new VARNASessionParser();
4192                         sp.parse(fis, sessionData);
4193                         FullBackup res = new FullBackup(sessionData.getVARNAConfig(),
4194                                         sessionData.getRNA(), "test"); 
4195                         return res;
4196                 } catch (ParserConfigurationException e) {
4197                         throw new ExceptionLoadingFailed("Bad XML parser configuration",
4198                                         path);
4199                 } catch (SAXException e) {
4200                         throw new ExceptionLoadingFailed("XML parser Exception", path);
4201                 } catch (IOException e) {
4202                         throw new ExceptionLoadingFailed("I/O error", path);
4203                 }
4204         }
4205
4206         public void loadFile(File path) {
4207                 loadFile(path, false);
4208         }
4209
4210         public boolean getDrawBackbone() {
4211                 return _conf._drawBackbone;
4212         }
4213
4214         public void setDrawBackbone(boolean b) {
4215                 _conf._drawBackbone = b;
4216         }
4217
4218         public void addHighlightRegion(HighlightRegionAnnotation n) {
4219                 _RNA.addHighlightRegion(n);
4220         }
4221
4222         public void removeHighlightRegion(HighlightRegionAnnotation n) {
4223                 _RNA.removeHighlightRegion(n);
4224         }
4225
4226         public void addHighlightRegion(int i, int j) {
4227                 _RNA.addHighlightRegion(i, j);
4228         }
4229
4230         public void addHighlightRegion(int i, int j, Color fill, Color outline,
4231                         double radius) {
4232                 _RNA.addHighlightRegion(i, j, fill, outline, radius);
4233         }
4234         
4235         public void loadRNA(String path) {
4236                 loadRNA(path, false);
4237         }
4238         
4239         public void loadRNA(Object path, boolean interpolate) { // BH was String
4240                 try {
4241                         Collection<RNA> rnas = (path instanceof File ? RNAFactory.loadSecStr(new FileReader((File) path)) : RNAFactory.loadSecStr(path.toString()));
4242                         if (rnas.isEmpty()) {
4243                                 throw new ExceptionFileFormatOrSyntax(
4244                                                 "No RNA could be parsed from that source.");
4245                         }
4246                         RNA rna = rnas.iterator().next();
4247                         try {
4248                                 rna.drawRNA(_conf);
4249                         } catch (ExceptionNAViewAlgorithm e) {
4250                                 e.printStackTrace();
4251                         }
4252                         if (!interpolate) {
4253                                 showRNA(rna);
4254                         } else {
4255                                 this.showRNAInterpolated(rna);
4256                         }
4257
4258                 } catch (FileNotFoundException e) {
4259                         e.printStackTrace();
4260                 } catch (ExceptionFileFormatOrSyntax e) {
4261                         e.printStackTrace();
4262                 } catch (Exception e) {
4263                         e.printStackTrace();
4264                 }
4265         }
4266
4267         public void loadFile(File path, boolean interpolate) { // was String BH StringJS
4268                 try {
4269                         loadSession(path);
4270                 } catch (Exception e1) {
4271                         loadRNA(path, interpolate);
4272                 }
4273         }
4274
4275         public void setConfig(VARNAConfig cfg) {
4276                 _conf = cfg;
4277         }
4278
4279         public void toggleDrawOutlineBases() {
4280                 _conf._drawOutlineBases = !_conf._drawOutlineBases;
4281         }
4282
4283         public void toggleFillBases() {
4284                 _conf._fillBases = !_conf._fillBases;
4285         }
4286
4287         public void setDrawOutlineBases(boolean drawn) {
4288                 _conf._drawOutlineBases = drawn;
4289         }
4290
4291         public void setFillBases(boolean drawn) {
4292                 _conf._fillBases = drawn;
4293         }
4294
4295         public void readValues(Reader r) {
4296                 this._RNA.readValues(r, _conf._cm);
4297         }
4298
4299         public void addVARNAListener(InterfaceVARNAListener v) {
4300                 _VARNAListeners.add(v);
4301         }
4302
4303         public void fireLayoutChanged() {
4304                 for (InterfaceVARNAListener v : _VARNAListeners) {
4305                         v.onStructureRedrawn();
4306                 }
4307         }
4308
4309         public void fireUINewStructure(RNA r) {
4310                 for (InterfaceVARNAListener v : _VARNAListeners) {
4311                         v.onUINewStructure(_conf, r);
4312                 }
4313         }
4314
4315         public void fireZoomLevelChanged(double d) {
4316                 for (InterfaceVARNAListener v : _VARNAListeners) {
4317                         v.onZoomLevelChanged();
4318                 }
4319         }
4320
4321         public void fireTranslationChanged() {
4322                 for (InterfaceVARNAListener v2 : _VARNAListeners) {
4323                         v2.onTranslationChanged();
4324                 }
4325         }
4326
4327         public void addSelectionListener(InterfaceVARNASelectionListener v) {
4328                 _selectionListeners.add(v);
4329         }
4330
4331         public void fireSelectionChanged(BaseList mold, BaseList mnew) {
4332                 BaseList addedBases = mnew.removeAll(mold);
4333                 BaseList removedBases = mold.removeAll(mnew);
4334                 for (InterfaceVARNASelectionListener v2 : _selectionListeners) {
4335                         v2.onSelectionChanged(mnew, addedBases, removedBases);
4336                 }
4337         }
4338
4339         public void fireHoverChanged(ModeleBase mold, ModeleBase mnew) {
4340                 for (InterfaceVARNASelectionListener v2 : _selectionListeners) {
4341                         v2.onHoverChanged(mold, mnew);
4342                 }
4343         }
4344
4345         public void addRNAListener(InterfaceVARNARNAListener v) {
4346                 _RNAListeners.add(v);
4347         }
4348
4349         public void addVARNABasesListener(InterfaceVARNABasesListener l) {
4350                 _basesListeners.add(l);
4351         }
4352
4353         public void fireSequenceChanged(int index, String oldseq, String newseq) {
4354                 for (InterfaceVARNARNAListener v2 : _RNAListeners) {
4355                         v2.onSequenceModified(index, oldseq, newseq);
4356                 }
4357         }
4358
4359         public void fireStructureChanged(Set<ModeleBP> current,
4360                         Set<ModeleBP> addedBasePairs, Set<ModeleBP> removedBasePairs) {
4361                 for (InterfaceVARNARNAListener v2 : _RNAListeners) {
4362                         v2.onStructureModified(current, addedBasePairs, removedBasePairs);
4363                 }
4364         }
4365
4366         public void fireLayoutChanged(
4367                         Hashtable<Integer, Point2D.Double> movedPositions) {
4368                 for (InterfaceVARNARNAListener v2 : _RNAListeners) {
4369                         v2.onRNALayoutChanged(movedPositions);
4370                 }
4371         }
4372
4373         public void fireBaseClicked(ModeleBase mb, MouseEvent me) {
4374                 if (mb != null) {
4375                         for (InterfaceVARNABasesListener v2 : _basesListeners) {
4376                                 v2.onBaseClicked(mb, me);
4377                         }
4378                 }
4379         }
4380
4381         public double getOrientation() {
4382                 return _RNA.getOrientation();
4383         }
4384
4385         public ModeleBase _hoveredBase = null;
4386
4387         public void setHoverBase(ModeleBase m) {
4388                 if (m != _hoveredBase) {
4389                         ModeleBase bck = _hoveredBase;
4390                         _hoveredBase = m;
4391                         repaint();
4392                         fireHoverChanged(bck, m);
4393                 }
4394         }
4395
4396         public void toXML(String path) {
4397                 FileOutputStream fis;
4398                 try {
4399                         fis = new FileOutputStream(path);
4400                         // ZipOutputStream zis = new ZipOutputStream(new
4401                         // BufferedOutputStream(fis));
4402                         // ZipEntry entry = new ZipEntry("VARNASession");
4403                         // zis.putNextEntry(entry);
4404                         PrintWriter pw = new PrintWriter(fis);
4405                         toXML(pw);
4406                         pw.flush();
4407                         // zis.closeEntry();
4408                         // zis.close();
4409                         fis.close();
4410                 } catch (FileNotFoundException e) {
4411                         // TODO Auto-generated catch block
4412                         e.printStackTrace();
4413                 } catch (IOException e) {
4414                         // TODO Auto-generated catch block
4415                         e.printStackTrace();
4416                 }
4417         }
4418
4419         public void toXML(PrintWriter out) {
4420                 try {
4421
4422                         // out = new PrintWriter(System.out);
4423                         StreamResult streamResult = new StreamResult(out);
4424                         SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory
4425                                         .newInstance();
4426                         // SAX2.0 ContentHandler.
4427                         TransformerHandler hd = tf.newTransformerHandler();
4428                         Transformer serializer = hd.getTransformer();
4429                         serializer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
4430                         serializer
4431                                         .setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "users.dtd");
4432                         serializer.setOutputProperty(OutputKeys.INDENT, "yes");
4433                         hd.setResult(streamResult);
4434                         hd.startDocument();
4435                         toXML(hd);
4436                         hd.endDocument();
4437                 } catch (TransformerConfigurationException e) {
4438                         // TODO Auto-generated catch block
4439                         e.printStackTrace();
4440                 } catch (SAXException e) {
4441                         // TODO Auto-generated catch block
4442                         e.printStackTrace();
4443                 }
4444
4445         }
4446
4447         public static String XML_ELEMENT_NAME = "VARNASession";
4448
4449         public void toXML(TransformerHandler hd) throws SAXException {
4450                 AttributesImpl atts = new AttributesImpl();
4451                 hd.startElement("", "", XML_ELEMENT_NAME, atts);
4452                 _RNA.toXML(hd);
4453                 _conf.toXML(hd);
4454                 hd.endElement("", "", XML_ELEMENT_NAME);
4455         }
4456
4457         public TextAnnotation getNearestAnnotation(int x, int y) {
4458                 TextAnnotation t = null;
4459                 if (getListeAnnotations().size() != 0) {
4460                         double dist = Double.MAX_VALUE;
4461                         double d2;
4462                         Point2D.Double position;
4463                         for (TextAnnotation textAnnot : getListeAnnotations()) {
4464                                 // calcul de la distance
4465                                 position = textAnnot.getCenterPosition();
4466                                 position = transformCoord(position);
4467                                 d2 = Math.sqrt(Math.pow((position.x - x), 2)
4468                                                 + Math.pow((position.y - y), 2));
4469                                 // si la valeur est inferieur au minimum actuel
4470                                 if ((dist > d2)
4471                                                 && (d2 < getScaleFactor()
4472                                                                 * ControleurClicMovement.MIN_SELECTION_DISTANCE)) {
4473                                         t = textAnnot;
4474                                         dist = d2;
4475                                 }
4476                         }
4477                 }
4478                 return t;
4479         }
4480
4481         public ModeleBase getNearestBase(int x, int y, boolean always,
4482                         boolean onlyPaired) {
4483                 int i = getNearestBaseIndex(x, y, always, onlyPaired);
4484                 if (i == -1)
4485                         return null;
4486                 return getRNA().get_listeBases().get(i);
4487         }
4488
4489         public ModeleBase getNearestBase(int x, int y) {
4490                 return getNearestBase(x, y, false, false);
4491         }
4492
4493         public int getNearestBaseIndex(int x, int y, boolean always,
4494                         boolean onlyPaired) {
4495                 double d2, dist = Double.MAX_VALUE;
4496                 int mb = -1;
4497                 for (int i = 0; i < getRealCoords().length; i++) {
4498                         if (!onlyPaired
4499                                         || (getRNA().get_listeBases().get(i).getElementStructure() != -1)) {
4500                                 d2 = Math.sqrt(Math.pow((getRealCoords()[i].x - x), 2)
4501                                                 + Math.pow((getRealCoords()[i].y - y), 2));
4502                                 if ((dist > d2)
4503                                                 && ((d2 < getScaleFactor()
4504                                                                 * ControleurClicMovement.MIN_SELECTION_DISTANCE) || always)) {
4505                                         dist = d2;
4506                                         mb = i;
4507                                 }
4508                         }
4509                 }
4510                 return mb;
4511         }
4512
4513         public void globalRescale(double factor) {
4514                 _RNA.rescale(factor);
4515                 fireLayoutChanged();
4516                 repaint();
4517         }
4518
4519         public void setSpaceBetweenBases(double sp) {
4520                 _conf._spaceBetweenBases = sp;
4521         }
4522
4523         public double getSpaceBetweenBases() {
4524                 return _conf._spaceBetweenBases;
4525         }
4526
4527
4528 }