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