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