diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ad8a572
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.classpath
+.project
+.settings
+/distrib
+/lib
+/bin
+**/.DS_Store
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..b348201
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,24 @@
+This product includes software developed by:
+
+ The Plealog Team (http://www.plealog.com)
+ Plealog license is here: http://www.apache.org/licenses/LICENSE-2.0
+ It targets: jgaf
+ Plealog license is here: https://www.gnu.org/licenses/agpl-3.0.txt
+ It targets: pb-core, pb-ui
+
+ The Apache Software Foundation (http://www.apache.org/)
+ Apache license is here: http://www.apache.org/licenses/LICENSE-2.0
+ It targets: commons-xxx, xerces, xmlParser
+
+ The Castor Framework Team (http://castor-data-binding.github.io/castor)
+ Castor license is here: http://castor-data-binding.github.io/castor/about/licenses.html
+ It targets: castor-xml
+
+ The XStream Framework Team (http://x-stream.github.io/):
+ XStream License is here: http://x-stream.github.io/license.html
+ It targets: xstream
+
+ The JGoodies Forms Framework Team (http://www.jgoodies.com/freeware/libraries/forms/).
+ JGoodies license is here: https://opensource.org/licenses/bsd-license.html
+ It targets: forms
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ee7be0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,40 @@
+#BlastViewer
+
+[![License](https://img.shields.io/badge/license-Affero%20GPL%203.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.txt)
+
+##Introduction
+
+This is the BlastViewer Tool. It aims at displaying in a graphical way results from the NCBI BLAST software.
+
+![BlastViewer](doc/BlastViewer.png)
+
+##Requirements
+
+Use a [Java Virtual Machine](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 1.7 (or above) from Oracle.
+
+*Not tested with any other JVM providers but Oracle... so there is no guarantee that the software will work as expected if not using Oracle's JVM.*
+
+##Software use
+
+
+See the Wiki page of this project.
+
+
+##License and dependencies
+
+BlastViewer itself is released under the GNU Affero General Public License, Version 3.0. [AGPL](https://www.gnu.org/licenses/agpl-3.0.txt)
+
+It depends on several thrid-party libraries as stated in the NOTICE.txt file provided with this project.
+
+##Once upon a time was: VisualBlast / KoriBlast
+
+During Summer 2004 I was asking myself how easy it could be to rewrite in Java the original [VisualBlast software](http://www.ncbi.nlm.nih.gov/pubmed/9283755) written in C for the MS-Windows platform.
+
+Actually, the answer was quite immediate: it took me a few days to fully rewrite Visual Blast, thanks to the many libraries available, mostly from Sun MicroSystems and the Apache Software Foundation.
+
+So, during my holidays on Summer 2004, I started a wonderful story: the creation of what would eventually become the [KoriBlast/ngKLAST suite of softwares](http://plealog.com/korilog/product-sheets/ngKLAST.pdf), the founding software of my company, Korilog.
+
+Korilog ceased its activities on June 2015, therefore I decided to release these UI components to the open source community... just in time for Christmas 2016! ;-)
+
+--
+(c) 2003-2016 - Patrick G. Durand
diff --git a/build.xml b/build.xml
new file mode 100755
index 0000000..6e5217a
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ant task to handle BLAST Viewer Tool project.
+
+ compile: compile the code.
+ makedistrib: compile and make release JAR of the BLAST system.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/blastp.xml b/data/blastp.xml
new file mode 100755
index 0000000..02d56e9
--- /dev/null
+++ b/data/blastp.xml
@@ -0,0 +1,596 @@
+
+
+
+ blastp
+ BLASTN 2.4.0+
+ Altschul, Stephen F., Thomas L. Madden, Alejandro A. Schaffer, Jinghui Zhang, Zheng Zhang, Webb Miller, and David J. Lipman (1997), "Gapped BLAST and PSI-BLAST: a new generation of protein database search programs", Nucleic Acids Res. 25:3389-3402.
+ pdb
+ 1_3291
+ P29972 Aquaporin-CHIP
+ 269
+
+
+ BLOSUM62
+ 10
+ 11
+ 1
+ L;
+
+
+
+
+ 1
+ 1_3291
+ P29972 Aquaporin-CHIP
+ 269
+
+
+ 1
+ gi|11514550|pdb|1FQY|A
+ Chain A, Structure Of Aquaporin-1 At 3.8 A Resolution By Electron Crystallography >gi|14278358|pdb|1IH5|A Chain A, Crystal Structure Of Aquaporin-1 >gi|18159033|pdb|1H6I|A Chain A, A Refined Structure Of Human Aquaporin 1
+ 1FQY-A
+ 269
+
+
+ 1
+ 528.094
+ 1359
+ 7.60283e-151
+ 1
+ 269
+ 1
+ 269
+ 0
+ 0
+ 269
+ 269
+ 0
+ 269
+ MASEFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+ MASEFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+ MASEFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+
+
+
+
+ 2
+ gi|20150315|pdb|1J4N|A
+ Chain A, Crystal Structure Of The Aqp1 Water Channel
+ 1J4N-A
+ 271
+
+
+ 1
+ 483.411
+ 1243
+ 2.14755e-137
+ 1
+ 269
+ 1
+ 271
+ 0
+ 0
+ 248
+ 255
+ 2
+ 271
+ MASEFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQT--AVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+ MASEFKKKLFWRAVVAEFLAMILFIFISIGSALGFHYPIKSNQTTGAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISVLRAIMYIIAQCVGAIVATAILSGITSSLPDNSLGLNALAPGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSGPLAIGFSVALGHLLAIDYTGCGINPARSFGSSVITHNFQDHWIFWVGPFIGAALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+ MASEFKKKLFWRAVVAEFLA LF+FISIGSALGF YP+ +NQT AVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQIS+ RA+MYIIAQCVGAIVATAILSGITSSL NSLG N LA GVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGS PLAIG SVALGHLLAIDYTGCGINPARSFGS+VITHNF +HWIFWVGPFIG ALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMKPK
+
+
+
+
+ 3
+ gi|83754265|pdb|2B6O|A
+ Chain A, Electron Crystallographic Structure Of Lens Aquaporin-0 (Aqp0) (Lens Mip) At 1.9a Resolution, In A Closed Pore State
+ 2B6O-A
+ 263
+
+
+ 1
+ 233.802
+ 595
+ 2.96373e-62
+ 4
+ 267
+ 3
+ 259
+ 0
+ 0
+ 117
+ 166
+ 7
+ 264
+ EFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMK
+ ELRSASFWRAIFAEFFATLFYVFFGLGASL--RWAPGPLHV-----LQVALAFGLALATLVQAVGHISGAHVNPAVTFAFLVGSQMSLLRAICYVVAQLLGAVAGAAVLYSVTPPAVRGNLALNTLHPGVSVGQATIVEIFLTLQFVLCIFATYDERRNGRLGSVALAVGFSLTLGHLFGMYYTGAGMNPARSFAPAILTRNFTNHWVYWVGPVIGAGLGSLLYDFLLFPRLKSVSERLSILKGTRPSESNGQPEVTGEPVELK
+ E + FWRA+ AEF AT +VF +G++L ++ G ++V+LAFGL++ATL Q+VGHISGAH+NPAVT L+ Q+S+ RA+ Y++AQ +GA+ A+L +T +L N L GV+ GQ +EI TLQ VLC+ AT D RR GS LA+G S+ LGHL + YTG G+NPARSF A++T NF+NHW++WVGP IG L L+YDF+L PR +++R+ + + E + + VE+K
+
+
+
+
+ 4
+ gi|61680729|pdb|1YMG|A
+ Chain A, The Channel Architecture Of Aquaporin O At 2.2 Angstrom Resolution >gi|83754266|pdb|2B6P|A Chain A, X-Ray Structure Of Lens Aquaporin-0 (Aqp0) (Lens Mip) In An Open Pore State >gi|85544350|pdb|2C32|A Chain A, Co-Axial Association Of Recombinant Eye Lens Aquaporin-0 Observed In Loosely Packed 3d-Crystals
+ 1YMG-A
+ 263
+
+
+ 1
+ 232.261
+ 591
+ 8.62313e-62
+ 4
+ 267
+ 3
+ 259
+ 0
+ 0
+ 116
+ 166
+ 7
+ 264
+ EFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVEMK
+ ELRSASFWRAICAEFFASLFYVFFGLGASL--RWAPGPLHV-----LQVALAFGLALATLVQAVGHISGAHVNPAVTFAFLVGSQMSLLRAICYMVAQLLGAVAGAAVLYSVTPPAVRGNLALNTLHPGVSVGQATIVEIFLTLQFVLCIFATYDERRNGRLGSVALAVGFSLTLGHLFGMYYTGAGMNPARSFAPAILTRNFTNHWVYWVGPVIGAGLGSLLYDFLLFPRLKSVSERLSILKGSRPSESNGQPEVTGEPVELK
+ E + FWRA+ AEF A+ +VF +G++L ++ G ++V+LAFGL++ATL Q+VGHISGAH+NPAVT L+ Q+S+ RA+ Y++AQ +GA+ A+L +T +L N L GV+ GQ +EI TLQ VLC+ AT D RR GS LA+G S+ LGHL + YTG G+NPARSF A++T NF+NHW++WVGP IG L L+YDF+L PR +++R+ + + E + + VE+K
+
+
+
+
+ 5
+ gi|49259096|pdb|1SOR|A
+ Chain A, Aquaporin-0 Membrane Junctions Reveal The Structure Of A Closed Water Pore
+ 1SOR-A
+ 235
+
+
+ 1
+ 230.335
+ 586
+ 3.27678e-61
+ 10
+ 244
+ 5
+ 232
+ 0
+ 0
+ 112
+ 156
+ 7
+ 235
+ FWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKV
+ FWRAIFAEFFATLFYVFFGLGASL--RWAPGPLHV-----LQVALAFGLALATLVQAVGHISGAHVNPAVTFAFLVGSQMSLLRAICYVVAQLLGAVAGAAVLYSVTPPAVRGNLALNTLHPGVSVGQATIVEIFLTLQFVLCIFATYDERRNGRLGSVALAVGFSLTLGHLFGMYYTGAGMNPARSFAPAILTRNFTNHWVYWVGPVIGAGLGSLLYDFLLFPRLKSVSERLSI
+ FWRA+ AEF AT +VF +G++L ++ G ++V+LAFGL++ATL Q+VGHISGAH+NPAVT L+ Q+S+ RA+ Y++AQ +GA+ A+L +T +L N L GV+ GQ +EI TLQ VLC+ AT D RR GS LA+G S+ LGHL + YTG G+NPARSF A++T NF+NHW++WVGP IG L L+YDF+L PR +++R+ +
+
+
+
+
+ 6
+ gi|88192744|pdb|2D57|A
+ Chain A, Double Layered 2d Crystal Structure Of Aquaporin-4 (Aqp4m23) At 3.2 A Resolution By Electron Crystallography
+ 2D57-A
+ 301
+
+
+ 1
+ 220.705
+ 561
+ 2.59635e-58
+ 10
+ 265
+ 12
+ 266
+ 0
+ 0
+ 117
+ 164
+ 7
+ 259
+ FWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYD---LDADDINSRVE
+ FWKAVTAEFLAMLIFVLLSVGSTINWG---GSENPLPVDMVLISLCFGLSIATMVQCFGHISGGHINPAVTVAMVCTRKISIAKSVFYITAQCLGAIIGAGILYLVTPPSVVGGLGVTTVHGNLTAGHGLLVELIITFQLVFTIFASCDSKRTDVTGSVALAIGFSVAIGHLFAINYTGASMNPARSFGPAVIMGNWENHWIYWVGPIIGAVLAGALYEYVFCP-DVELKRRLKEAFSKAAQQTKGSYMEVEDNRSQVE
+ FW+AV AEFLA +FV +S+GS + + G+ D V +SL FGLSIAT+ Q GHISG H+NPAVT+ ++ + +ISI +++ YI AQC+GAI+ IL +T LG + + +G GL +E+I T QLV + A+ D +R D+ GS LAIG SVA+GHL AI+YTG +NPARSFG AVI N+ NHWI+WVGP IG LA +Y+++ P +L R+K S ++ ++ +D S+VE
+
+
+
+
+ 7
+ gi|85544225|pdb|2B5F|A
+ Chain A, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In An Open Conformation To 3.9 Resolution >gi|85544226|pdb|2B5F|B Chain B, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In An Open Conformation To 3.9 Resolution >gi|85544227|pdb|2B5F|C Chain C, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In An Open Conformation To 3.9 Resolution >gi|85544228|pdb|2B5F|D Chain D, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In An Open Conformation To 3.9 Resolution
+ 2B5F-A
+ 303
+
+
+ 1
+ 176.407
+ 446
+ 5.61533e-45
+ 4
+ 265
+ 31
+ 297
+ 0
+ 0
+ 112
+ 159
+ 23
+ 276
+ EFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVK---VSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAI----VATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRR--RD--LGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHN---FSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDLDADDINSRVE
+ ELKLWSFWRAAIAEFIATLLFLYITVATVIGH-----SKETVVCGSVGLLGIAWAFGGMIFVLVYCTAGISGGHINPAVTFGLFLARKVSLLRALVYMIAQCLGAICGVGLVKAFMKGPYNQFGG---GANSVALGYNKGTALGAEIIGTFVLVYTVFSATDPKRSARDSHVPILAPLPIGFAVFMVHLATIPITGTGINPARSFGAAVIFNSNKVWDDQWIFWVGPFIGAAVAAAYHQYVLRAAAIKALGSFRS-NPTNLEQKLISEEDLNSAVD
+ E K FWRA +AEF+AT LF++I++ + +G + +T V +V ++ AFG I L ISG H+NPAVT GL L+ ++S+ RAL+Y+IAQC+GAI + A + G + G G N +A G N G LG EIIGT LV V + TD +R RD + APL IG +V + HL I TG GINPARSFG+AVI ++ + + WIFWVGPFIG A+A + ++L + + +E+ + +D+NS V+
+
+
+
+
+ 8
+ gi|85544014|pdb|1Z98|A
+ Chain A, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In A Closed Conformation >gi|85544015|pdb|1Z98|M Chain M, Crystal Structure Of The Spinach Aquaporin Sopip2;1 In A Closed Conformation
+ 1Z98-A
+ 281
+
+
+ 1
+ 175.252
+ 443
+ 1.25097e-44
+ 4
+ 231
+ 31
+ 264
+ 0
+ 0
+ 107
+ 146
+ 22
+ 242
+ EFKKKLFWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVK---VSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAI----VATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRR--RD--LGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHN---FSNHWIFWVGPFIGGALAVLIYDFIL
+ ELKLWSFWRAAIAEFIATLLFLYITVATVIGH-----SKETVVCGSVGLLGIAWAFGGMIFVLVYCTAGISGGHINPAVTFGLFLARKVSLLRALVYMIAQCLGAICGVGLVKAFMKGPYNQFGG---GANSVALGYNKGTALGAEIIGTFVLVYTVFSATDPKRSARDSHVPILAPLPIGFAVFMVHLATIPITGTGINPARSFGAAVIFNSNKVWDDQWIFWVGPFIGAAVAAAYHQYVL
+ E K FWRA +AEF+AT LF++I++ + +G + +T V +V ++ AFG I L ISG H+NPAVT GL L+ ++S+ RAL+Y+IAQC+GAI + A + G + G G N +A G N G LG EIIGT LV V + TD +R RD + APL IG +V + HL I TG GINPARSFG+AVI ++ + + WIFWVGPFIG A+A + ++L
+
+
+
+
+ 9
+ gi|134105082|pdb|2O9D|A
+ Chain A, Crystal Structure Of Aqpz Mutant T183c. >gi|134105083|pdb|2O9D|B Chain B, Crystal Structure Of Aqpz Mutant T183c.
+ 2O9D-A
+ 234
+
+
+ 1
+ 125.561
+ 314
+ 1.13671e-29
+ 11
+ 234
+ 5
+ 233
+ 0
+ 0
+ 85
+ 121
+ 17
+ 235
+ WRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLAD---------GVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFS--NHWIFWVGPFIGGALAVLIYDFILAPR
+ FRKLAAESFGTFWLVFGGSGSAV---LAAGFPELGI-GFAGVALAFGLTVLTMAFAVGHISGGHFNPAVTIGLWAGGRFPAKEVVGYVIAQVVGGIVAAALLYLIASGKTGFDAAASGFASNGYGEHSPGGYSMLSALVVELVLSAGFLLVIHGATDKFAP--AGFAPIAIGLALTLIHLISIPVTNCSVNPARSTAVAIFQGGWALEQLWFFWVVPIVGGIIGGLIYRTLLEKR
+ +R + AE T VF GSA+ G + + V+LAFGL++ T+A +VGHISG H NPAVT+GL + + Y+IAQ VG IVA A+L I S TG + A G + L +E++ + +L + TD+ G AP+AIGL++ L HL++I T C +NPARS A+ ++ W FWV P +GG + LIY +L R
+
+
+
+
+ 10
+ gi|134105084|pdb|2O9E|A
+ Chain A, Crystal Structure Of Aqpz Mutant T183c Complexed With Mercury
+ 2O9E-A
+ 234
+
+
+ 1
+ 125.561
+ 314
+ 1.13671e-29
+ 11
+ 234
+ 5
+ 233
+ 0
+ 0
+ 85
+ 121
+ 17
+ 235
+ WRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLAD---------GVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFS--NHWIFWVGPFIGGALAVLIYDFILAPR
+ FRKLAAESFGTFWLVFGGSGSAV---LAAGFPELGI-GFAGVALAFGLTVLTMAFAVGHISGGHFNPAVTIGLWAGGRFPAKEVVGYVIAQVVGGIVAAALLYLIASGKTGFDAAASGFASNGYGEHSPGGYSMLSALVVELVLSAGFLLVIHGATDKFAP--AGFAPIAIGLALTLIHLISIPVTNCSVNPARSTAVAIFQGGWALEQLWFFWVVPIVGGIIGGLIYRTLLEKR
+ +R + AE T VF GSA+ G + + V+LAFGL++ T+A +VGHISG H NPAVT+GL + + Y+IAQ VG IVA A+L I S TG + A G + L +E++ + +L + TD+ G AP+AIGL++ L HL++I T C +NPARS A+ ++ W FWV P +GG + LIY +L R
+
+
+
+
+ 11
+ gi|39654847|pdb|1RC2|B
+ Chain B, 2.5 Angstrom Resolution X-Ray Structure Of Aquaporin Z >gi|39654848|pdb|1RC2|A Chain A, 2.5 Angstrom Resolution X-Ray Structure Of Aquaporin Z >gi|78101284|pdb|2ABM|A Chain A, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101285|pdb|2ABM|B Chain B, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101286|pdb|2ABM|C Chain C, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101287|pdb|2ABM|D Chain D, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101288|pdb|2ABM|E Chain E, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101289|pdb|2ABM|F Chain F, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101290|pdb|2ABM|G Chain G, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels >gi|78101291|pdb|2ABM|H Chain H, Crystal Structure Of Aquaporin Z Tetramer Reveals Both Open And Closed Water-Conducting Channels
+ 1RC2-B
+ 231
+
+
+ 1
+ 122.094
+ 305
+ 1.25678e-28
+ 11
+ 234
+ 2
+ 230
+ 0
+ 0
+ 84
+ 120
+ 17
+ 235
+ WRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLAD---------GVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFS--NHWIFWVGPFIGGALAVLIYDFILAPR
+ FRKLAAECFGTFWLVFGGCGSAV---LAAGFPELGI-GFAGVALAFGLTVLTMAFAVGHISGGHFNPAVTIGLWAGGRFPAKEVVGYVIAQVVGGIVAAALLYLIASGKTGFDAAASGFASNGYGEHSPGGYSMLSALVVELVLSAGFLLVIHGATDKFAP--AGFAPIAIGLALTLIHLISIPVTNTSVNPARSTAVAIFQGGWALEQLWFFWVVPIVGGIIGGLIYRTLLEKR
+ +R + AE T VF GSA+ G + + V+LAFGL++ T+A +VGHISG H NPAVT+GL + + Y+IAQ VG IVA A+L I S TG + A G + L +E++ + +L + TD+ G AP+AIGL++ L HL++I T +NPARS A+ ++ W FWV P +GG + LIY +L R
+
+
+
+
+ 12
+ gi|134105085|pdb|2O9F|A
+ Chain A, Crystal Structure Of Aqpz Mutant L170c >gi|134105086|pdb|2O9F|B Chain B, Crystal Structure Of Aqpz Mutant L170c >gi|134105087|pdb|2O9G|A Chain A, Crystal Structure Of Aqpz Mutant L170c Complexed With Mercury.
+ 2O9F-A
+ 234
+
+
+ 1
+ 120.939
+ 302
+ 2.79982e-28
+ 11
+ 234
+ 5
+ 233
+ 0
+ 0
+ 84
+ 119
+ 17
+ 235
+ WRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLAD---------GVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVITHNFS--NHWIFWVGPFIGGALAVLIYDFILAPR
+ FRKLAAESFGTFWLVFGGSGSAV---LAAGFPELGI-GFAGVALAFGLTVLTMAFAVGHISGGHFNPAVTIGLWAGGRFPAKEVVGYVIAQVVGGIVAAALLYLIASGKTGFDAAASGFASNGYGEHSPGGYSMLSALVVELVLSAGFLLVIHGATDKFAP--AGFAPIAIGLACTLIHLISIPVTNTSVNPARSTAVAIFQGGWALEQLWFFWVVPIVGGIIGGLIYRTLLEKR
+ +R + AE T VF GSA+ G + + V+LAFGL++ T+A +VGHISG H NPAVT+GL + + Y+IAQ VG IVA A+L I S TG + A G + L +E++ + +L + TD+ G AP+AIGL+ L HL++I T +NPARS A+ ++ W FWV P +GG + LIY +L R
+
+
+
+
+ 13
+ gi|83754991|pdb|2EVU|A
+ Chain A, Crystal Structure Of Aquaporin Aqpm At 2.3a Resolution >gi|83755033|pdb|2F2B|A Chain A, Crystal Structure Of Integral Membrane Protein Aquaporin Aqpm At 1.68a Resolution
+ 2EVU-A
+ 246
+
+
+ 1
+ 94.7449
+ 234
+ 2.14872e-20
+ 15
+ 230
+ 9
+ 243
+ 0
+ 0
+ 73
+ 118
+ 25
+ 238
+ VAEFLATTLFVFISIGSALGFKYPVGNNQTA-------------VQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAIL---SGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAVI------THNFSNHWIFWVGPFIGGALAVLIYDFI
+ IAEFIGTFILVFFGAGSA-AVTLMIASGGTSPNPFNIGIGLLGGLGDWVAIGLAFGFAIAASIYALGNISGCHINPAVTIGLWSVKKFPGREVVPYIIAQLLGAAFGSFIFLQCAGIGAATVG-GLGATAPFPGISYWQAMLAEVVGTFLLMITIMGIAVDERAP-KGFAGIIIGLTVAGIITTLGNISGSSLNPARTFGPYLNDMIFAGTDLWNYYSIYVIGPIVGAVLAALTYQYL
+ +AEF+ T + VF GSA + + T+ + D V + LAFG +IA ++G+ISG H+NPAVT+GL + + YIIAQ +GA + I +GI ++ G LG G++ Q + E++GT L++ ++ R G A + IGL+VA + +G +NPAR+FG + T ++ + I+ +GP +G LA L Y ++
+
+
+ 2
+ 50.0618
+ 118
+ 6.06945e-07
+ 10
+ 117
+ 143
+ 245
+ 0
+ 0
+ 34
+ 57
+ 15
+ 113
+ FWRAVVAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRAL-----MYIIAQCVGAIVATAILSGITS
+ YWQAMLAEVVGTFLLMITIMGIAVDERAPKG----------FAGIIIGLTVAGIITTLGNISGSSLNPARTFGPYLNDMIFAGTDLWNYYSIYVIGPIVGAVLAALTYQYLTS
+ +W+A++AE + T L + +G A+ + P G + GL++A + ++G+ISG+ LNPA T G L+ I L +Y+I VGA++A +TS
+
+
+
+
+ 14
+ gi|21466057|pdb|1LDF|A
+ Chain A, Crystal Structure Of The E. Coli Glycerol Facilitator (Glpf) Mutation W48f, F200t
+ 1LDF-A
+ 281
+
+
+ 1
+ 82.0333
+ 201
+ 1.44128e-16
+ 15
+ 201
+ 12
+ 212
+ 0
+ 0
+ 65
+ 93
+ 24
+ 206
+ VAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGI----------TSSLTGNSLGRNDLA--------DGVNSGQGLGIEIIGTLQLVLCVLATTDRRRR-DLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAV
+ IAEFLGTGLLIFFGVGCVAALKVA-----GASFGQWEISVIFGLGVAMAIYLTAGVSGAHLNPAVTIALWLFACFDKRKVIPFIVSQVAGAFCAAALVYGLYYNLFFDFEQTHHIVRGSVESVDLAGTFSTYPNPHINFVQAFAVEMVITAILMGLILALTDDGNGVPRGPLAPLLIGLLIAVIGASMGPLTGTAMNPARDFGPKV
+ +AEFL T L +F +G K A ++S+ FGL +A +SGAHLNPAVT+ L L + + +I++Q GA A A++ G+ T + S+ DLA +N Q +E++ T L+ +LA TD G APL IGL +A+ TG +NPAR FG V
+
+
+
+
+ 15
+ gi|11514194|pdb|1FX8|A
+ Chain A, Crystal Structure Of The E. Coli Glycerol Facilitator (Glpf) With Substrate Glycerol >gi|21466052|pdb|1LDA|A Chain A, Crystal Structure Of The E. Coli Glycerol Facilitator (Glpf) Without Substrate Glycerol >gi|21466058|pdb|1LDI|A Chain A, Crystal Structure Of The E. Coli Glycerol Facilitator (Glpf) Without Substrate Glycerol
+ 1FX8-A
+ 281
+
+
+ 1
+ 79.7221
+ 195
+ 7.15301e-16
+ 15
+ 201
+ 12
+ 212
+ 0
+ 0
+ 64
+ 93
+ 24
+ 206
+ VAEFLATTLFVFISIGSALGFKYPVGNNQTAVQDNVKVSLAFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGI----------TSSLTGNSLGRNDLA--------DGVNSGQGLGIEIIGTLQLVLCVLATTDRRRR-DLGGSAPLAIGLSVALGHLLAIDYTGCGINPARSFGSAV
+ IAEFLGTGLLIFFGVGCVAALKVA-----GASFGQWEISVIWGLGVAMAIYLTAGVSGAHLNPAVTIALWLFACFDKRKVIPFIVSQVAGAFCAAALVYGLYYNLFFDFEQTHHIVRGSVESVDLAGTFSTYPNPHINFVQAFAVEMVITAILMGLILALTDDGNGVPRGPLAPLLIGLLIAVIGASMGPLTGFAMNPARDFGPKV
+ +AEFL T L +F +G K A ++S+ +GL +A +SGAHLNPAVT+ L L + + +I++Q GA A A++ G+ T + S+ DLA +N Q +E++ T L+ +LA TD G APL IGL +A+ TG +NPAR FG V
+
+
+
+
+ 16
+ gi|82407721|pdb|2A9M|L
+ Chain L, Structural Analysis Of A Tight-Binding Fluorescein-Scfv; Apo Form >gi|82407723|pdb|2A9M|M Chain M, Structural Analysis Of A Tight-Binding Fluorescein-Scfv; Apo Form >gi|82407725|pdb|2A9N|L Chain L, A Mutation Designed To Alter Crystal Packing Permits Structural Analysis Of A Tight-Binding Fluorescein-Scfv Complex >gi|82407727|pdb|2A9N|M Chain M, A Mutation Designed To Alter Crystal Packing Permits Structural Analysis Of A Tight-Binding Fluorescein-Scfv Complex
+ 2A9M-L
+ 110
+
+
+ 1
+ 27.335
+ 59
+ 4.21299
+ 203
+ 255
+ 25
+ 75
+ 0
+ 0
+ 16
+ 25
+ 2
+ 53
+ THNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDL
+ TSNIGNNYVSWYQQHPGKAPKLMIYD--VSKRPSGVPDRFSGSKSGNSASLDI
+ T N N+++ W G A ++IYD ++ R S + DR SG D+
+
+
+
+
+ 17
+ gi|56967161|pdb|1XMX|A
+ Chain A, Crystal Structure Of Protein Vc1899 From Vibrio Cholerae
+ 1XMX-A
+ 385
+
+
+ 1
+ 27.335
+ 59
+ 4.21299
+ 23
+ 53
+ 115
+ 145
+ 0
+ 0
+ 12
+ 17
+ 0
+ 31
+ LFVFISIGSALGFKYPVGNNQTAVQDNVKVS
+ IFVVEPNSDCLCWLYPEGNNDTQVQDRITIA
+ +FV L + YP GNN T VQD + ++
+
+
+
+
+ 18
+ gi|42543068|pdb|1NL0|L
+ Chain L, Crystal Structure Of Human Factor Ix Gla Domain In Complex Of An Inhibitory Antibody, 10c12
+ 1NL0-L
+ 213
+
+
+ 1
+ 27.335
+ 59
+ 4.21299
+ 203
+ 255
+ 26
+ 76
+ 0
+ 0
+ 16
+ 25
+ 2
+ 53
+ THNFSNHWIFWVGPFIGGALAVLIYDFILAPRSSDLTDRVKVWTSGQVEEYDL
+ TSNIGNNYVSWYQQHPGKAPKLMIYD--VSKRPSGVPDRFSGSKSGNSASLDI
+ T N N+++ W G A ++IYD ++ R S + DR SG D+
+
+
+
+
+ 19
+ gi|13399662|pdb|1EVY|A
+ Chain A, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase >gi|13399663|pdb|1EVZ|A Chain A, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase In Complex With Nad >gi|21730363|pdb|1JDJ|A Chain A, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase In Complex With 2-Fluoro-6- Chloropurine >gi|27573848|pdb|1M66|A Chain A, Crystal Structure Of Leishmania Mexicana Gpdh Complexed With Inhibitor 2-Bromo-6-Chloro-Purine >gi|27573849|pdb|1M67|A Chain A, Crystal Structure Of Leishmania Mexicana Gpdh Complexed With Inhibitor 2-Bromo-6-Hydroxy-Purine >gi|31615595|pdb|1N1E|A Chain A, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase Complexed With Dhap And Nad >gi|31615596|pdb|1N1E|B Chain B, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase Complexed With Dhap And Nad >gi|38492474|pdb|1N1G|A Chain A, Crystal Structure Of Leishmania Mexicana Glycerol-3- Phosphate Dehydrogenase With Inhibitor Bcp
+ 1EVY-A
+ 366
+
+
+ 1
+ 26.1794
+ 56
+ 9.38556
+ 55
+ 181
+ 155
+ 264
+ 0
+ 0
+ 32
+ 50
+ 17
+ 127
+ AFGLSIATLAQSVGHISGAHLNPAVTLGLLLSCQISIFRALMYIIAQCVGAIVATAILSGITSSLTGNSLGRNDLADGVNSGQGLGIEIIGTLQLVLCVLATTDRRRRDLGGSAPLAIGLSVALGHL
+ SFAIEVATGVFTCVSIASADINVARRLQRIMSTGDRSF--VCWATTDTVGCEVASAV--------------KNVLAIGSGVANGLGMGLNARAALIMRGLLEIRDLTAALGGDGSAVFGLA-GLGDL
+ +F + +AT + I+ A +N A L ++S F + + VG VA+A+ +N LA G GLG+ + L++ L LGG GL+ LG L
+
+
+
+
+
+
+ 30464
+ 6832400
+ 0
+ 0
+ 0.041
+ 0.267
+ 0.14
+
+
+
+
+
+
+
+
+
diff --git a/doc/BlastViewer.png b/doc/BlastViewer.png
new file mode 100644
index 0000000..624f9d5
Binary files /dev/null and b/doc/BlastViewer.png differ
diff --git a/doc/Getting-NCBI-RID.png b/doc/Getting-NCBI-RID.png
new file mode 100644
index 0000000..4a195e1
Binary files /dev/null and b/doc/Getting-NCBI-RID.png differ
diff --git a/jar/BrowserLauncher.jar b/jar/BrowserLauncher.jar
new file mode 100644
index 0000000..35b7615
Binary files /dev/null and b/jar/BrowserLauncher.jar differ
diff --git a/jar/castor-xml-1.1.2.jar b/jar/castor-xml-1.1.2.jar
new file mode 100755
index 0000000..202c8cd
Binary files /dev/null and b/jar/castor-xml-1.1.2.jar differ
diff --git a/jar/commons-configuration-1.10.jar b/jar/commons-configuration-1.10.jar
new file mode 100755
index 0000000..7922436
Binary files /dev/null and b/jar/commons-configuration-1.10.jar differ
diff --git a/jar/commons-io-2.4.jar b/jar/commons-io-2.4.jar
new file mode 100755
index 0000000..90035a4
Binary files /dev/null and b/jar/commons-io-2.4.jar differ
diff --git a/jar/commons-lang-2.6.jar b/jar/commons-lang-2.6.jar
new file mode 100755
index 0000000..98467d3
Binary files /dev/null and b/jar/commons-lang-2.6.jar differ
diff --git a/jar/commons-logging-1.1.jar b/jar/commons-logging-1.1.jar
new file mode 100755
index 0000000..2ff9bbd
Binary files /dev/null and b/jar/commons-logging-1.1.jar differ
diff --git a/jar/forms-1.1.jar b/jar/forms-1.1.jar
new file mode 100755
index 0000000..50c1eb8
Binary files /dev/null and b/jar/forms-1.1.jar differ
diff --git a/jar/jgaf-2.1.1.jar b/jar/jgaf-2.1.1.jar
new file mode 100644
index 0000000..0c30134
Binary files /dev/null and b/jar/jgaf-2.1.1.jar differ
diff --git a/jar/log4j-1.2.14.jar b/jar/log4j-1.2.14.jar
new file mode 100755
index 0000000..6251307
Binary files /dev/null and b/jar/log4j-1.2.14.jar differ
diff --git a/jar/pb-core-5.0.3.jar b/jar/pb-core-5.0.3.jar
new file mode 100644
index 0000000..3c54db0
Binary files /dev/null and b/jar/pb-core-5.0.3.jar differ
diff --git a/jar/pb-ui-5.1.0.jar b/jar/pb-ui-5.1.0.jar
new file mode 100644
index 0000000..1dce6d4
Binary files /dev/null and b/jar/pb-ui-5.1.0.jar differ
diff --git a/jar/xercesImpl-2.7.1.jar b/jar/xercesImpl-2.7.1.jar
new file mode 100755
index 0000000..eac75ae
Binary files /dev/null and b/jar/xercesImpl-2.7.1.jar differ
diff --git a/jar/xmlParserAPIs.jar b/jar/xmlParserAPIs.jar
new file mode 100755
index 0000000..243eaea
Binary files /dev/null and b/jar/xmlParserAPIs.jar differ
diff --git a/jar/xstream.jar b/jar/xstream.jar
new file mode 100755
index 0000000..392e1c9
Binary files /dev/null and b/jar/xstream.jar differ
diff --git a/src/bzh/plealog/blastviewer/BlastViewer.java b/src/bzh/plealog/blastviewer/BlastViewer.java
new file mode 100644
index 0000000..3276bec
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/BlastViewer.java
@@ -0,0 +1,412 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagLayout;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.BasicConfigurator;
+
+import bzh.plealog.bioinfo.api.core.config.CoreSystemConfigurator;
+import bzh.plealog.bioinfo.ui.blast.config.ConfigManager;
+import bzh.plealog.bioinfo.ui.blast.config.color.ColorPolicyConfig;
+import bzh.plealog.bioinfo.ui.config.UISystemConfigurator;
+import bzh.plealog.blastviewer.actions.FetchFromNcbiAction;
+import bzh.plealog.blastviewer.actions.OpenFileAction;
+import bzh.plealog.blastviewer.config.color.ColorPolicyConfigImplem;
+import bzh.plealog.blastviewer.config.directory.DirManager;
+import bzh.plealog.blastviewer.hittable.BVHitTableFactoryImplem;
+import bzh.plealog.blastviewer.resources.BVMessages;
+import bzh.plealog.blastviewer.util.BlastViewerOpener;
+
+import com.plealog.genericapp.api.EZApplicationBranding;
+import com.plealog.genericapp.api.EZEnvironment;
+import com.plealog.genericapp.api.EZGenericApplication;
+import com.plealog.genericapp.api.EZUIStarterListener;
+import com.plealog.genericapp.api.file.EZFileUtils;
+import com.plealog.genericapp.api.log.EZLogger;
+import com.plealog.genericapp.api.log.EZLoggerManager;
+import com.plealog.genericapp.api.log.EZLoggerManager.LogLevel;
+import com.plealog.genericapp.api.log.EZSingleLineFormatter;
+import com.plealog.genericapp.ui.desktop.CascadingWindowPositioner;
+import com.plealog.genericapp.ui.desktop.GDesktopPane;
+import com.plealog.genericapp.ui.desktop.JWindowsMenu;
+
+/**
+ * Starter class for the Blast Viewer software.
+ *
+ * @author Patrick G. Durand
+ */
+public class BlastViewer {
+
+ /**
+ * JVM optional argument. Provide a configuration directory. If not provided,
+ * software locates its resources and configuration files within compiled Java
+ * codes. Sample use: -DV_CONF=./config
+ */
+ private static final String JVM_ARG_CONF = "V_CONF";
+ /**
+ * JVM optional argument. Switch debug mode to true or false. If not provided,
+ * debug mode is disabled. Sample use: -DV_DEBUG=true
+ */
+ public static final String JVM_ARG_DEBUG = "V_DEBUG";
+
+ private static final String LOAD_ERR = "Load Color configuration from: %s";
+ private static final String CONF_ERR = "Unable to load color configuration: ";
+
+ /**
+ * Start application. Relies on the Java Generic Application Framework. See
+ * https://github.com/pgdurand/jGAF
+ */
+ public static void main(String[] args) {
+ // This has to be done at the very beginning, i.e. first method call within
+ // main().
+ EZGenericApplication.initialize("BLASTViewer");
+ // Add application branding
+ Properties props = getVersionProperties();
+ EZApplicationBranding.setAppName(props.getProperty("prg.app.name"));
+ EZApplicationBranding.setAppVersion(props.getProperty("prg.version"));
+ EZApplicationBranding.setCopyRight(props.getProperty("prg.copyright"));
+ EZApplicationBranding.setProviderName(props.getProperty("prg.provider"));
+
+ // setup the logger framework
+ // turn off Java Logging standard console log
+ EZLoggerManager.enableConsoleLogger(false);
+ // turn on UI logger; text size limit is set to 2 million characters (when
+ // content of UI logger reaches that limit, then UI text component simply
+ // reset its content).
+ EZLoggerManager.enableUILogger(true, 2);
+ // delegate LogLevel to software config since JVM argument can be used
+ // to modify standard behavior (see DocViewerConfig.JVM_ARG_DEBUG)
+ initLogLevel();
+ // setup the logging system
+ EZLoggerManager.initialize();
+
+ // some third party libraries rely on log4j (e.g. Castor XML framework)
+ BasicConfigurator.configure();
+
+ // Required to use Plealog Bioinformatics Core objects such as Features,
+ // FeatureTables, Sequences
+ CoreSystemConfigurator.initializeSystem();
+
+ // Required to use the Plealog Bioinformatics UI library (CartoViewer
+ // default graphics)
+ UISystemConfigurator.initializeSystem();
+
+ // we need to know where are located this application resources (messages
+ // and icons)
+ EZEnvironment
+ .addResourceLocator(bzh.plealog.blastviewer.resources.BVMessages.class);
+
+ // we enable the application to automatically serialize application
+ // properties (e.g. column model of the BlastHitTable)
+ ConfigManager.setEnableSerialApplicationProperty(true);
+ // we redirect the factory to use our implementation of a BlastHitTable
+ ConfigManager.setHitTableFactory(new BVHitTableFactoryImplem());
+ // we setup the Directory Manager
+ ConfigManager.addConfig(new DirManager());
+ // we setup the color policy
+ initColorPolicyConfig();
+
+ // Add a listener to application startup cycle (see below)
+ EZEnvironment.setUIStarterListener(new MyStarterListener());
+
+ // Start the application
+ EZGenericApplication.startApplication(args);
+ }
+
+ /**
+ * Set the log level to info or debug. Rely on the JVM argument DV_DEBUG. Use:
+ * -DDV_DEBUG=true.
+ */
+ public static void initLogLevel() {
+ String dbg = System.getProperty(JVM_ARG_DEBUG);
+ if (dbg != null) {
+ EZLoggerManager
+ .setLevel(dbg.toLowerCase().equals("true") ? LogLevel.debug
+ : LogLevel.info);
+ }
+ // set the Formatter of the UI logger: in debug mode, provide full
+ // class/method names
+ EZLoggerManager.setUILoggerFormatter(new EZSingleLineFormatter(
+ EZLoggerManager.getLevel() == LogLevel.debug));
+ }
+
+ /**
+ * Return the software configuration file. By default, there is no such
+ * directory available. Has to be setup using JRM argument: DV_CONF, with
+ * value targeting a directory.
+ */
+ public static String getConfigurationPath() {
+ String confP = System.getProperty(JVM_ARG_CONF);
+
+ if (confP == null)
+ return null;
+
+ return EZFileUtils.terminatePath(confP);
+ }
+
+ /**
+ * Return the content of the version resource.
+ */
+ private static Properties getVersionProperties() {
+ Properties props = new Properties();
+ try (InputStream in = BlastViewer.class
+ .getResourceAsStream("version.properties");) {
+ props.load(in);
+ in.close();
+ } catch (Exception ex) {// should not happen
+ System.err.println("Unable to read props: " + ex.toString());
+ }
+ return props;
+ }
+
+ /**
+ * Initializes colors system.
+ */
+ private static void initColorPolicyConfig() {
+ ColorPolicyConfig nc;
+ FileInputStream fis = null;
+ String confPath;
+ File f;
+ InputStream in = null;
+
+ try {
+ // first, try to locate the file in the user conf dir
+ confPath = getConfigurationPath();
+ if (confPath != null) {
+ confPath += ColorPolicyConfigImplem.CONFIG_FILE_NAME;
+ f = new File(confPath);
+ if (f.exists()) {
+ EZLogger.debug(String.format(LOAD_ERR, f.getAbsolutePath()));
+ in = new FileInputStream(f);
+ }
+ }
+ // try from software resource
+ if (in == null) {
+ EZLogger.debug(String.format(
+ LOAD_ERR,
+ BVMessages.class.getResource(
+ ColorPolicyConfigImplem.CONFIG_FILE_NAME).toString()));
+ in = BVMessages.class
+ .getResourceAsStream(ColorPolicyConfigImplem.CONFIG_FILE_NAME);
+ }
+ // will use default color config
+ if (in == null)
+ return;
+
+ nc = new ColorPolicyConfigImplem(confPath);
+ nc.load(in);
+ // nc.dumpConfig();
+ ConfigManager.addConfig(nc);
+ } catch (Exception ex) {
+ EZLogger.warn(CONF_ERR + ex.toString());
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ }
+
+ /**
+ * Implementation of the jGAF API.
+ */
+ private static class MyStarterListener implements EZUIStarterListener {
+
+ private GDesktopPane _desktop = new GDesktopPane();
+ private Component _mainCompo = null;
+ private JPanel _btnPanel;
+
+ private Component prepareDesktop() {
+ JPanel dpanel, mnuPnl, hlpPnl;
+ JButton logBtn;
+ JWindowsMenu windowsMenu;
+
+ dpanel = new JPanel(new BorderLayout());
+ mnuPnl = new JPanel(new BorderLayout());
+
+ _btnPanel = new JPanel(new BorderLayout());
+
+ JMenuBar menuBar = new JMenuBar();
+ ImageIcon icon = EZEnvironment.getImageIcon("documents.png");
+ if (icon != null) {
+ windowsMenu = new JWindowsMenu(_desktop.getDesktopPane());
+ windowsMenu.setIcon(icon);
+ } else {
+ windowsMenu = new JWindowsMenu(
+ BVMessages.getString("DocumentViewer.docs.mnu"),
+ _desktop.getDesktopPane());
+ }
+ windowsMenu.setWindowPositioner(new CascadingWindowPositioner(_desktop
+ .getDesktopPane()));
+ menuBar.add(windowsMenu);
+
+ logBtn = new JButton(EZEnvironment.getImageIcon("logger.png"));
+ logBtn.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
+ logBtn.addActionListener(new ShowLoggerFrame());
+ logBtn.setVerticalTextPosition(SwingConstants.BOTTOM);
+ logBtn.setHorizontalTextPosition(SwingConstants.CENTER);
+ logBtn.setText("Log");
+
+ windowsMenu.setFont(logBtn.getFont());
+
+ mnuPnl.add(menuBar, BorderLayout.WEST);
+ mnuPnl.add(logBtn, BorderLayout.EAST);
+ _btnPanel.add(mnuPnl, BorderLayout.EAST);
+ hlpPnl = new JPanel(new GridBagLayout());
+ hlpPnl.add(BlastViewerOpener.getHelperField());
+ _btnPanel.add(hlpPnl, BorderLayout.CENTER);
+ _btnPanel.add(getToolbar(), BorderLayout.WEST);
+ dpanel.add(_btnPanel, BorderLayout.NORTH);
+ dpanel.add(_desktop, BorderLayout.CENTER);
+
+ BlastViewerOpener.setDesktop(_desktop);
+
+ return dpanel;
+ }
+
+ @Override
+ public Component getApplicationComponent() {
+ if (_mainCompo != null)
+ return _mainCompo;
+
+ // prepare the desktop viewer system
+ _mainCompo = prepareDesktop();
+
+ return _mainCompo;
+ }
+
+ @Override
+ public boolean isAboutToQuit() {
+ // You can add some code to figure out if application can exit.
+
+ // Return false to prevent application from exiting (e.g. a background
+ // task is still running).
+ // Return true otherwise.
+
+ // Do not add a Quit dialogue box to ask user confirmation: the framework
+ // already does that for you.
+ return true;
+ }
+
+ @Override
+ public void postStart() {
+ // This method is called by the framework just before displaying UI
+ // (main frame).
+ EZLogger.info(String.format("%s - %s",
+ EZApplicationBranding.getAppName(),
+ EZApplicationBranding.getAppVersion()));
+ EZLogger.info(EZApplicationBranding.getCopyRight());
+ try {
+ DirManager dmgr = (DirManager) ConfigManager.getConfig(DirManager.NAME);
+ //EZLogger.info(dmgr.getApplicationDataPath());
+ EZLogger.info("Storage directory is: "+dmgr.getBlastDataPath());
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void preStart() {
+ // This method is called by the framework at the very beginning of
+ // application startup.
+ }
+
+ }
+
+ private static JToolBar getToolbar() {
+ JToolBar tBar;
+ ImageIcon icon;
+ Action act;
+ JButton btn;
+
+ tBar = new JToolBar();
+ tBar.setFloatable(false);
+
+ icon = EZEnvironment.getImageIcon("open.png");
+ if (icon != null) {
+ act = new OpenFileAction("", icon);
+ } else {
+ act = new OpenFileAction(BVMessages.getString("OpenBlastList.open.name"));
+ }
+ act.setEnabled(true);
+ btn = tBar.add(act);
+ btn.setToolTipText(BVMessages.getString("OpenBlastList.open.tip"));
+ btn.setText(BVMessages.getString("OpenBlastList.open.name"));
+
+ icon = EZEnvironment.getImageIcon("download.png");
+ if (icon != null) {
+ act = new FetchFromNcbiAction("", icon);
+ } else {
+ act = new FetchFromNcbiAction(
+ BVMessages.getString("OpenBlastList.openrid.name"));
+ }
+ act.setEnabled(true);
+ btn = tBar.add(act);
+ btn.setToolTipText(BVMessages.getString("OpenBlastList.openrid.tip"));
+ btn.setText(BVMessages.getString("OpenBlastList.openrid.name"));
+ return tBar;
+ }
+
+ /**
+ * Utility class to show the UI Logger component.
+ */
+ private static class ShowLoggerFrame implements ActionListener {
+ private JFrame frame;
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (frame == null) {
+ makeFrame();
+ }
+ frame.setVisible(!frame.isVisible());
+ }
+
+ private void makeFrame() {
+ int delta = 50;
+ frame = new JFrame(BVMessages.getString("DocumentViewer.docs.tab2"));
+ frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+ Rectangle rect = EZEnvironment.getParentFrame().getBounds();
+ rect.x += delta;
+ rect.y += delta;
+ rect.width -= 2 * delta;
+ rect.height -= 2 * delta;
+ frame.getContentPane().add(EZLoggerManager.getUILogger());
+ frame.setBounds(rect);
+ }
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/BlastViewerPanel.java b/src/bzh/plealog/blastviewer/BlastViewerPanel.java
new file mode 100755
index 0000000..9e0404a
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/BlastViewerPanel.java
@@ -0,0 +1,254 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.util.Collections;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import bzh.plealog.bioinfo.api.core.config.CoreSystemConfigurator;
+import bzh.plealog.bioinfo.api.data.feature.Feature;
+import bzh.plealog.bioinfo.api.data.feature.Qualifier;
+import bzh.plealog.bioinfo.api.data.searchresult.SRHsp;
+import bzh.plealog.bioinfo.api.data.searchresult.SROutput;
+import bzh.plealog.bioinfo.api.data.searchresult.SRRequestInfo;
+import bzh.plealog.bioinfo.ui.blast.config.ConfigManager;
+import bzh.plealog.bioinfo.ui.blast.config.color.ColorPolicyConfig;
+import bzh.plealog.bioinfo.ui.blast.config.color.DefaultHitColorPolicy;
+import bzh.plealog.bioinfo.ui.blast.core.BlastEntry;
+import bzh.plealog.bioinfo.ui.blast.core.BlastHitHSP;
+import bzh.plealog.bioinfo.ui.blast.event.BlastHitListSupport;
+import bzh.plealog.bioinfo.ui.blast.hittable.BlastHitTable;
+import bzh.plealog.bioinfo.ui.blast.nav.BlastNavigator;
+import bzh.plealog.bioinfo.ui.blast.saviewer.SeqAlignViewer;
+import bzh.plealog.bioinfo.ui.blast.summary.GraphicViewer;
+import bzh.plealog.bioinfo.ui.carto.data.BasicFeatureOrganizer;
+import bzh.plealog.bioinfo.ui.carto.data.FGraphics;
+import bzh.plealog.bioinfo.ui.carto.data.FeatureOrganizerManager;
+import bzh.plealog.bioinfo.ui.carto.painter.FeaturePainter;
+import bzh.plealog.bioinfo.ui.resources.SVMessages;
+import bzh.plealog.bioinfo.ui.util.JHeadPanel;
+
+import com.plealog.genericapp.api.EZEnvironment;
+
+/**
+ * This is the BlastViewer Main Module.
+ *
+ * It wraps within a single component the various
+ * elements required to displayed Blast data: a BlastNavigator, a Blast Hit Table,
+ * the pairwise sequence alignment viewer, etc.
+ *
+ * @author Patrick G. Durand
+ */
+public class BlastViewerPanel extends JPanel {
+
+ private static final long serialVersionUID = -2405089127382200483L;
+
+ protected BlastHitTable _hitListPane;
+ protected SeqAlignViewer _seqAlignViewer;
+ protected BlastNavigator _summaryPane;
+ protected JPanel _rightPane;
+ protected BlastHitListSupport _updateSupport;
+ protected GraphicViewer _cartoViewer;
+
+ protected static final String HITPANEL_HEADER = SVMessages.getString("BlastViewerPanel.0");
+ protected static final String HITPANEL_LIST = SVMessages.getString("BlastViewerPanel.1");
+ protected static final String HITPANEL_GRAPHIC = SVMessages.getString("BlastViewerPanel.2");
+
+ /**
+ * Default constructor.
+ */
+ public BlastViewerPanel() {
+ super();
+ createGUI();
+ BasicFeatureOrganizer.setFeatureOrganizerManager(new LocalFeatureOrganizerManager());
+ }
+
+ /**
+ * Set the data to display in this viewer.
+ */
+ public void setContent(BlastEntry entry) {
+ _summaryPane.setContent(entry);
+ }
+
+ /**
+ * Set the data to display in this viewer.
+ */
+ public void setContent(SROutput so, String soPath) {
+ _summaryPane.setContent(prepareEntry(so, soPath));
+ }
+
+ /**
+ * Set the data to display in this viewer.
+ */
+ public void setContent(SROutput so) {
+ _summaryPane.setContent(prepareEntry(so, null));
+ }
+
+ /**
+ * Return the Hit currently selected in this BlastViewerPanel. Actually, the
+ * method returns the Hit that is currently displayed by the SeqAlignViewer
+ * panel.
+ */
+ public BlastHitHSP getSelectedHit() {
+ return _seqAlignViewer.getCurrentHit();
+ }
+
+ /**
+ * Return the HSP currently selected in this BlastViewerPanel. Actually, the
+ * method returns the HSP that is currently displayed by the SeqAlignViewer
+ * panel.
+ */
+ public SRHsp getSelectedHsp() {
+ return _seqAlignViewer.getCurrentHsp();
+ }
+
+ private BlastEntry prepareEntry(SROutput bo, String soPath) {
+ String val;
+ int pos;
+
+ // analyze SROutput object (i.e. a Blast result) to get:
+ // program name, query name and databank name
+ SRRequestInfo bri = bo.getRequestInfo();
+ Object obj = bri.getValue(SRRequestInfo.PRGM_VERSION_DESCRIPTOR_KEY);
+ if (obj != null) {
+ val = obj.toString();
+ if ((pos = val.indexOf('[')) > 0) {
+ val = val.substring(0, pos - 1);
+ } else {
+ val = obj.toString();
+ }
+ } else {
+ val = null;
+ }
+ String program = val != null ? val : "?";
+ obj = bri.getValue(SRRequestInfo.DATABASE_DESCRIPTOR_KEY);
+ String dbname = obj != null ? obj.toString() : "?";
+ obj = bri.getValue(SRRequestInfo.QUERY_DEF_DESCRIPTOR_KEY);
+ String queryName = obj != null ? obj.toString() : "?";
+
+ return new BlastEntry(program, queryName, soPath, bo, null, dbname, false);
+ }
+
+ private void createGUI() {
+ JHeadPanel headPanel;
+ ImageIcon icon;
+
+ _updateSupport = new BlastHitListSupport();
+ _summaryPane = new BlastNavigator();
+ _hitListPane = ConfigManager.getHitTableFactory().createViewer();
+ _seqAlignViewer = ConfigManager.getSeqAlignViewerFactory().createViewer();
+ icon = EZEnvironment.getImageIcon("hitTable.png");
+ if (icon != null) {
+ headPanel = new JHeadPanel(icon, HITPANEL_HEADER, _hitListPane);
+ } else {
+ headPanel = new JHeadPanel(null, HITPANEL_HEADER, _hitListPane);
+ }
+ headPanel.setToolPanel(_summaryPane);
+ _rightPane = new JPanel(new BorderLayout());
+ // _rightPane.add(_summaryPane, BorderLayout.NORTH);
+ _rightPane.add(headPanel, BorderLayout.CENTER);
+ _rightPane.add(_seqAlignViewer, BorderLayout.SOUTH);
+
+ _cartoViewer = new GraphicViewer();
+
+ JTabbedPane jtp;
+
+ if (EZEnvironment.getOSType() == EZEnvironment.MAC_OS) {
+ jtp = new JTabbedPane(JTabbedPane.LEFT);
+ } else {
+ jtp = new JTabbedPane(JTabbedPane.TOP);
+ }
+ jtp.add("Hit Table", _rightPane);
+ jtp.add("Graphic Summary", _cartoViewer);
+
+ this.setLayout(new BorderLayout());
+ this.add(jtp, BorderLayout.CENTER);
+
+ // listeners to the selection of a new BIteration
+ _summaryPane.addIterationListener(_hitListPane);
+ _summaryPane.addIterationListener(_cartoViewer);
+ // listeners to the change of data model
+ _hitListPane.addHitDataListener(_seqAlignViewer);
+ // listeners to selection within hit tables
+ _hitListPane.registerHitListSupport(_updateSupport);
+ _seqAlignViewer.registerHitListSupport(_updateSupport);
+ _updateSupport.addBlastHitListListener(_hitListPane);
+ _updateSupport.addBlastHitListListener(_seqAlignViewer);
+ this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ }
+
+ private class LocalFeatureOrganizerManager implements FeatureOrganizerManager {
+
+ private ColorPolicyConfig nc;
+ private SRHsp fakeHsp;
+
+ private LocalFeatureOrganizerManager(){
+ nc = (ColorPolicyConfig) ConfigManager.getConfig(ColorPolicyConfig.NAME);
+ fakeHsp = CoreSystemConfigurator.getSRFactory().createBHsp();
+ fakeHsp.setScores(CoreSystemConfigurator.getSRFactory().createBHspScore());
+ }
+
+ private Color getColor(String score) {
+ Color clr = Color.BLACK;
+ int val = (int) Math.round(Double.valueOf(score));
+
+ if (nc == null) {
+ clr = DefaultHitColorPolicy.getColor(val);
+ } else {
+ fakeHsp.getScores().setBitScore(val);
+ clr = nc.getHitColor(fakeHsp, false);
+ }
+ return clr;
+ }
+
+ @Override
+ public String[] getFeatureOrderingNames() {
+ return null;
+ }
+
+ @Override
+ public FGraphics getFGraphics(Feature feat, FGraphics fg) {
+ if (feat.getKey().equals(GraphicViewer.BHIT_FEATURE_TYPE) == false)
+ return null;
+
+ FGraphics fg2 = fg;
+ for (Qualifier qual : Collections.list(feat.enumQualifiers())) {
+ if (qual.getName().equals(GraphicViewer.SCORE_BITS_QUALIFIER)) {
+ fg2 = (FGraphics) fg.clone();
+ fg2.setBackgroundColor(getColor(qual.getValue()));
+ }
+ }
+ return fg2;
+ }
+
+ @Override
+ public FeaturePainter getFeaturePainter(Feature feat, FeaturePainter fp) {
+ return null;
+ }
+
+ @Override
+ public String getReferenceFeatureName() {
+ return null;
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/actions/EditColorPolicyAction.java b/src/bzh/plealog/blastviewer/actions/EditColorPolicyAction.java
new file mode 100755
index 0000000..4c6f6a8
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/actions/EditColorPolicyAction.java
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+import javax.swing.JOptionPane;
+import javax.swing.JTable;
+
+import bzh.plealog.blastviewer.config.color.HitPolicyEditorDialog;
+
+import com.plealog.genericapp.api.EZEnvironment;
+
+/**
+ * This class manages an action to start the Color Policy Editor.
+ *
+ * @author Patrick G. Durand
+ */
+public class EditColorPolicyAction extends AbstractAction {
+ private static final long serialVersionUID = 6933508753277672501L;
+ private JTable _parent;
+
+ public EditColorPolicyAction(String name) {
+ super(name);
+ }
+
+ public EditColorPolicyAction(String name, Icon icon) {
+ super(name, icon);
+ }
+
+ public void setParent(JTable table) {
+ _parent = table;
+ }
+
+ public void actionPerformed(ActionEvent event) {
+ HitPolicyEditorDialog dlg;
+
+ dlg = new HitPolicyEditorDialog(JOptionPane.getFrameForComponent(EZEnvironment.getParentFrame()));
+ dlg.showDlg();
+ _parent.repaint();
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/actions/FetchFromNcbiAction.java b/src/bzh/plealog/blastviewer/actions/FetchFromNcbiAction.java
new file mode 100755
index 0000000..f0f9b9d
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/actions/FetchFromNcbiAction.java
@@ -0,0 +1,165 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.actions;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+import javax.swing.JOptionPane;
+
+import bzh.plealog.bioinfo.api.data.searchresult.SROutput;
+import bzh.plealog.bioinfo.api.data.searchresult.io.SRLoader;
+import bzh.plealog.bioinfo.io.searchresult.SerializerSystemFactory;
+import bzh.plealog.bioinfo.ui.blast.config.ConfigManager;
+import bzh.plealog.blastviewer.BlastViewerPanel;
+import bzh.plealog.blastviewer.client.ncbi.QBlastRetriever;
+import bzh.plealog.blastviewer.config.directory.DirManager;
+import bzh.plealog.blastviewer.resources.BVMessages;
+import bzh.plealog.blastviewer.util.BlastViewerOpener;
+
+import com.plealog.genericapp.api.EZApplicationBranding;
+import com.plealog.genericapp.api.EZEnvironment;
+import com.plealog.genericapp.api.file.EZFileUtils;
+import com.plealog.genericapp.api.log.EZLogger;
+
+/**
+ * This class implements the action used to fetch a Blast results directly from
+ * the NCBI.
+ *
+ * @author Patrick G. Durand
+ */
+public class FetchFromNcbiAction extends AbstractAction {
+ private static final long serialVersionUID = -2654059939053088591L;
+
+ private boolean _fetcherLocked = false;
+
+ /**
+ * Action constructor.
+ *
+ * @param name
+ * the name of the action.
+ */
+ public FetchFromNcbiAction(String name) {
+ super(name);
+ }
+
+ /**
+ * Action constructor.
+ *
+ * @param name
+ * the name of the action.
+ * @param icon
+ * the icon of the action.
+ */
+ public FetchFromNcbiAction(String name, Icon icon) {
+ super(name, icon);
+ }
+
+ public void actionPerformed(ActionEvent event) {
+ String rid;
+ if (_fetcherLocked)
+ return;
+ rid = JOptionPane.showInputDialog(EZEnvironment.getParentFrame(),
+ BVMessages.getString("FetchFromNcbiAction.lbl"),
+ EZApplicationBranding.getAppName(), JOptionPane.QUESTION_MESSAGE);
+ if (rid == null || rid.length() == 0)
+ return;
+ new Fetcher(rid).start();
+ }
+
+ /**
+ * Handle the data retrieval using a separate thread.
+ */
+ private class Fetcher extends Thread {
+ private String _rid;
+
+ public Fetcher(String rid) {
+ _rid = rid;
+ }
+
+ private String chooseFile() {
+ try {
+ DirManager dmgr = (DirManager) ConfigManager.getConfig(DirManager.NAME);
+ return dmgr.getBlastDataPath() + _rid + ".xml";
+ } catch (IOException e) {
+ EZLogger.warn(BVMessages.getString("FetchFromNcbiAction.err2") + e);
+ }
+ return null;
+ }
+
+ public void run() {
+ _fetcherLocked = true;
+
+ QBlastRetriever qRet;
+ File tmpFile, resFile;
+ String resFileStr;
+ boolean bRet;
+
+ // connect to the NCBI
+ BlastViewerOpener.setHelperMessage(BVMessages
+ .getString("FetchFromNcbiAction.msg1"));
+ qRet = new QBlastRetriever();
+ EZEnvironment.setWaitCursor();
+ bRet = qRet.getBlastResult(_rid);
+ EZEnvironment.setDefaultCursor();
+ // error ?
+ if (bRet == false) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(),
+ qRet.getErrorMsg());
+ } else {
+ // ok, then ask the user for a file to save the Blast data
+ BlastViewerOpener.setHelperMessage(BVMessages
+ .getString("FetchFromNcbiAction.msg2"));
+ tmpFile = qRet.getResultFile();
+ resFileStr = chooseFile();
+ if (resFileStr != null) {
+ resFile = new File(resFileStr);
+ try {
+ EZFileUtils.copyFile(tmpFile, resFile);
+ EZLogger.info(BVMessages.getString("FetchFromNcbiAction.msg3")
+ + resFileStr);
+ // setup an NCBI Blast Loader (XML)
+ BlastViewerOpener.setHelperMessage(BVMessages
+ .getString("FetchFromNcbiAction.msg4"));
+ SRLoader ncbiBlastLoader = SerializerSystemFactory
+ .getLoaderInstance(SerializerSystemFactory.NCBI_LOADER);
+ // load data from file
+ SROutput so = ncbiBlastLoader.load(resFile);
+ // prepare the viewer
+ BlastViewerPanel viewer = new BlastViewerPanel();
+ viewer.setContent(so);
+ // display the viewer
+ BlastViewerOpener.displayInternalFrame(viewer, resFile.getName(),
+ null);
+ } catch (IOException e) {
+ EZLogger.warn(BVMessages.getString("FetchFromNcbiAction.err1")
+ + ": " + e);
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(),
+ BVMessages.getString("FetchFromNcbiAction.err1") + ".");
+ }
+ }
+ // discard the temporary file
+ tmpFile.delete();
+ }
+ BlastViewerOpener.cleanHelperMessage();
+ _fetcherLocked = false;
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/actions/OpenFileAction.java b/src/bzh/plealog/blastviewer/actions/OpenFileAction.java
new file mode 100644
index 0000000..f9fbf26
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/actions/OpenFileAction.java
@@ -0,0 +1,104 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.actions;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+import javax.swing.SwingUtilities;
+
+import bzh.plealog.bioinfo.api.data.searchresult.SROutput;
+import bzh.plealog.bioinfo.api.data.searchresult.io.SRLoader;
+import bzh.plealog.bioinfo.io.searchresult.SerializerSystemFactory;
+import bzh.plealog.blastviewer.BlastViewerPanel;
+import bzh.plealog.blastviewer.resources.BVMessages;
+import bzh.plealog.blastviewer.util.BlastViewerOpener;
+
+import com.plealog.genericapp.api.EZEnvironment;
+import com.plealog.genericapp.api.file.EZFileManager;
+import com.plealog.genericapp.api.log.EZLogger;
+
+/**
+ * This class implements the action to load a Blast XML results from a file.
+ *
+ * @author Patrick G. Durand
+ */
+public class OpenFileAction extends AbstractAction {
+ private static final long serialVersionUID = -3984245135396746453L;
+
+ /**
+ * Action constructor.
+ *
+ * @param name
+ * the name of the action.
+ */
+ public OpenFileAction(String name) {
+ super(name);
+ }
+
+ /**
+ * Action constructor.
+ *
+ * @param name
+ * the name of the action.
+ * @param icon
+ * the icon of the action.
+ */
+ public OpenFileAction(String name, Icon icon) {
+ super(name, icon);
+ }
+
+ private SROutput readBlastFile(File f) {
+ // setup an NCBI Blast Loader (XML)
+ SRLoader ncbiBlastLoader = SerializerSystemFactory
+ .getLoaderInstance(SerializerSystemFactory.NCBI_LOADER);
+ return ncbiBlastLoader.load(f);
+ }
+
+ private void doAction() {
+ File f = EZFileManager.chooseFileForOpenAction(BVMessages
+ .getString("OpenFileAction.lbl"));
+ if (f == null)// user canceled dlg box
+ return;
+
+ EZEnvironment.setWaitCursor();
+
+ BlastViewerPanel viewer = new BlastViewerPanel();
+ viewer.setContent(readBlastFile(f));
+
+ BlastViewerOpener.displayInternalFrame(viewer, f.getName(), null);
+ }
+
+ public void actionPerformed(ActionEvent event) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ doAction();
+ } catch (Throwable t) {
+ EZLogger.warn(BVMessages.getString("OpenFileAction.err")
+ + t.toString());
+ } finally {
+ EZEnvironment.setDefaultCursor();
+ }
+ }
+ });
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/client/ncbi/QBlastRetriever.java b/src/bzh/plealog/blastviewer/client/ncbi/QBlastRetriever.java
new file mode 100755
index 0000000..1c91f0f
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/client/ncbi/QBlastRetriever.java
@@ -0,0 +1,101 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.client.ncbi;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.Map;
+
+import bzh.plealog.blastviewer.resources.BVMessages;
+import bzh.plealog.blastviewer.util.HTTPBasicEngine;
+import bzh.plealog.blastviewer.util.HTTPEngineException;
+
+/**
+ * This class implements a basic system to fetch a Blast results from the NCBI
+ * given a Request Identifier.
+ *
+ * @author Patrick G. Durand
+ */
+public class QBlastRetriever {
+ private String _errorMsg;
+ private File _resFile;
+
+ public static final MessageFormat QBLAST_URL = new MessageFormat(
+ "https://blast.ncbi.nlm.nih.gov/Blast.cgi?RESULTS_FILE=on&RID={0}&FORMAT_TYPE=XML&FORMAT_OBJECT=Alignment&CMD=Get"
+ );
+ // Note: old address was:
+ // "https://www.ncbi.nlm.nih.gov/blast/Blast.cgi?RID={0}&FORMAT_TYPE=XML&CMD=Get&ALIGNMENT_TYPE=Pairwise&FORMAT_OBJECT=Alignment"
+ // To get XML 2, use: FORMAT_TYPE=XML2_S
+ private static final String QUERY_NAME = "QBlastRetriever";
+
+ /**
+ * Call this method after a call to getBlastResult to get back some error
+ * message if any.
+ *
+ * @return an error message or null if no error was reported.
+ */
+ public String getErrorMsg() {
+ return _errorMsg;
+ }
+
+ /**
+ * Call this method after a call to getBlastResult to get back the result
+ * file.
+ *
+ * @return a result file or null if an error was reported.
+ */
+ public File getResultFile() {
+ return _resFile;
+ }
+
+ public boolean getBlastResult(String rid) {
+ QBlasterBase qb;
+ Map qBlastInfo;
+ String status;
+ String url;
+ File tmpFile;
+
+ url = QBLAST_URL.format(new Object[] { rid.trim() });
+ try {
+ tmpFile = HTTPBasicEngine.doGet(url);
+ } catch (HTTPEngineException ex) {
+ _errorMsg = ex.getMessage();
+ return false;
+ }
+ qb = new QBlasterBase();
+ qBlastInfo = qb.analyseOutput(QUERY_NAME, tmpFile, false, false);
+ if (qBlastInfo.size() == 0) {
+ // ok
+ _resFile = tmpFile;
+ return true;
+ } else {
+ // status different than WAITING: Blast error!
+ status = (String) qBlastInfo.get("Status");
+ if (status != null && !status.equals("WAITING")) {
+ // we return an ERROR param, while NCBI not
+ _errorMsg = (String) qBlastInfo.get("ERROR");
+ if (_errorMsg == null)
+ _errorMsg = status;
+ } else {
+ _errorMsg = BVMessages.getString("QBlastRetriever.err");
+ }
+ tmpFile.delete();
+ return false;
+ }
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/client/ncbi/QBlasterBase.java b/src/bzh/plealog/blastviewer/client/ncbi/QBlasterBase.java
new file mode 100755
index 0000000..2a63d4c
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/client/ncbi/QBlasterBase.java
@@ -0,0 +1,111 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.client.ncbi;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+
+import bzh.plealog.blastviewer.resources.BVMessages;
+
+import com.plealog.genericapp.api.log.EZLogger;
+
+public class QBlasterBase {
+ private String _errorMsg;
+
+ /**
+ * Analyze a file containing some data retrieved from the NCBI Blast server.
+ * Actually this method looks for the section QBlastInfo and retrieves the
+ * data available there. It gives the status of a query running on the server
+ * side.
+ *
+ * @param file
+ * the file to analyze
+ * @return a key/value pairs table, i.e. query status. More on that is
+ * available from the NCBI Blast server documentation.
+ */
+ protected Map analyseOutput(String qName, File file,
+ boolean logInfo, boolean logError) {
+ Hashtable qBlastInfo;
+ BufferedReader br = null;
+ String line, key, value;
+ boolean readInfo = false;
+ int pos;
+
+ qBlastInfo = new Hashtable<>();
+ try {
+ if (file.length() < 30) {
+ qBlastInfo.put("LENGTH", "NOT_VALID");
+ } else {
+ br = new BufferedReader(new FileReader(file));
+ while ((line = br.readLine()) != null) {
+ if (line.indexOf("QBlastInfoBegin") != -1) {
+ readInfo = true;
+ }
+ if (logInfo && readInfo) {
+ EZLogger.info(line);
+ }
+ if (line.indexOf("QBlastInfoEnd") != -1) {
+ break;
+ }
+ pos = line.indexOf("ERROR:");
+ if (pos != -1) {
+ value = line.substring(pos + 6).trim();
+ pos = value.indexOf('<');
+ if (pos != -1)
+ qBlastInfo.put("ERROR", value.substring(0, pos));
+ else
+ qBlastInfo.put("ERROR", value);
+ }
+ pos = line.indexOf("INFO:");
+ if (pos != -1) {
+ value = line.substring(pos + 5).trim();
+ pos = value.indexOf('<');
+ if (pos != -1)
+ qBlastInfo.put("INFO", value.substring(0, pos));
+ else
+ qBlastInfo.put("INFO", value);
+ }
+ if (readInfo) {
+ pos = line.indexOf('=');
+ if (pos != -1) {
+ key = line.substring(0, pos).trim();
+ value = line.substring(pos + 1).trim();
+ qBlastInfo.put(key, value);
+ }
+ }
+ }
+ }
+ } catch (Exception ex) {
+ _errorMsg = BVMessages.getString("QBlaster.analyseFileError");
+ if (logError) {
+ EZLogger.warn(qName + ": " + _errorMsg + ": " + ex.toString());
+ }
+ } finally {
+ IOUtils.closeQuietly(br);
+ }
+ return (qBlastInfo);
+ }
+
+ public String getErrorMsg() {
+ return _errorMsg;
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/ColorPolicyConfigImplem.java b/src/bzh/plealog/blastviewer/config/color/ColorPolicyConfigImplem.java
new file mode 100755
index 0000000..097f0e2
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/ColorPolicyConfigImplem.java
@@ -0,0 +1,666 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.Color;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.StringTokenizer;
+
+import javax.swing.ImageIcon;
+
+import org.apache.commons.io.IOUtils;
+
+import bzh.plealog.bioinfo.api.data.searchresult.SRHsp;
+import bzh.plealog.bioinfo.api.data.searchresult.SRHspScore;
+import bzh.plealog.bioinfo.ui.blast.config.color.ColorPolicyConfig;
+import bzh.plealog.bioinfo.util.CoreUtil;
+
+import com.plealog.genericapp.api.EZEnvironment;
+import com.plealog.genericapp.api.file.EZFileUtils;
+import com.plealog.genericapp.api.log.EZLogger;
+
+/**
+ * This class contains the color policy used to display colored Blast alignment,
+ * scores and so on.
+ *
+ * @author Patrick G. Durand
+ */
+public class ColorPolicyConfigImplem extends ColorPolicyConfig {
+ /** contains the color policy */
+ private HitColorPolicyAtom[] _hitListColorPolicy;
+ private HitQualityPolicyAtom[] _hitListQualityPolicy;
+ private int _hlcField;
+ private int _hlqField;
+ private Color _defFeatClr;
+ private boolean _useInvVideo;
+ private boolean _useAntialias = true;
+ private boolean _useTransparency = true;
+ private String _confPath;
+
+ /** of this configuration */
+ public static final String NAME = "ColorPolicyConfig";
+ /**
+ * key used to retrieve the color configuration within a resource bundle file
+ */
+ private static final String MSA_REVERSE_VIDEO_KEY = "inverse.video";
+ private static final String TRANSPARENCY_KEY = "clr.transparency";
+ private static final String ANTIALIAS_KEY = "antialias";
+ private static final String TABLE_BK_COLOR_KEY = "table.bk.color";
+ private static final String HLC_CLASSES = "hitListColorClasses";
+ private static final String HLQ_CLASSES = "hitListQualityClasses";
+ private static final String HLC_CLASS = "hlc.";
+ private static final String HLQ_CLASS = "hlq.";
+ private static final String HLC_FIELD = "hlc.field";
+ private static final String HLQ_FIELD = "hlq.field";
+ private static final String THRESH_SUFFIX = ".threshold";
+ private static final String CLR_SUFFIX = ".color";
+ private static final String QUAL_SUFFIX = ".qualityCode";
+ private static final String DEF_FEAT_CLR = "feature.clr";
+
+ public static Color BK_COLOR = Color.WHITE;
+ public static final Color QUERY_CELL_BK_COLOR = new Color(184, 207,
+ 229);
+ public static final int TRANSPARENCY_FACTOR = 128;
+
+ public static final ImageIcon[] QUALITY_SMILEY = new ImageIcon[] {
+ EZEnvironment.getImageIcon("smiley_g.png"),
+ EZEnvironment.getImageIcon("smiley_y.png"),
+ EZEnvironment.getImageIcon("smiley_o.png"),
+ EZEnvironment.getImageIcon("smiley_r.png") };
+
+ public static final String[] FIELDS = new String[] {
+ "Bit score", "E-Value", "Identity (%)", "Similarity (%)", "Gaps (%)",
+ "Query Coverage (%)", "Hit Coverage (%)", "Score" };
+
+ public static final int BITS_FIELD = 0;
+ public static final int EVAL_FIELD = 1;
+ public static final int IDENT_FIELD = 2;
+ public static final int SIMIL_FIELD = 3;
+ public static final int GAPS_FIELD = 4;
+ public static final int COVERAGE_FIELD = 5;
+ public static final int HCOVERAGE_FIELD = 6;
+ public static final int SCORE_FIELD = 7;
+
+ public static final String CONFIG_FILE_NAME = "colorpolicy.cfg";
+
+ /**
+ * Default constructor.
+ */
+ public ColorPolicyConfigImplem(String confPath) {
+ super();
+ setName(NAME);
+ _confPath = EZFileUtils.terminatePath(confPath);
+ }
+
+ /**
+ * Set on/off color transparency.
+ *
+ * @param useCT
+ * true of false
+ */
+ public void useColorTransparency(boolean useCT) {
+ _useTransparency = useCT;
+ }
+
+ /**
+ * Check if color transparency is used.
+ *
+ * @return true or false
+ */
+ public boolean isUsingColorTransparency() {
+ return _useTransparency;
+ }
+
+ /**
+ * Set on/off anti-alias.
+ *
+ * @param useAA
+ * true of false
+ */
+ public void useAntialias(boolean useAA) {
+ _useAntialias = useAA;
+ }
+
+ /**
+ * Check if anti-alias is used.
+ *
+ * @return true of false
+ */
+ public boolean isUsingAntialias() {
+ return _useAntialias;
+ }
+
+ /**
+ * Return the default color to use to display features.
+ *
+ * @return a Color
+ */
+ public Color getDefFeatureClr() {
+ return _defFeatClr;
+ }
+
+ /**
+ * Utility method used to create a HitColorPolicyAtom.
+ */
+ private HitColorPolicyAtom createClrAtom(String key) {
+ HitColorPolicyAtom atom = null;
+ String thresh, clr;
+
+ thresh = this.getProperty(HLC_CLASS + key + THRESH_SUFFIX);
+ clr = this.getProperty(HLC_CLASS + key + CLR_SUFFIX);
+ try {
+ atom = new HitColorPolicyAtom();
+ atom.setThreshold(Double.valueOf(thresh));
+ atom.setColor(convertColor(clr, ","));
+ } catch (Exception ex) {
+ EZLogger.warn("Invalid HitColorPolicyAtom: " + key + ": " + ex);
+ }
+ return atom;
+ }
+
+ /**
+ * Utility method used to create a HitColorPolicyAtom table.
+ */
+ private void initHLCPolicyTable() {
+ String items;
+ String[] itemsKeys;
+ HitColorPolicyAtom atom;
+ int i;
+
+ // read classes
+ items = this.getProperty(HLC_CLASSES);
+ itemsKeys = CoreUtil.tokenize(items);
+ _hlcField = Integer.valueOf(this.getProperty(HLC_FIELD));
+ _hitListColorPolicy = new HitColorPolicyAtom[itemsKeys.length];
+ for (i = 0; i < itemsKeys.length; i++) {
+ atom = createClrAtom(itemsKeys[i]);
+ if (atom == null) {
+ _hitListColorPolicy = null;
+ return;
+ }
+ _hitListColorPolicy[i] = atom;
+ }
+ }
+
+ /**
+ * Utility method used to create a HitQualityPolicyAtom.
+ */
+ private HitQualityPolicyAtom createQualAtom(String key) {
+ HitQualityPolicyAtom atom = null;
+ String thresh, code;
+ int idx;
+
+ thresh = this.getProperty(HLQ_CLASS + key + THRESH_SUFFIX);
+ code = this.getProperty(HLQ_CLASS + key + QUAL_SUFFIX);
+ try {
+ atom = new HitQualityPolicyAtom();
+ atom.setThreshold(Double.valueOf(thresh));
+ idx = Integer.valueOf(code);
+ atom.setIconId(idx);
+ atom.setQualityIcon((idx < QUALITY_SMILEY.length ? QUALITY_SMILEY[idx]
+ : null));
+ } catch (Exception ex) {
+ EZLogger.warn("Invalid HitQualityPolicyAtom: " + key + ": " + ex);
+ }
+ return atom;
+ }
+
+ /**
+ * Utility method used to create a HitQualityPolicyAtom table.
+ */
+ private void initHLQPolicyTable() {
+ String items;
+ String[] itemsKeys;
+ HitQualityPolicyAtom atom;
+ int i;
+
+ // read classes
+ items = this.getProperty(HLQ_CLASSES);
+ itemsKeys = CoreUtil.tokenize(items);
+ _hlqField = Integer.valueOf(this.getProperty(HLQ_FIELD));
+ _hitListQualityPolicy = new HitQualityPolicyAtom[itemsKeys.length];
+ for (i = 0; i < itemsKeys.length; i++) {
+ atom = createQualAtom(itemsKeys[i]);
+ if (atom == null) {
+ _hitListQualityPolicy = null;
+ return;
+ }
+ _hitListQualityPolicy[i] = atom;
+ }
+ }
+
+ /**
+ * Upload color policy from a stream.
+ *
+ * @param inStream
+ * the input stream to read color configuration
+ */
+ public void load(InputStream inStream) throws IOException {
+ super.load(inStream);
+ String val;
+
+ val = getProperty(TRANSPARENCY_KEY);
+ if (val != null) {
+ _useTransparency = val.equalsIgnoreCase("true");
+ }
+ val = getProperty(ANTIALIAS_KEY);
+ if (val != null) {
+ _useAntialias = val.equalsIgnoreCase("true");
+ }
+
+ val = getProperty(MSA_REVERSE_VIDEO_KEY);
+ if (val != null) {
+ _useInvVideo = val.equalsIgnoreCase("true");
+ }
+ val = getProperty(TABLE_BK_COLOR_KEY);
+ if (val != null) {
+ BK_COLOR = convertColor(val, ",");
+ }
+
+ val = getProperty(DEF_FEAT_CLR);
+ if (val != null) {
+ _defFeatClr = convertColor(val, ",");
+ } else {
+ _defFeatClr = Color.DARK_GRAY;
+ }
+ _defFeatClr = new Color(_defFeatClr.getRed(), _defFeatClr.getGreen(),
+ _defFeatClr.getBlue(), 128);
+ if (getProperty(HLC_CLASSES) != null) {
+ initHLCPolicyTable();
+ }
+ if (getProperty(HLQ_CLASSES) != null) {
+ initHLQPolicyTable();
+ }
+ }
+
+ /**
+ * Convert color (R,G,B) to Color object.
+ */
+ private Color convertColor(String szColor, String sep) {
+ StringTokenizer tokenizer;
+ String token;
+ Color clr;
+ int r, g, b;
+
+ tokenizer = new StringTokenizer(szColor, sep);
+ if (tokenizer.hasMoreTokens() == false)
+ return Color.black;
+ token = tokenizer.nextToken();
+ r = Integer.valueOf(token).intValue();
+ if (tokenizer.hasMoreTokens() == false)
+ return Color.black;
+ token = tokenizer.nextToken();
+ g = Integer.valueOf(token).intValue();
+ if (tokenizer.hasMoreTokens() == false)
+ return Color.black;
+ token = tokenizer.nextToken();
+ b = Integer.valueOf(token).intValue();
+ clr = new Color(r, g, b);
+ return clr;
+ }
+
+ private double getValue(SRHsp hsp, int field) {
+ SRHspScore score;
+
+ double value;
+ score = hsp.getScores();
+ switch (field) {
+ case BITS_FIELD:
+ value = score.getBitScore();
+ break;
+ case EVAL_FIELD:
+ value = score.getEvalue();
+ break;
+ case IDENT_FIELD:
+ value = score.getIdentityP();
+ break;
+ case SIMIL_FIELD:
+ value = score.getPositiveP();
+ break;
+ case GAPS_FIELD:
+ value = score.getGapsP();
+ break;
+ case COVERAGE_FIELD:
+ value = hsp.getQueryCoverage();
+ break;
+ case HCOVERAGE_FIELD:
+ value = hsp.getHitCoverage();
+ break;
+ case SCORE_FIELD:
+ value = score.getScore();
+ break;
+ default:
+ value = score.getBitScore();
+ break;
+ }
+ return value;
+ }
+
+ /**
+ * Given a bitScore return the color defined by this color policy.
+ *
+ * @param hsp
+ * a SRHsp object
+ * @param alpha
+ * use alpha transparency or not
+ *
+ * @return a Color
+ */
+ public Color getHitColor(SRHsp hsp, boolean alpha) {
+ HitColorPolicyAtom atom;
+ int i;
+ double value;
+
+ if (_hitListColorPolicy == null || _hitListColorPolicy.length == 0)
+ return Color.BLACK;
+ value = getValue(hsp, _hlcField);
+ for (i = 0; i < _hitListColorPolicy.length; i++) {
+ atom = _hitListColorPolicy[i];
+ if (value >= atom.getThreshold()) {
+ return atom.getColor(alpha);
+ }
+ }
+ return (Color.black);
+ }
+
+ /**
+ * Given a bitScore return the quality defined by this color policy.
+ *
+ * @param hsp
+ * a SRHsp object
+ *
+ * @return a quality value
+ */
+ public int getQualityValue(SRHsp hsp) {
+ HitQualityPolicyAtom atom;
+ int i;
+ double value;
+
+ if (_hitListQualityPolicy == null || _hitListQualityPolicy.length == 0)
+ return 0;
+ value = getValue(hsp, _hlqField);
+ for (i = 0; i < _hitListQualityPolicy.length; i++) {
+ atom = _hitListQualityPolicy[i];
+ if (value >= atom.getThreshold()) {
+ return _hitListQualityPolicy.length - i;
+ }
+ }
+ return (0);
+ }
+
+ /**
+ * Given a bitScore returns the quality icon defined by this color policy.
+ *
+ * @param hsp
+ * a SRHsp object
+ *
+ * @return a quality icon
+ */
+ public ImageIcon getQualityIcon(SRHsp hsp) {
+ HitQualityPolicyAtom atom;
+ int i;
+ double value;
+
+ if (_hitListQualityPolicy == null || _hitListQualityPolicy.length == 0)
+ return null;
+ value = getValue(hsp, _hlqField);
+ for (i = 0; i < _hitListQualityPolicy.length; i++) {
+ atom = _hitListQualityPolicy[i];
+ if (value >= atom.getThreshold()) {
+ return atom.getQualityIcon();
+ }
+ }
+ return (QUALITY_SMILEY[QUALITY_SMILEY.length - 1]);
+ }
+
+ /**
+ * Return the field identifier to use to get colors. Returned value is one of
+ * XXX_FIELD. Using such ID can be used to query the array FIELDS contained in
+ * this class to get a human readable representation of this ID.
+ */
+ public int getFieldForColor() {
+ return _hlcField;
+ }
+
+ /**
+ * Set the field identifier to use to get colors.
+ *
+ * @param val one of
+ * XXX_FIELD. Using such ID can be used to query the array FIELDS contained in
+ * this class to get a human readable representation of this ID.
+ */
+ public void setFieldForColor(int val) {
+ _hlcField = val;
+ }
+
+ /**
+ * Return the field identifier to use to get quality icons. Returned value is
+ * one of XXX_FIELD. Using such ID can be used to query the array FIELDS
+ * contained in this class to get a human readable representation of this ID.
+ */
+ public int getFieldForQuality() {
+ return _hlqField;
+ }
+
+ /**
+ * Set the field identifier to use to get quality icons.
+ *
+ * @param val
+ * one of XXX_FIELD. Using such ID can be used to query the array FIELDS
+ * contained in this class to get a human readable representation of this ID.
+ */
+ public void setFieldForQuality(int val) {
+ _hlqField = val;
+ }
+
+ /**
+ * Return the full color policy.
+ *
+ * @return a color policy instance
+ */
+ public HitColorPolicyAtom[] getHitListColorPolicy() {
+ return _hitListColorPolicy;
+ }
+
+ /**
+ * Set a full color policy.
+ *
+ * @param listColorPolicy a color policy instance
+ */
+ public void setHitListColorPolicy(HitColorPolicyAtom[] listColorPolicy) {
+ _hitListColorPolicy = listColorPolicy;
+ }
+
+ /**
+ * Return the full quality policy.
+ *
+ * @return a quality policy instance
+ */
+ public HitQualityPolicyAtom[] getHitListQualityPolicy() {
+ return _hitListQualityPolicy;
+ }
+
+ /**
+ * Set a full quality policy.
+ *
+ * @param listQualityPolicy a quality policy instance
+ */
+ public void setHitListQualityPolicy(HitQualityPolicyAtom[] listQualityPolicy) {
+ _hitListQualityPolicy = listQualityPolicy;
+ }
+
+ /**
+ * Dump the current color policy within this class logger.
+ */
+ public void dumpConfig() {
+ int i;
+
+ if (_hitListColorPolicy == null || _hitListColorPolicy.length == 0) {
+ EZLogger.info("Color Policy: config empty");
+ } else {
+ EZLogger.info("Color Policy: " + FIELDS[_hlcField]);
+ for (i = 0; i < _hitListColorPolicy.length; i++) {
+ EZLogger.info(_hitListColorPolicy[i].toString());
+ }
+ }
+ if (_hitListQualityPolicy == null || _hitListQualityPolicy.length == 0) {
+ EZLogger.info("Quality Policy: config empty");
+ } else {
+ EZLogger.info("Quality Policy: " + FIELDS[_hlqField]);
+ for (i = 0; i < _hitListQualityPolicy.length; i++) {
+ EZLogger.info(_hitListQualityPolicy[i].toString());
+ }
+ }
+ }
+
+ private String getClrRepr(Color clr) {
+ StringBuffer szBuf;
+ szBuf = new StringBuffer();
+ szBuf.append(clr.getRed());
+ szBuf.append(",");
+ szBuf.append(clr.getGreen());
+ szBuf.append(",");
+ szBuf.append(clr.getBlue());
+ return szBuf.toString();
+ }
+
+ /**
+ * Figure out whether or not to use inverse video mode.
+ *
+ * @param useRV true or false
+ */
+ public void setUseInverseVideo(boolean useRV) {
+ _useInvVideo = useRV;
+ }
+
+ /**
+ * Figure out whether or not to use inverse video mode.
+ *
+ * @return true or false.
+ */
+ public boolean useInverseVideo() {
+ return _useInvVideo;
+ }
+
+ /**
+ * Save the content of this ColorConfigPolicy in its configuration file.
+ */
+ public void save() throws IOException {
+ FileOutputStream fos = null;
+ fos = new FileOutputStream(_confPath + CONFIG_FILE_NAME);
+ try {
+ save(fos);
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ IOUtils.closeQuietly(fos);
+ }
+ }
+
+ /**
+ * Save the content of this ColorConfigPolicy. This method terminates with a
+ * flush on the OutputStream AND close it.
+ *
+ * @param os the output stream
+ */
+ private void save(OutputStream os) throws IOException {
+ HitColorPolicyAtom atomClr;
+ HitQualityPolicyAtom atomQual;
+ PrintWriter writer;
+ String id;
+ int i;
+
+ writer = new PrintWriter(new OutputStreamWriter(os));
+
+ // save HitColorPolicyTable name
+ if (_hitListColorPolicy != null) {
+ writer.print(HLC_CLASSES);
+ writer.print("=");
+ for (i = 0; i < _hitListColorPolicy.length; i++) {
+ writer.print("c" + (i + 1));
+ if ((i + 1) < _hitListColorPolicy.length) {
+ writer.print(",");
+ }
+ }
+ writer.print("\n");
+ writer.print(HLC_FIELD);
+ writer.print("=");
+ writer.print(_hlcField);
+ writer.print("\n");
+ for (i = 0; i < _hitListColorPolicy.length; i++) {
+ atomClr = _hitListColorPolicy[i];
+ id = "c" + String.valueOf(i + 1);
+ writer.print(HLC_CLASS + id + THRESH_SUFFIX + "=");
+ writer.print(atomClr.getThreshold());
+ writer.print("\n");
+ writer.print(HLC_CLASS + id + CLR_SUFFIX + "=");
+ writer.print(getClrRepr(atomClr.getColor(false)));
+ writer.print("\n");
+ }
+ }
+ writer.print("\n");
+ // save HitQualityPolicyTable name
+ if (_hitListQualityPolicy != null) {
+ writer.print(HLQ_CLASSES);
+ writer.print("=");
+ for (i = 0; i < _hitListQualityPolicy.length; i++) {
+ writer.print("c" + (i + 1));
+ if ((i + 1) < _hitListQualityPolicy.length) {
+ writer.print(",");
+ }
+ }
+ writer.print("\n");
+ writer.print(HLQ_FIELD);
+ writer.print("=");
+ writer.print(_hlqField);
+ writer.print("\n");
+ for (i = 0; i < _hitListQualityPolicy.length; i++) {
+ atomQual = _hitListQualityPolicy[i];
+ id = "c" + String.valueOf(i + 1);
+ writer.print(HLQ_CLASS + id + THRESH_SUFFIX + "=");
+ writer.print(atomQual.getThreshold());
+ writer.print("\n");
+ writer.print(HLQ_CLASS + id + QUAL_SUFFIX + "=");
+ writer.print(atomQual.getIconId());
+ writer.print("\n");
+ }
+ }
+ writer.print("\n");
+ // save reverse video usage
+ writer.print(MSA_REVERSE_VIDEO_KEY);
+ writer.print("=");
+ writer.print(useInverseVideo() ? "true" : "false");
+ writer.print("\n\n");
+ // save table bk color
+ writer.print(TABLE_BK_COLOR_KEY);
+ writer.print("=");
+ writer.print(getClrRepr(BK_COLOR));
+ writer.print("\n\n");
+ // save transparency usage
+ writer.print(TRANSPARENCY_KEY);
+ writer.print("=");
+ writer.print(_useTransparency ? "true" : "false");
+ writer.print("\n\n");
+ writer.flush();
+ writer.close();
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitColorPolicyAtom.java b/src/bzh/plealog/blastviewer/config/color/HitColorPolicyAtom.java
new file mode 100755
index 0000000..7476ade
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitColorPolicyAtom.java
@@ -0,0 +1,115 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.Color;
+
+/**
+ * This class stores information related to a single color policy. Such a policy
+ * corresponds to a bit score and its associated color.
+ *
+ * @author Patrick G. Durand
+ */
+public class HitColorPolicyAtom {
+ private double _threshold;
+ private Color _clr = Color.BLACK;
+ private Color _clrWithAlpha = Color.black;
+
+ /**
+ * Default constructor.
+ */
+ public HitColorPolicyAtom() {
+ }
+
+ /**
+ * Constructor with a threshold and its associated color.
+ */
+ public HitColorPolicyAtom(long threshold, Color clr) {
+ setThreshold(threshold);
+ setColor(clr);
+ }
+
+ /**
+ * Return the bit score.
+ */
+ public double getThreshold() {
+ return _threshold;
+ }
+
+ /**
+ * Set the bit score.
+ */
+ public void setThreshold(double val) {
+ _threshold = val;
+ }
+
+ /**
+ * Return the color.
+ */
+ public Color getColor(boolean alpha) {
+ if (alpha)
+ return _clrWithAlpha;
+ else
+ return _clr;
+ }
+
+ /**
+ * Set the color.
+ *
+ * @param clr
+ * a color without alpha channel. This method will create a
+ * corresponding color with an alpha channel that can be retrieved
+ * using this getColor method.
+ */
+ public void setColor(Color clr) {
+ if (clr == null)
+ _clr = Color.BLACK;
+ else
+ _clr = clr;
+ _clrWithAlpha = new Color(_clr.getRed(), _clr.getGreen(), _clr.getBlue(),
+ ColorPolicyConfigImplem.TRANSPARENCY_FACTOR);
+ }
+
+ /**
+ * Return a string representation of this color policy.
+ *
+ * */
+ public String getClrRepr() {
+ StringBuffer szBuf;
+ szBuf = new StringBuffer();
+ szBuf.append(_clr.getRed());
+ szBuf.append(",");
+ szBuf.append(_clr.getGreen());
+ szBuf.append(",");
+ szBuf.append(_clr.getBlue());
+ return szBuf.toString();
+ }
+
+ /**
+ * Return a string representation of this color policy.
+ *
+ * */
+ public String toString() {
+ StringBuffer szBuf;
+ szBuf = new StringBuffer();
+ szBuf.append(_threshold);
+ szBuf.append(": [");
+ szBuf.append(getClrRepr());
+ szBuf.append("]");
+ return szBuf.toString();
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitColorPolicyEditorPanel.java b/src/bzh/plealog/blastviewer/config/color/HitColorPolicyEditorPanel.java
new file mode 100755
index 0000000..34ffcce
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitColorPolicyEditorPanel.java
@@ -0,0 +1,201 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JColorChooser;
+import javax.swing.JComponent;
+
+import com.plealog.genericapp.api.EZEnvironment;
+
+/**
+ * This is the editor of color policy.
+ *
+ * @author Patrick G. Durand
+ */
+public class HitColorPolicyEditorPanel extends HitPolicyEditorBasePanel {
+ private static final long serialVersionUID = 9094467477284177517L;
+
+ private JButton[] _clr;
+
+ private static final String MSG_P1_TIP = "Click to change colour";
+ private static final String MSG_HEAD = "Colour policy will be applied using";
+ private static final String HELP_MSG = "This panel defines the value ranges used to set Hit colours. "
+ + "Values set for each range have to be defined by decreasing order. "
+ + "Only use positive real numbers; scientific notation is allowed (e.g. 1e-3). "
+ + "Click on a coloured button to change a colour.";
+ private static final String CHOOSE_MSG = "Choose a color";
+
+ /**
+ * Constructor.
+ *
+ * @param nb of color classes to use
+ */
+ public HitColorPolicyEditorPanel(int nClasses) {
+ super();
+ if (nClasses == 0)
+ nClasses = 4;
+ _nClasses = nClasses;
+ buildGUI(nClasses);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param policy a color policy
+ *
+ * @param valueType one of ColorColicyConfig.XXX_FIELD
+ */
+ public HitColorPolicyEditorPanel(HitColorPolicyAtom[] policy, int valueType) {
+ super();
+ if (policy == null)
+ _nClasses = 4;
+ else
+ _nClasses = policy.length;
+ buildGUI(_nClasses);
+ setData(policy);
+ setValueType(valueType);
+ }
+
+ /**
+ * Set a color policy.
+ *
+ * @param policy the color policy
+ *
+ * */
+ public void setData(HitColorPolicyAtom[] policy) {
+ Color clr;
+ int i;
+
+ if (policy == null || policy.length != _nClasses)
+ return;
+ for (i = 0; i < _nClasses; i++) {
+ _valuesTo[i].setText(String.valueOf(policy[i].getThreshold()));
+ clr = policy[i].getColor(false);
+ _clr[i].setBackground(clr);
+ }
+ }
+
+ /**
+ * Get the color policy.
+ *
+ * @return the color policy
+ *
+ * */
+ public HitColorPolicyAtom[] getData() {
+ HitColorPolicyAtom[] policy = null;
+ String val;
+ Color clr;
+ int i;
+ double[] thresholds;
+
+ thresholds = new double[_nClasses];
+ for (i = 0; i < _nClasses - 1; i++) {
+ val = _valuesTo[i].getText();
+ if (val.length() == 0) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(), MSG_ERR2);
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ try {
+ thresholds[i] = Double.valueOf(val);
+ if (thresholds[i] < 0)
+ throw new NumberFormatException();
+ } catch (Exception e) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(), BAD_VALUE.format(new Object[] { val }));
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ }
+ for (i = 0; i < _nClasses - 2; i++) {
+ if (thresholds[i + 1] > thresholds[i]) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(), MSG_ERR1);
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ }
+ policy = new HitColorPolicyAtom[_nClasses];
+ for (i = 0; i < _nClasses - 1; i++) {
+ policy[i] = new HitColorPolicyAtom();
+ policy[i].setThreshold(thresholds[i]);
+ clr = _clr[i].getBackground();
+ policy[i].setColor(clr);
+ }
+ i = _nClasses - 1;
+ policy[i] = new HitColorPolicyAtom();
+ policy[i].setThreshold(0);
+ clr = _clr[i].getBackground();
+ policy[i].setColor(clr);
+ return policy;
+ }
+
+ private JButton createClrButton() {
+ JButton btn;
+ FontMetrics fm;
+ Dimension dim;
+ int h;
+
+ btn = new JButton();
+ btn.setOpaque(true);
+ btn.setBorder(BorderFactory.createRaisedBevelBorder());
+ btn.setFont(DEF_FNT);
+ btn.setToolTipText(MSG_P1_TIP);
+ btn.addActionListener(new ColorChooser());
+ fm = btn.getFontMetrics(DEF_FNT);
+ h = fm.getHeight();
+ dim = new Dimension(6 * h, h);
+ btn.setPreferredSize(dim);
+ return btn;
+ }
+
+ protected void initSpecialComponents(int nClasses) {
+ _clr = new JButton[nClasses];
+ for (int i = 0; i < nClasses; i++) {
+ _clr[i] = createClrButton();
+ }
+ }
+
+ protected JComponent getSpecialComponent(int i) {
+ return _clr[i];
+ }
+
+ protected String getHeaderMsg() {
+ return MSG_HEAD;
+ }
+
+ protected String getHelpMsg() {
+ return HELP_MSG;
+ }
+
+ private class ColorChooser implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ Color bg;
+
+ bg = JColorChooser.showDialog(HitColorPolicyEditorPanel.this, CHOOSE_MSG,
+ ((JButton) e.getSource()).getBackground());
+ if (bg != null)
+ ((JButton) e.getSource()).setBackground(bg);
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorBasePanel.java b/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorBasePanel.java
new file mode 100755
index 0000000..a88a43a
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorBasePanel.java
@@ -0,0 +1,278 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.MessageFormat;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+
+/**
+ * This is the base panel for color and quality policy editors.
+ *
+ * @author Patrick G. Durand
+ */
+public abstract class HitPolicyEditorBasePanel extends JPanel {
+ private static final long serialVersionUID = -5471357033799472849L;
+ protected JTextField[] _valuesFrom;
+ protected JTextField[] _valuesTo;
+ protected int _nClasses;
+ protected int _valueType;// one of ColorColicyConfig.XXX_FIELD
+ protected JComboBox _valueTypeChooser;
+
+ protected static final String MSG_P1 = "Assign";
+ protected static final String MSG_P2 = "if value is above";
+ protected static final String MSG_P3 = "if value is less than";
+ protected static final String MSG_P4 = "and above";
+ protected static final String MSG_P5 = "in any other cases";
+ protected static final String MSG_ERR1 = "Values are not given by descreasing order.";
+ protected static final String MSG_ERR2 = "Value is not defined.";
+ protected static final Font DEF_FNT = new Font("sans-serif", Font.PLAIN, 12);
+ protected static final MessageFormat BAD_VALUE = new MessageFormat("Value {0} is not a positive real number.");
+
+ /**
+ * Constructor.
+ */
+ public HitPolicyEditorBasePanel() {
+ super();
+ }
+
+ /**
+ * Set the type of data.
+ *
+ * @param valueType one of ColorColicyConfig.XXX_FIELD
+ */
+ public void setValueType(int valueType) {
+ _valueType = valueType;
+ _valueTypeChooser.setSelectedIndex(valueType);
+ }
+
+ /**
+ * Get the type of data.
+ *
+ * @return one of ColorColicyConfig.XXX_FIELD
+ */
+ public int getValueType() {
+ return _valueType;
+ }
+
+ /**
+ * Create a text field.
+ *
+ * @param editable true or false
+ *
+ * @return a text field
+ */
+ protected JTextField createTextField(boolean editable) {
+ JTextField tf;
+
+ tf = new JTextField();
+ tf.setEditable(editable);
+ // tf.setBorder(null);
+ // tf.setOpaque(false);
+ tf.setFont(DEF_FNT);
+
+ return tf;
+ }
+
+ /**
+ * Create a label.
+ *
+ * @param msg the message of the label
+ *
+ * @return a label
+ */
+ protected JLabel createLabel(String msg) {
+ JLabel btn;
+
+ btn = new JLabel(msg);
+ btn.setFont(DEF_FNT);
+ return btn;
+ }
+
+ /**
+ * Create a text area used to display help message.
+ *
+ * @param nLines number of lines
+ * @param defMsg default message
+ *
+ * @return a text area
+ */
+ protected JTextArea createHelper(int nLines, String defMsg) {
+ JTextArea helpArea = new JTextArea();
+ helpArea.setRows(nLines);
+ helpArea.setLineWrap(true);
+ helpArea.setWrapStyleWord(true);
+ helpArea.setEditable(false);
+ helpArea.setOpaque(false);
+ helpArea.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
+ helpArea.setText(defMsg);
+ helpArea.setFont(DEF_FNT);
+ return helpArea;
+ }
+
+ /**
+ * Implement this method to initialize specific components.
+ *
+ * @param nClasses nb of classes to use
+ */
+ protected abstract void initSpecialComponents(int nClasses);
+
+ /**
+ * Return a particular component.
+ *
+ * @param i ith component to return
+ *
+ * @return a component
+ */
+ protected abstract JComponent getSpecialComponent(int i);
+
+ /**
+ * Return the header message.
+ *
+ * @return header message
+ * */
+ protected abstract String getHeaderMsg();
+
+ /**
+ * Return the help message.
+ *
+ * @return help message
+ * */
+ protected abstract String getHelpMsg();
+
+ /**
+ * Create the UI.
+ *
+ * @param nClasses nb of classes to use
+ */
+ protected void buildGUI(int nClasses) {
+ DefaultFormBuilder builder;
+ FormLayout layout;
+ JLabel emptyLbl;
+ JPanel pnl, pnl2, pnl3, pnl4;
+ int i;
+
+ emptyLbl = new JLabel();
+ _valuesFrom = new JTextField[nClasses];
+ _valuesTo = new JTextField[nClasses];
+ for (i = 0; i < nClasses; i++) {
+ _valuesFrom[i] = createTextField(false);
+ _valuesTo[i] = createTextField(true);
+ }
+ initSpecialComponents(nClasses);
+ nClasses--;
+ for (i = 0; i < nClasses; i++) {
+ _valuesTo[i].getDocument().addDocumentListener(new EditListener(_valuesTo[i], _valuesFrom[i + 1]));
+ }
+ nClasses++;
+ layout = new FormLayout("30dlu, 2dlu, 25dlu, 2dlu, 80dlu, 2dlu, 40dlu, 2dlu, 40dlu, 2dlu, 40dlu", "");
+ builder = new DefaultFormBuilder(layout);
+ builder.setDefaultDialogBorder();
+ for (i = 0; i < nClasses; i++) {
+ if (i == 0) {
+ builder.append(createLabel(MSG_P1));
+ builder.append(getSpecialComponent(i));
+ builder.append(createLabel(MSG_P2));
+ builder.append(_valuesTo[i]);
+ builder.append(emptyLbl);
+ builder.append(emptyLbl);
+ } else if (i == nClasses - 1) {
+ builder.append(createLabel(MSG_P1));
+ builder.append(getSpecialComponent(i));
+ builder.append(createLabel(MSG_P5));
+ builder.append(emptyLbl);
+ builder.append(emptyLbl);
+ builder.append(emptyLbl);
+ } else {
+ builder.append(createLabel(MSG_P1));
+ builder.append(getSpecialComponent(i));
+ builder.append(createLabel(MSG_P3));
+ builder.append(_valuesFrom[i]);
+ builder.append(createLabel(MSG_P4));
+ builder.append(_valuesTo[i]);
+ }
+ if ((i + 1) < nClasses)
+ builder.nextLine();
+ }
+ pnl = new JPanel();
+ _valueTypeChooser = new JComboBox<>();
+ _valueTypeChooser.setFont(DEF_FNT);
+ _valueTypeChooser.addActionListener(new ValueTypeSelector());
+ for (i = 0; i < ColorPolicyConfigImplem.FIELDS.length; i++) {
+ _valueTypeChooser.addItem(ColorPolicyConfigImplem.FIELDS[i]);
+ }
+ pnl.add(createLabel(getHeaderMsg()));
+ pnl.add(_valueTypeChooser);
+ pnl.add(createLabel("values"));
+ pnl2 = new JPanel(new BorderLayout());
+ pnl2.add(pnl, BorderLayout.WEST);
+ pnl2.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
+ pnl3 = new JPanel(new BorderLayout());
+ pnl3.add(createHelper(5, getHelpMsg()), BorderLayout.CENTER);
+ pnl4 = new JPanel(new BorderLayout());
+ pnl4.add(pnl2, BorderLayout.NORTH);
+ pnl4.add(builder.getContainer(), BorderLayout.CENTER);
+ pnl4.add(pnl3, BorderLayout.SOUTH);
+ this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ this.add(pnl4);
+ }
+
+ protected class EditListener implements DocumentListener {
+ private JTextField _src;
+ private JTextField _tgt;
+
+ public EditListener(JTextField src, JTextField tgt) {
+ _src = src;
+ _tgt = tgt;
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ _tgt.setText(_src.getText());
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ _tgt.setText(_src.getText());
+ }
+
+ public void changedUpdate(DocumentEvent e) {
+ }
+ }
+
+ protected class ValueTypeSelector implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ _valueType = ((JComboBox>) e.getSource()).getSelectedIndex();
+ }
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorDialog.java b/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorDialog.java
new file mode 100755
index 0000000..d1b3c88
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitPolicyEditorDialog.java
@@ -0,0 +1,189 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import bzh.plealog.bioinfo.ui.blast.config.ConfigManager;
+import bzh.plealog.blastviewer.resources.BVMessages;
+
+import com.plealog.genericapp.api.log.EZLogger;
+
+/**
+ * This is the color policy editor.
+ *
+ * @author Patrick G. Durand
+ */
+public class HitPolicyEditorDialog extends JDialog {
+ private static final long serialVersionUID = 812060132777071379L;
+ private HitColorPolicyEditorPanel _colorPolicy;
+ private HitQualityPolicyEditorPanel _qualityPolicy;
+ private JTabbedPane _jtp;
+
+ /**
+ * Constructor.
+ *
+ * @param owner
+ * parent frame of this dialog box.
+ * */
+ public HitPolicyEditorDialog(Frame owner) {
+ super(owner, BVMessages.getString("HitPolicyEditorDialog.header"), true);
+ buildGUI();
+ this.pack();
+ }
+
+ /**
+ * Create the GUI.
+ */
+ private void buildGUI() {
+ JPanel mainPnl, btnPnl;
+ JButton okBtn, cancelBtn;
+ ColorPolicyConfigImplem nc;
+ HitColorPolicyAtom[] clrPolicy;
+ HitQualityPolicyAtom[] qualPolicy;
+
+ nc = (ColorPolicyConfigImplem) ConfigManager.getConfig(ColorPolicyConfigImplem.NAME);
+ if (nc == null) {
+ getContentPane().setLayout(new BorderLayout());
+ getContentPane().add(
+ new JLabel(BVMessages.getString("HitPolicyEditorDialog.err")),
+ BorderLayout.CENTER);
+ return;
+ }
+ clrPolicy = nc.getHitListColorPolicy();
+ qualPolicy = nc.getHitListQualityPolicy();
+ _colorPolicy = new HitColorPolicyEditorPanel(clrPolicy == null ? 4
+ : clrPolicy.length);
+ _colorPolicy.setData(clrPolicy);
+ _colorPolicy.setValueType(nc.getFieldForColor());
+ _qualityPolicy = new HitQualityPolicyEditorPanel(qualPolicy == null ? 4
+ : qualPolicy.length);
+ _qualityPolicy.setData(qualPolicy);
+ _qualityPolicy.setValueType(nc.getFieldForQuality());
+
+ _jtp = new JTabbedPane();
+ _jtp.setFocusable(false);
+ _jtp.add(BVMessages.getString("HitPolicyEditorDialog.tab1"), _colorPolicy);
+ _jtp.add(BVMessages.getString("HitPolicyEditorDialog.tab2"), _qualityPolicy);
+ mainPnl = new JPanel(new BorderLayout());
+ mainPnl.add(_jtp, BorderLayout.CENTER);
+
+ okBtn = new JButton(BVMessages.getString("HitPolicyEditorDialog.btn1"));
+ okBtn.addActionListener(new OkDialogAction());
+ cancelBtn = new JButton(BVMessages.getString("HitPolicyEditorDialog.btn2"));
+ cancelBtn.addActionListener(new CloseDialogAction());
+ btnPnl = new JPanel();
+ btnPnl.setLayout(new BoxLayout(btnPnl, BoxLayout.X_AXIS));
+ btnPnl.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+ btnPnl.add(Box.createHorizontalGlue());
+ btnPnl.add(okBtn);
+ btnPnl.add(Box.createRigidArea(new Dimension(10, 0)));
+ btnPnl.add(cancelBtn);
+ btnPnl.add(Box.createHorizontalGlue());
+
+ getContentPane().setLayout(new BorderLayout());
+ getContentPane().add(mainPnl, BorderLayout.CENTER);
+ getContentPane().add(btnPnl, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Show the dialog box on screen.
+ */
+ public void showDlg() {
+ centerOnScreen();
+ setVisible(true);
+ }
+
+ /**
+ * Center the frame on the screen.
+ */
+ private void centerOnScreen() {
+ Dimension screenSize = this.getToolkit().getScreenSize();
+ Dimension dlgSize = this.getSize();
+
+ this.setLocation(screenSize.width / 2 - dlgSize.width / 2,
+ screenSize.height / 2 - dlgSize.height / 2);
+ }
+
+ /**
+ * This inner class manages actions coming from the JButton CloseDialog.
+ */
+ private class CloseDialogAction extends AbstractAction {
+ private static final long serialVersionUID = -7737589249414570785L;
+
+ /**
+ * Manages JButton action
+ */
+ public void actionPerformed(ActionEvent e) {
+ dispose();
+ }
+ }
+
+ /**
+ * This inner class manages actions coming from the JButton OkDialog.
+ */
+ private class OkDialogAction extends AbstractAction {
+ private static final long serialVersionUID = -3503165540629775725L;
+
+ /**
+ * Manages JButton action
+ */
+ public void actionPerformed(ActionEvent e) {
+ HitColorPolicyAtom[] clrPolicy;
+ HitQualityPolicyAtom[] qualPolicy;
+ ColorPolicyConfigImplem nc;
+
+ nc = (ColorPolicyConfigImplem) ConfigManager.getConfig(ColorPolicyConfigImplem.NAME);
+ // check data
+ clrPolicy = _colorPolicy.getData();
+ if (clrPolicy == null) {
+ _jtp.setSelectedIndex(0);
+ return;
+ }
+ qualPolicy = _qualityPolicy.getData();
+ if (qualPolicy == null) {
+ _jtp.setSelectedIndex(1);
+ return;
+ }
+ // set and save new data
+ nc.setHitListColorPolicy(clrPolicy);
+ nc.setFieldForColor(_colorPolicy.getValueType());
+ nc.setHitListQualityPolicy(qualPolicy);
+ nc.setFieldForQuality(_qualityPolicy.getValueType());
+ try {
+ nc.save();
+ } catch (IOException e1) {
+ EZLogger.warn("Unable to save Color Policy: " + e1);
+ }
+ dispose();
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyAtom.java b/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyAtom.java
new file mode 100755
index 0000000..5c2462c
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyAtom.java
@@ -0,0 +1,115 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import javax.swing.ImageIcon;
+
+/**
+ * This class stores information related to a single quality policy. Such a
+ * policy corresponds to a bit score and its associated quality icon.
+ *
+ * @author Patrick G. Durand
+ */
+public class HitQualityPolicyAtom {
+ private double _threshold;
+ private int _iconId;
+ private ImageIcon _qualityIcon;
+
+ /**
+ * Default constructor.
+ */
+ public HitQualityPolicyAtom() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param threshold
+ * threshold
+ * @param iconId
+ * icon id
+ * @param qIcon
+ * quality icon.
+ */
+ public HitQualityPolicyAtom(double threshold, int iconId, ImageIcon qIcon) {
+ setThreshold(threshold);
+ setQualityIcon(qIcon);
+ setIconId(iconId);
+ }
+
+ /**
+ * Return the threshold.
+ *
+ * @return a threshold
+ */
+ public double getThreshold() {
+ return _threshold;
+ }
+
+ /**
+ * Set the threshold.
+ *
+ * @param val
+ * threshold
+ */
+ public void setThreshold(double val) {
+ _threshold = val;
+ }
+
+ /**
+ * Return the quality icon
+ *
+ * @return an icon
+ * */
+ public ImageIcon getQualityIcon() {
+ return _qualityIcon;
+ }
+
+ /**
+ * Set the quality icon
+ *
+ * @param icon
+ * an icon
+ * */
+ public void setQualityIcon(ImageIcon icon) {
+ _qualityIcon = icon;
+ }
+
+ public int getIconId() {
+ return _iconId;
+ }
+
+ /**
+ * Set the icon identifier.
+ *
+ * @param id
+ * an identifier
+ */
+ public void setIconId(int id) {
+ _iconId = id;
+ }
+
+ public String toString() {
+ StringBuffer szBuf;
+ szBuf = new StringBuffer();
+ szBuf.append(_threshold);
+ szBuf.append(": [");
+ szBuf.append(_iconId);
+ szBuf.append("]");
+ return szBuf.toString();
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyEditorPanel.java b/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyEditorPanel.java
new file mode 100755
index 0000000..e0b6291
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/color/HitQualityPolicyEditorPanel.java
@@ -0,0 +1,215 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.color;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+
+import com.plealog.genericapp.api.EZEnvironment;
+
+/**
+ * This is the editor of quality policy.
+ *
+ * @author Patrick G. Durand
+ */
+public class HitQualityPolicyEditorPanel extends HitPolicyEditorBasePanel {
+ private static final long serialVersionUID = 7552474180799736916L;
+
+ private JComboBox[] _quality;
+
+ private static final String MSG_HEAD = "Quality policy will be applied using";
+ private static final String HELP_MSG = "This panel defines the value ranges used to set Hit quality. "
+ + "Values set for each range have to be defined by decreasing order. "
+ + "Only use positive real numbers; scientific notation is allowed (e.g. 1e-3).";
+
+ /**
+ * Constructor.
+ *
+ * @param nb
+ * of quality classes to use
+ */
+ public HitQualityPolicyEditorPanel(int nClasses) {
+ super();
+ if (nClasses == 0)
+ nClasses = 4;
+ _nClasses = nClasses;
+ buildGUI(nClasses);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param policy
+ * a quality policy
+ *
+ * @param valueType
+ * one of ColorColicyConfig.XXX_FIELD
+ */
+ public HitQualityPolicyEditorPanel(HitQualityPolicyAtom[] policy,
+ int valueType) {
+ super();
+ if (policy == null)
+ _nClasses = 4;
+ else
+ _nClasses = policy.length;
+ buildGUI(_nClasses);
+ setData(policy);
+ setValueType(valueType);
+ }
+
+ /**
+ * Set a quality policy.
+ *
+ * @param policy
+ * the quality policy
+ *
+ * */
+ public void setData(HitQualityPolicyAtom[] policy) {
+ int i;
+
+ if (policy == null || policy.length != _nClasses)
+ return;
+ for (i = 0; i < _nClasses; i++) {
+ _valuesTo[i].setText(String.valueOf(policy[i].getThreshold()));
+ _quality[i].setSelectedIndex(policy[i].getIconId());
+ }
+ }
+
+ /**
+ * Get the quality policy.
+ *
+ * @return the quality policy
+ *
+ * */
+ public HitQualityPolicyAtom[] getData() {
+ HitQualityPolicyAtom[] policy = null;
+ String val;
+ int i, idx;
+ double[] thresholds;
+
+ thresholds = new double[_nClasses];
+ for (i = 0; i < _nClasses - 1; i++) {
+ val = _valuesTo[i].getText();
+ if (val.length() == 0) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(),
+ MSG_ERR2);
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ try {
+ thresholds[i] = Double.valueOf(val);
+ if (thresholds[i] < 0)
+ throw new NumberFormatException();
+ } catch (Exception e) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(),
+ BAD_VALUE.format(new Object[] { val }));
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ }
+ for (i = 0; i < _nClasses - 2; i++) {
+ if (thresholds[i + 1] > thresholds[i]) {
+ EZEnvironment.displayWarnMessage(EZEnvironment.getParentFrame(),
+ MSG_ERR1);
+ _valuesTo[i].grabFocus();
+ return null;
+ }
+ }
+ policy = new HitQualityPolicyAtom[_nClasses];
+ for (i = 0; i < _nClasses - 1; i++) {
+ policy[i] = new HitQualityPolicyAtom();
+ policy[i].setThreshold(thresholds[i]);
+ idx = _quality[i].getSelectedIndex();
+ policy[i].setQualityIcon(ColorPolicyConfigImplem.QUALITY_SMILEY[idx]);
+ policy[i].setIconId(idx);
+
+ }
+ i = _nClasses - 1;
+ policy[i] = new HitQualityPolicyAtom();
+ policy[i].setThreshold(0);
+ idx = _quality[i].getSelectedIndex();
+ policy[i].setQualityIcon(ColorPolicyConfigImplem.QUALITY_SMILEY[idx]);
+ policy[i].setIconId(idx);
+ return policy;
+ }
+
+ private JComboBox createQualityCombo() {
+ JComboBox c = new JComboBox<>();
+ c.setFont(DEF_FNT);
+ c.setRenderer(new ComboBoxRenderer());
+ for (int i = 0; i < ColorPolicyConfigImplem.QUALITY_SMILEY.length; i++) {
+ c.addItem(new Integer(i));
+ }
+ return c;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void initSpecialComponents(int nClasses) {
+ _quality = new JComboBox[nClasses];
+ for (int i = 0; i < nClasses; i++) {
+ _quality[i] = createQualityCombo();
+ }
+ }
+
+ protected JComponent getSpecialComponent(int i) {
+ return _quality[i];
+ }
+
+ protected String getHeaderMsg() {
+ return MSG_HEAD;
+ }
+
+ protected String getHelpMsg() {
+ return HELP_MSG;
+ }
+
+ private class ComboBoxRenderer extends JLabel implements
+ ListCellRenderer {
+ private static final long serialVersionUID = -3429945853105749966L;
+ private Dimension DEF_DIM = new Dimension(20, 20);
+
+ public ComboBoxRenderer() {
+ setOpaque(true);
+ setHorizontalAlignment(CENTER);
+ setVerticalAlignment(CENTER);
+ }
+
+ public Dimension getPreferredSize() {
+ return DEF_DIM;
+ }
+
+ public Component getListCellRendererComponent(
+ JList extends Integer> list, Integer value, int index,
+ boolean isSelected, boolean cellHasFocus) {
+ if (isSelected) {
+ setBackground(list.getSelectionBackground());
+ setForeground(list.getSelectionForeground());
+ } else {
+ setBackground(list.getBackground());
+ setForeground(list.getForeground());
+ }
+ setIcon(ColorPolicyConfigImplem.QUALITY_SMILEY[value]);
+ return this;
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/config/directory/DirManager.java b/src/bzh/plealog/blastviewer/config/directory/DirManager.java
new file mode 100644
index 0000000..5b29db2
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/config/directory/DirManager.java
@@ -0,0 +1,120 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.config.directory;
+
+import java.io.File;
+import java.io.IOException;
+
+import bzh.plealog.bioinfo.ui.blast.config.AbstractPropertiesConfig;
+import bzh.plealog.bioinfo.util.CoreUtil;
+
+import com.plealog.genericapp.api.EZApplicationBranding;
+import com.plealog.genericapp.api.file.EZFileUtils;
+
+/**
+ * This class handle the directories used by the software to store some internal
+ * stuffs.
+ *
+ * @author Patrick G. Durand
+ */
+public class DirManager extends AbstractPropertiesConfig {
+ public static final String NAME = "DirManager";
+
+ private static final String DOC_DIR = "documents";
+
+ private static final String BLAST_DOCS = "blast";
+
+ private String _appPath;
+ private String _blastDataPath;
+
+ /**
+ * Default constructor.
+ *
+ * Such an object is supposed to be created at application startup and stored
+ * in the ConfigManager system. Then access this configuration using
+ * ConfigManager.
+ */
+ public DirManager() {
+ setName(NAME);
+ }
+
+ private void createPath(String path) throws IOException {
+ File f;
+
+ f = new File(path);
+ if (f.exists()) {
+ return;
+ }
+ if (!f.mkdirs()) {
+ throw new IOException("unable to create: " + path);
+ }
+ }
+
+ /**
+ * Get the full path to the directory where the application stores its stuffs.
+ *
+ * It is worth noting that the method will try to create that path if it does
+ * not exist.
+ *
+ * @return a path. Note that path is terminated with OS-dependent path
+ * separator character.
+ *
+ * @throws IOException
+ * if the method failed to create the path.
+ */
+ public String getApplicationDataPath() throws IOException {
+ if (_appPath != null)
+ return _appPath;
+
+ _appPath = EZFileUtils.terminatePath(System.getProperty("user.home"))
+ + "."
+ + EZFileUtils.terminatePath(CoreUtil.replaceAll(
+ EZApplicationBranding.getAppName(), " ", "_"));
+
+ createPath(_appPath);
+
+ return _appPath;
+ }
+
+ /**
+ * Get the full path to the directory where the application stores BLAST
+ * results retrieved from a remote server.
+ *
+ * It is worth noting that the method will try to create that path if it does
+ * not exist.
+ *
+ * @return a path. Note that path is terminated with OS-dependent path
+ * separator character.
+ *
+ * @throws IOException
+ * if the method failed to create the path.
+ */
+ public String getBlastDataPath() throws IOException {
+ if (_blastDataPath != null)
+ return _blastDataPath;
+
+ _blastDataPath = getApplicationDataPath()
+ + EZFileUtils.terminatePath(DOC_DIR)
+ + EZFileUtils.terminatePath(BLAST_DOCS);
+
+ createPath(_blastDataPath);
+
+ return _blastDataPath;
+ }
+
+
+}
diff --git a/src/bzh/plealog/blastviewer/hittable/BVHitTable.java b/src/bzh/plealog/blastviewer/hittable/BVHitTable.java
new file mode 100644
index 0000000..e6a29ef
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/hittable/BVHitTable.java
@@ -0,0 +1,54 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.hittable;
+
+import javax.swing.Action;
+
+import bzh.plealog.bioinfo.ui.blast.hittable.BlastHitTable;
+import bzh.plealog.blastviewer.actions.EditColorPolicyAction;
+import bzh.plealog.blastviewer.resources.BVMessages;
+
+/**
+ * Specific implementation of a BlastHitTable that adds some more controls.
+ *
+ * @author Patrick G. Durand
+ */
+public class BVHitTable extends BlastHitTable {
+
+ private static final long serialVersionUID = -5195223880667175259L;
+
+ public BVHitTable() {
+ super();
+ }
+
+ public BVHitTable(String id) {
+ super(id);
+ }
+
+ @Override
+ protected Action[] getTableSpecialActionsForMenu() {
+ EditColorPolicyAction editAct;
+ Action[] acts;
+
+ acts = new Action[1];
+ editAct = new EditColorPolicyAction(BVMessages.getString("BVHitTable.tool.edt.clr"));
+ editAct.setParent(_blastList);
+ acts[0] = editAct;
+ return acts;
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/hittable/BVHitTableFactoryImplem.java b/src/bzh/plealog/blastviewer/hittable/BVHitTableFactoryImplem.java
new file mode 100644
index 0000000..c0fb06a
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/hittable/BVHitTableFactoryImplem.java
@@ -0,0 +1,35 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.hittable;
+
+import bzh.plealog.bioinfo.ui.blast.config.HitTableFactory;
+import bzh.plealog.bioinfo.ui.blast.hittable.BlastHitTable;
+
+/**
+ * Factory to use to create instances of BVHitTable.
+ *
+ * @author Patrick G. Durand
+ */
+public class BVHitTableFactoryImplem implements HitTableFactory{
+
+ /**
+ * Create a new instance of a BlastHitTable.
+ */
+ public BlastHitTable createViewer(){
+ return new BVHitTable(null);
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/resources/BVMessages.java b/src/bzh/plealog/blastviewer/resources/BVMessages.java
new file mode 100644
index 0000000..8bdc2ef
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/resources/BVMessages.java
@@ -0,0 +1,50 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.resources;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * This class defines a utility class used to read the content of a resource
+ * file where the GUI localized strings are saved.
+ *
+ * @author Patrick G. Durand
+ */
+public class BVMessages {
+ private static final String BUNDLE_NAME =
+ BVMessages.class.getPackage().getName()+".messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE =
+ ResourceBundle.getBundle(BUNDLE_NAME);
+
+ /**
+ * Default constructor not available. Use this class as static.
+ */
+ private BVMessages() {}
+
+ /**
+ * Returns a value associated to a given key.
+ */
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/resources/circle_all.gif b/src/bzh/plealog/blastviewer/resources/circle_all.gif
new file mode 100755
index 0000000..251df05
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/circle_all.gif differ
diff --git a/src/bzh/plealog/blastviewer/resources/colorpolicy.cfg b/src/bzh/plealog/blastviewer/resources/colorpolicy.cfg
new file mode 100755
index 0000000..8c18cc8
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/resources/colorpolicy.cfg
@@ -0,0 +1,74 @@
+#
+# Colors Configuration for KoriBlast Data Table.
+#
+# This file relies on 'key=value' pairs. Keys are reserved words of the
+# system and cannot be changed. Values on the other hand can be changed
+# as needed.
+#
+
+# Hit List color policy classes. Each class defined a value threshold
+# and an associated graphical property (such as color). Classes have
+# to be declared by decreasing order of the threshold value, so that
+# class[i+1] and class[i] define a valid range. During table rendering,
+# KoriBlast compares an HSP score value (see key hlc.field) with each
+# threshold range to associate the corresponding graphical property.
+hitListColorClasses=c1,c2,c3,c4,c5
+# Field used by the software to associate the graphical property.
+# Accepted values range from 0 to 4, and correspond to the use of
+# bit score, E-Value, identity, similarity, or gaps.
+hlc.field=0
+hlc.c1.threshold=200.0
+hlc.c1.color=255,102,102
+hlc.c2.threshold=80.0
+hlc.c2.color=254,103,254
+hlc.c3.threshold=50.0
+hlc.c3.color=0,177,0
+hlc.c4.threshold=40.0
+hlc.c4.color=128,128,255
+hlc.c5.threshold=0.0
+hlc.c5.color=0,0,0
+
+# Hit List quality policy classes.
+hitListQualityClasses=c1,c2,c3,c4,c5
+hlq.field=0
+hlq.c1.threshold=200
+# associated quality icon (a smiley). This index refers to the type of
+# quality smiley to be displayed in the hit list (0: green smiley, 1:
+# yellow, 2: orange and 3: red).
+hlq.c1.threshold=200.0
+hlq.c1.qualityCode=0
+hlq.c2.threshold=80.0
+hlq.c2.qualityCode=0
+hlq.c3.threshold=50.0
+hlq.c3.qualityCode=1
+hlq.c4.threshold=40.0
+hlq.c4.qualityCode=2
+hlq.c5.threshold=0.0
+hlq.c5.qualityCode=3
+
+#
+# Use reverse video mode for Multiple Sequence Alignment.
+#
+inverse.video=true
+
+#
+# Color used in tables to set the background every two rows.
+#
+table.bk.color=228,236,236
+
+#
+# Color are generated with an alpha channel
+#
+clr.transparency=true
+
+#
+# Use antialias for better graphics rendering
+#
+antialias=true
+
+#
+# Default color to use to display features
+#
+feature.clr=0,102,102
+
+
diff --git a/src/bzh/plealog/blastviewer/resources/documents.png b/src/bzh/plealog/blastviewer/resources/documents.png
new file mode 100755
index 0000000..e621681
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/documents.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/download.png b/src/bzh/plealog/blastviewer/resources/download.png
new file mode 100755
index 0000000..2dc1549
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/download.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/logger.png b/src/bzh/plealog/blastviewer/resources/logger.png
new file mode 100644
index 0000000..621ed91
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/logger.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/messages.properties b/src/bzh/plealog/blastviewer/resources/messages.properties
new file mode 100755
index 0000000..5b68ae1
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/resources/messages.properties
@@ -0,0 +1,30 @@
+DocumentViewer.docs.mnu=Documents
+DocumentViewer.docs.tab2=Log
+
+OpenBlastList.open.name=Open
+OpenBlastList.open.tip=Open BLAST results
+OpenBlastList.openrid.name=Fetch
+OpenBlastList.openrid.tip=Fetch BLAST results from NCBI
+
+QBlaster.analyseFileError=Unable to get execution status from BLAST server
+QBlastRetriever.err=Result file not yet available.
+
+FetchFromNcbiAction.err1=unable to save Blast results file
+FetchFromNcbiAction.err2=Unable to create BLAST XML file\:
+FetchFromNcbiAction.msg1=Connecting to NCBI...
+FetchFromNcbiAction.msg2=Result retrieved... saving in a local file...
+FetchFromNcbiAction.msg3=BLAST results save in\:
+FetchFromNcbiAction.msg4=Opening viewer...
+FetchFromNcbiAction.lbl=Enter an NCBI Blast Request ID\:
+
+OpenFileAction.lbl=Open BLAST file
+OpenFileAction.err=Unable to load BLAST file:
+
+HitPolicyEditorDialog.btn1=Apply
+HitPolicyEditorDialog.btn2=Cancel
+HitPolicyEditorDialog.header=Hit List Graphics Properties
+HitPolicyEditorDialog.tab1=Colors
+HitPolicyEditorDialog.tab2=Quality
+HitPolicyEditorDialog.err=No color policy configuration file available.
+
+BVHitTable.tool.edt.clr=Edit colors
\ No newline at end of file
diff --git a/src/bzh/plealog/blastviewer/resources/open.png b/src/bzh/plealog/blastviewer/resources/open.png
new file mode 100755
index 0000000..1a5b0fc
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/open.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/smiley_g.png b/src/bzh/plealog/blastviewer/resources/smiley_g.png
new file mode 100755
index 0000000..91d0f9b
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/smiley_g.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/smiley_o.png b/src/bzh/plealog/blastviewer/resources/smiley_o.png
new file mode 100755
index 0000000..7ad5e3d
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/smiley_o.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/smiley_r.png b/src/bzh/plealog/blastviewer/resources/smiley_r.png
new file mode 100755
index 0000000..20a2d06
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/smiley_r.png differ
diff --git a/src/bzh/plealog/blastviewer/resources/smiley_y.png b/src/bzh/plealog/blastviewer/resources/smiley_y.png
new file mode 100755
index 0000000..616a6e4
Binary files /dev/null and b/src/bzh/plealog/blastviewer/resources/smiley_y.png differ
diff --git a/src/bzh/plealog/blastviewer/util/BlastViewerOpener.java b/src/bzh/plealog/blastviewer/util/BlastViewerOpener.java
new file mode 100644
index 0000000..538b7d6
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/util/BlastViewerOpener.java
@@ -0,0 +1,125 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.util;
+
+import java.awt.Color;
+import java.awt.Dimension;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+
+import com.plealog.genericapp.api.EZEnvironment;
+import com.plealog.genericapp.ui.desktop.GDesktopPane;
+import com.plealog.genericapp.ui.desktop.GInternalFrame;
+
+/**
+ * Utility class to enable interaction with the GDesktopPane.
+ *
+ * @author Patrick G. Durand
+ */
+public class BlastViewerOpener {
+ private static GDesktopPane _desktop;
+ private static JLabel _helperField;
+
+ public static ImageIcon WORKING_ICON = EZEnvironment
+ .getImageIcon("circle_all.gif");
+ private static Color RUNNING_TASK_COLOR = Color.GREEN.darker();
+ private static Color NOT_RUNNING_TASK_COLOR;
+
+ /**
+ * Register the desktop to this component.
+ */
+ public static void setDesktop(GDesktopPane desktop) {
+ _desktop = desktop;
+ }
+
+ /**
+ * Return the help field.
+ */
+ public static JComponent getHelperField() {
+ if (_helperField == null) {
+ _helperField = new JLabel();
+ _helperField.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ _helperField.setOpaque(true);
+ _helperField.setFocusable(false);
+ NOT_RUNNING_TASK_COLOR = _helperField.getBackground();
+ }
+ return _helperField;
+ }
+
+ /**
+ * Set a message during some operation.
+ */
+ public static void setHelperMessage(String msg) {
+ if (msg == null) {
+ cleanHelperMessage();
+ }
+ _helperField.setText(msg);
+ _helperField.setIcon(WORKING_ICON);
+ _helperField.setBackground(RUNNING_TASK_COLOR);
+ }
+
+ /**
+ * Clear the message.
+ */
+ public static void cleanHelperMessage() {
+ _helperField.setText("");
+ _helperField.setIcon(null);
+ _helperField.setBackground(NOT_RUNNING_TASK_COLOR);
+ }
+
+ /**
+ * Add a new BlastViewer to this desktop.
+ *
+ * @param viewer the viewer to add. Should be a Blast Viewer component.
+ * Cannot be null.
+ * @param title the internal frame title. Cannot be null.
+ * @param icon the internal frame icon. Can be null.
+ */
+ public static void displayInternalFrame(JComponent viewer, String title,
+ ImageIcon icon) {
+ int delta = 20;
+
+ GInternalFrame iFrame = new GInternalFrame(viewer, // the viewer
+ title, // iFrame title will be the entry ID
+ true, true, true, // resizable, closable, maximizable: allowed
+ false);// does not allow iconifiable: not working with JRE1.7+ on OSX !
+ // Known bug.
+ if (icon != null)
+ iFrame.setFrameIcon(icon);
+ Dimension dim = _desktop.getSize();
+ iFrame.setVisible(false);
+ _desktop.addGInternalFrame(iFrame);
+ iFrame.setSize(dim);
+ iFrame.setBounds(delta, delta, dim.width - 2 * delta, dim.height - 2
+ * delta);
+ // for future use...
+ // iFrame.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
+ // iFrame.addInternalFrameListener(new IFrameListener(navigator));
+ iFrame.setVisible(true);
+ }
+
+ /**
+ * Add a new BlastViewer to this desktop.
+ */
+ public static void displayInternalFrame(JComponent viewer) {
+ displayInternalFrame(viewer, "Blast Results", null);
+ }
+
+}
diff --git a/src/bzh/plealog/blastviewer/util/HTTPBasicEngine.java b/src/bzh/plealog/blastviewer/util/HTTPBasicEngine.java
new file mode 100644
index 0000000..815da30
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/util/HTTPBasicEngine.java
@@ -0,0 +1,169 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.plealog.genericapp.api.log.EZLogger;
+
+/**
+ * A very basic HTTPclient.
+ *
+ * @author Patrick G. Durand
+ */
+public class HTTPBasicEngine {
+ public static String TMP_FILE_PREFIX = "http";
+ public static String TMP_FILE_SUFIX = ".tmp";
+
+ public static int CONNECT_TIMEOUT = 5000; // 5 seconds
+ public static int SOCKET_TIMEOUT = 60000; // 1 minute
+
+ private static void closeConnection(InputStream ins) {
+ if (ins != null) {
+ try {
+ ins.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ public static File doGet(String url) {
+ return doGet(url, null);
+ }
+ /**
+ * Do a HTTP GET using the provided url.
+ *
+ * @param url
+ * the URL. HTTP and HTTPS are supported.
+ *
+ * @param header_attrs
+ * attributes to set in header connection
+ * @return a file containing the result. Returned file is set to deleteOnExit,
+ * so you do not have to worry about deleting it.
+ *
+ * @throws HTTPEngineException
+ * if something wrong occurs.
+ */
+ // Tutorial:
+ // http://stackoverflow.com/questions/2793150/using-java-net-urlconnection-to-fire-and-handle-http-requests
+ public static File doGet(String url, Map header_attrs) {
+ InputStream ins = null;
+ byte[] buffer = new byte[4096];
+ int n = -1;
+
+ // this is a very, very basic implementation to handle HTTP Get transactions
+ // using URL APIs (e.g. NCBI eUtils, Ensembl, etc.). May need optimization
+ // for more powerful needs...
+ // Possible upgrade: use Jersey to deal with web services?
+
+ // 1. prepare a temporary file to receive answer
+ File answerFile = null;
+
+ EZLogger.debug(url);
+ try {
+ answerFile = File.createTempFile(TMP_FILE_PREFIX, TMP_FILE_SUFIX);
+ answerFile.deleteOnExit();
+ EZLogger.debug(answerFile.getAbsolutePath());
+ } catch (IOException e) {
+ EZLogger.warn(e.toString());
+ throw new HTTPEngineException("Failed to create response file", url, HTTPEngineException.HTTPEX_TMP_FILE_ERROR);
+ }
+
+ // 2. run the HTTP GET method
+ try (OutputStream output = new FileOutputStream(answerFile)) {
+ // open connection to the remote server
+ URL myurl = new URL(url);
+ HttpURLConnection con = (HttpURLConnection) myurl.openConnection();
+ if (header_attrs!=null){
+ Iterator attrIter = header_attrs.keySet().iterator();
+ String key;
+ while(attrIter.hasNext()){
+ key = attrIter.next();
+ //con.setRequestProperty("Accept", "text/xml");
+ con.setRequestProperty(key, header_attrs.get(key));
+ }
+ }
+ con.setConnectTimeout(CONNECT_TIMEOUT);
+ con.setReadTimeout(SOCKET_TIMEOUT);
+
+ // ensembl and ebi provides additional header fields.
+ // see
+ // http://www.ebi.ac.uk/Tools/webservices/services/eb-eye_rest#additional_information_in_http_response_header
+ // https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Response-Codes
+ // some of these header values can be used to adapt connection to remote
+ // server. For now, we just monitor them... TODO: use them!
+ EZLogger.debug(con.getHeaderFields().toString());
+
+ // response code is checked before opening input stream
+ if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ throw new HTTPEngineException("Failed to connect to server", url, con.getResponseCode());
+ }
+
+ // 200 OK: read server answer
+ ins = con.getInputStream();
+ while ((n = ins.read(buffer)) != -1) {
+ output.write(buffer, 0, n);
+ }
+ output.flush();
+ } catch (HTTPEngineException hee) {
+ throw hee;
+ } catch (SocketTimeoutException ste) {
+ throw new HTTPEngineException("Server does not answer (time out)", url, HTTPEngineException.HTTPEX_TIMEOUT);
+ } catch (Exception e) {
+ // we Log the HTTP or IO error since message is usually out of concern
+ // for the end user. However, a log trace is always useful.
+ EZLogger.warn(e.toString());
+ // then raises a "generic" exception
+ throw new HTTPEngineException("Unable to write in response file", url, HTTPEngineException.HTTPEX_WRITE_FILE_ERROR);
+ }
+ finally {
+ // 3. close HTTP connection
+ closeConnection(ins);
+ }
+ // 4. return answer
+ return answerFile;
+ }
+
+ /**
+ * Figures out whether or not a particular web server is available.
+ */
+ public static boolean isServerAvailable(String url) {
+ try {
+ URL myurl = new URL(url);
+ HttpURLConnection httpConn = (HttpURLConnection)myurl.openConnection();
+ httpConn.setInstanceFollowRedirects(false);
+ httpConn.setRequestMethod("HEAD");
+ httpConn.setConnectTimeout(CONNECT_TIMEOUT);
+ httpConn.connect();
+ EZLogger.debug(httpConn.getHeaderFields().toString());
+ } catch (Exception e) {
+ EZLogger.warn(e.toString());
+ return false;
+ }
+ //if we hit this line, server is available
+ return true;
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/util/HTTPEngineException.java b/src/bzh/plealog/blastviewer/util/HTTPEngineException.java
new file mode 100644
index 0000000..137d966
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/util/HTTPEngineException.java
@@ -0,0 +1,87 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package bzh.plealog.blastviewer.util;
+
+public class HTTPEngineException extends RuntimeException {
+
+ private static final long serialVersionUID = 4332507260541550768L;
+
+ private int httpCode;
+ private String url;
+
+ /** 1001: unable to create response file, i.e. the file in which HTTPBasicEngine
+ * writes server answer.
+ */
+ public static final int HTTPEX_TMP_FILE_ERROR = 1001;
+ /** 1002: unable to write in response file.
+ */
+ public static final int HTTPEX_WRITE_FILE_ERROR = 1002;
+
+ /** 1003: time out.
+ */
+ public static final int HTTPEX_TIMEOUT = 1003;
+
+ @SuppressWarnings("unused")
+ private HTTPEngineException() { }
+
+ public HTTPEngineException(String message, String url, int httpcode) {
+ super(message);
+ this.url = url;
+ this.httpCode = httpcode;
+ }
+
+ /**
+ * Return the URL responsible for the exception.
+ */
+ public String getUrl(){
+ return url;
+ }
+
+ /**
+ * Return standard HTTP code. In addition, we define some additional values using
+ * HTTPEX_xxx constants.
+ * */
+ public int getHttpCode() {
+ return httpCode;
+ }
+
+ /**
+ * Figures out whether or not we have a problem with response file.
+ */
+ public boolean isTmpFileError(){
+ return httpCode>=1000;
+ }
+
+ /**
+ * Figures out whether or not we have an HTTP error code of class 5xx.
+ */
+ public boolean isServerError(){
+ return httpCode>=500;
+ }
+ /**
+ * Figures out whether or not we have an HTTP error code 400.
+ */
+ public boolean isBadRequest(){
+ return httpCode==400;
+ }
+ /**
+ * Figures out whether or not we have an HTTP error code 404.
+ */
+ public boolean isWrongUrl(){
+ return httpCode==400;
+ }
+}
diff --git a/src/bzh/plealog/blastviewer/version.properties b/src/bzh/plealog/blastviewer/version.properties
new file mode 100644
index 0000000..a57e0ae
--- /dev/null
+++ b/src/bzh/plealog/blastviewer/version.properties
@@ -0,0 +1,13 @@
+# package name
+prg.name=blastviewer
+# UI name
+prg.app.name=BLAST-Viewer
+# release prior to 5: KoriBlast/ngKLAST suite of software
+prg.version=5.0.0
+# Who did what and when
+prg.copyright=(c) 2003-2016, Patrick G. Durand
+prg.provider=Plealog
+# Place of the source code
+prg.url=https://github.com/pgdurand
+# Affero-GPL license
+prg.license=Licensed under the the GNU Affero General Public License, Version 3.0. https://www.gnu.org/licenses/agpl-3.0.txt
diff --git a/src/test/HitColorPolicyEditorPanelTest.java b/src/test/HitColorPolicyEditorPanelTest.java
new file mode 100755
index 0000000..524edd7
--- /dev/null
+++ b/src/test/HitColorPolicyEditorPanelTest.java
@@ -0,0 +1,72 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package test;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import bzh.plealog.blastviewer.config.color.ColorPolicyConfigImplem;
+import bzh.plealog.blastviewer.config.color.HitColorPolicyAtom;
+import bzh.plealog.blastviewer.config.color.HitColorPolicyEditorPanel;
+
+public class HitColorPolicyEditorPanelTest {
+ public static void main(String[] args) {
+ JFrame frame = new JFrame("Hello");
+ JPanel pnl = new JPanel(new BorderLayout());
+ frame.addWindowListener(new ApplicationCloser());
+ Container contentPane = frame.getContentPane();
+ final HitColorPolicyEditorPanel toto = new HitColorPolicyEditorPanel(4);
+ toto.setValueType(ColorPolicyConfigImplem.GAPS_FIELD);
+ pnl.add(toto, BorderLayout.CENTER);
+ JButton checker = new JButton("check values!");
+ checker.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ HitColorPolicyAtom[] policy = toto.getData();
+ if (policy == null) {
+ return;
+ }
+ System.out.println("Value type: "
+ + ColorPolicyConfigImplem.FIELDS[toto.getValueType()]);
+ System.out.println("Policy: ");
+ for (int i = 0; i < policy.length; i++) {
+ System.out.println("[" + i + "] Threshold = "
+ + policy[i].getThreshold());
+ System.out.println(" Color = " + policy[i].getClrRepr());
+ }
+ }
+ });
+ pnl.add(checker, BorderLayout.SOUTH);
+ contentPane.add(pnl);
+ frame.pack();
+ // frame.setSize(200, 600);
+ frame.setVisible(true);
+ }
+
+ private static class ApplicationCloser extends WindowAdapter {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ }
+}
diff --git a/src/test/HitQualityPolicyEditorPanelTest.java b/src/test/HitQualityPolicyEditorPanelTest.java
new file mode 100755
index 0000000..3e71429
--- /dev/null
+++ b/src/test/HitQualityPolicyEditorPanelTest.java
@@ -0,0 +1,74 @@
+/* Copyright (C) 2003-2016 Patrick G. Durand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/agpl-3.0.txt
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ */
+package test;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import bzh.plealog.bioinfo.ui.config.UISystemConfigurator;
+import bzh.plealog.blastviewer.config.color.ColorPolicyConfigImplem;
+import bzh.plealog.blastviewer.config.color.HitQualityPolicyAtom;
+import bzh.plealog.blastviewer.config.color.HitQualityPolicyEditorPanel;
+
+public class HitQualityPolicyEditorPanelTest {
+ public static void main(String[] args) {
+ UISystemConfigurator.initializeSystem();
+ JFrame frame = new JFrame("Hello");
+ JPanel pnl = new JPanel(new BorderLayout());
+ frame.addWindowListener(new ApplicationCloser());
+ Container contentPane = frame.getContentPane();
+ final HitQualityPolicyEditorPanel toto = new HitQualityPolicyEditorPanel(4);
+ toto.setValueType(ColorPolicyConfigImplem.GAPS_FIELD);
+ pnl.add(toto, BorderLayout.CENTER);
+ JButton checker = new JButton("check values!");
+ checker.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ HitQualityPolicyAtom[] policy = toto.getData();
+ if (policy == null) {
+ return;
+ }
+ System.out.println("Value type: "
+ + ColorPolicyConfigImplem.FIELDS[toto.getValueType()]);
+ System.out.println("Policy: ");
+ for (int i = 0; i < policy.length; i++) {
+ System.out.println("[" + i + "] Threshold = "
+ + policy[i].getThreshold());
+ System.out.println(" Icon Id = " + policy[i].getIconId());
+ }
+ }
+ });
+ pnl.add(checker, BorderLayout.SOUTH);
+ contentPane.add(pnl);
+ frame.pack();
+ // frame.setSize(200, 600);
+ frame.setVisible(true);
+ }
+
+ private static class ApplicationCloser extends WindowAdapter {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ }
+}
diff --git a/start.sh b/start.sh
new file mode 100755
index 0000000..c826be7
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Script used to start BlastViewer during development cycles. It requires
+# BlastViewer be compiled using: ant makejar
+
+V_PROVIDER=EBI
+
+# *** Application home
+PL_APP_HOME=.
+PL_MAIN_CLASS=bzh.plealog.blastviewer.BlastViewer
+
+# *** Java VM
+PL_JAVA_VM=$JAVA_HOME/bin/java
+PL_JAVA_ARGS="-Xms2048m -Xmx2048m -DV_DEBUG=true "
+
+# *** JARs section
+PL_JAR_LIST_TMP=`\ls $PL_APP_HOME/jar/*.jar`
+PL_JAR_LIST=`echo $PL_JAR_LIST_TMP | sed 's/ /:/g'`
+PL_JAR_LIST2_TMP=`\ls $PL_APP_HOME/distrib/*.jar`
+PL_JAR_LIST=${PL_JAR_LIST}:`echo $PL_JAR_LIST2_TMP | sed 's/ /:/g'`
+
+# *** start application
+$PL_JAVA_VM $PL_JAVA_ARGS -classpath $PL_JAR_LIST $PL_MAIN_CLASS
+