pax_global_header00006660000000000000000000000064117445152720014522gustar00rootroot0000000000000052 comment=59920029fb67eb026aa69c6828aa7590c0493313 jscribble-1.7.7/000077500000000000000000000000001174451527200134755ustar00rootroot00000000000000jscribble-1.7.7/.gitignore000066400000000000000000000003401174451527200154620ustar00rootroot00000000000000*.class *.jar *.orig *.properties .classpath .project .testrun CHANGELOG VersionName.java de.mo doc/jscribble.1 doc/keylist.rst html install_files/completion/jscribble javadoc jscribble.pot jscribble_*.tar.gz surrogates.tar jscribble-1.7.7/LICENSE000066400000000000000000000432541174451527200145120ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. jscribble-1.7.7/README.rst000066400000000000000000000032321174451527200151640ustar00rootroot00000000000000jscribble ========= building from source -------------------- just the program ~~~~~~~~~~~~~~~~ You can obtain a tarball with the latest source code from the [jscribble website](http://martin-ueding.de/jscribble/) The following software is needed to compile this program: make Build system. Java Development Kit Java compiler, version 1.6 works. xgettext, msgfmt Parses source code for translation calls and converts translation file into the Java property format. php5-cli Used for various file creations, lists all the config entries in the manual page for instance. rst2man Converts reStructuredText into html and manual page. various Linux tools find, rm, touch, bash To build the main program, simply invoke make:: make Then you can just launch the program with a `java -jar jscribble.jar`. In case you use Linux and want to install it for all users, run this:: make install # as root Now it can be launched with a simple `jscribble`. developer documentation ~~~~~~~~~~~~~~~~~~~~~~~ In case you want to build all the developer documentation, you might want to install these as well: javadoc A HTML documentation generator for Java. This should be included with the Java Development Kit (JDK). To build the documentation, call:: build dev-doc unit tests ~~~~~~~~~~ jscribble has a couple test cases which can be run with junit. junit Unit test runner for Java. To run the tests, call ``make test``. contributing ------------ If you like, you can send patches from the latest source checkout. Please include which version you based on, so that I can merge. If you care for the git repository, please let me know. jscribble-1.7.7/artwork/000077500000000000000000000000001174451527200151665ustar00rootroot00000000000000jscribble-1.7.7/artwork/banner.svg000066400000000000000000000114241174451527200171560ustar00rootroot00000000000000 image/svg+xml jscribble jscribble-1.7.7/artwork/jscribble.png000066400000000000000000001146401174451527200176410ustar00rootroot00000000000000PNG  IHDRxsRGBbKGD pHYs B(xtIME  @ IDATxy\T (. Zk_5R2-﹛{+nhn n+&80_/^`3ss=y@!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!DH!A@lJ'6i*!B秜KŞ$)$B|zx`4H\H gxI>$#"$BW|q:֖RJQt/>~)WSWC:!B<3NxB''L'x////ZSW1w\+n޼ݏ\kBL x=$d'uwwIÇ>|8&L 558 - $BX[:gOhmmMşzwtt4  O>?~<Á.i !,Kr1ēzxx燷_...&8L8'|' Bcs.\W񞞞fxk׮9s&6!5{i'y?Xi4+V'ygggj ̙3{:\PH 0-F7ҹ_NXr%AAAܹs'C ԒA!$B<7y~i*TRދ7֭[Ӈ5kdb-8i)!1-*'ӆ I K"NرcꫯHNN~-@ w^Ϫϟ??^{yyacc#b {SNܸq#CwPKVa9R9tԉ}e}(UXH'-%$$/392e }SBi! M<}8ldɒO:goo/",ŋٳ'Y^i! 0O9 K0%Kf-$̓@>JO*Kx~˖-k׮YT+DZH!U&|v9VVV/^'K/_N׮]N:$y30ҹ%J`kk+"DZb]tģ@X&kĺuQC9~j)Yd pcڵ[Y8u`¼OOsB̙ᅬN|@|8@KJ(ԓ,o 80 @ RZHa|Z$F,-h(U nj?Ae$igU3ҹ"EdrsBq bY7EH@8'L rIHrt:w]@i! OϪ:)~j9Y:'xQqqq4lؐ>1@ rIO̪st"gݼyڵks%@s`(Wyzz>$_P!!хS^=3W$0GFUD2e_B<==(0I[n_Z7 J I`jdB_>,?PŃ-F19/777y' !,NK.,YDIBmڕ|vK9r // ( !DK`` @/Ϯ:'K\x5jpmͧPe>O^Tr'sBaoNfHMM߼,7/Oi_hQWѣn ֱ̓՗4IU'='F#֭Ç7GUBzI!8Oߟ/^8;Bab"""V111 Ti! n ]]]8?<'K<͛7={f𫴎ye++++ԡz'''ia!@;wfҥ*@vvvO]:WT)Y:'yЭ['**J 0 u M6e„ +WNZK!D+VЩSH>+0J.\`RNB@ 8uǏXvN&>  ZRJ1sL7n,-'۷oVV{l?x}͛GTT 6!:!*dJ囉;SL]vҊBuؑUVouc l 111,YDFBPF ONrrMQb7Kg@ x??|rB<Ņvؑ).VLϋ2]1f  *yPBB+Vٳw2sLGٍqFhѢB<-Z$pFZȼǢYih?p)/^Lڵ)VB!eʔ!44SNo GvDGG3gRSS_>ZVZZ!Zj1ydRRRorGM*?*cc׀%@5:;wF֭B<Ņ+Wpa͕@i߲wKϏ?iq!]F2e 𻴎_[nbٔ/_K !srr">>]vo HZȲuKPD/_իWB iHHHxvJXf,^KNǺuHHHiӦh4!PoٲEse`(-q')qPΝ3g Ba)]47n<EZ2GǏgmGGG !@666dO0>XE`=ॿ\rlڴŋKo!z%JL3ur13=O:EZ8zTC!%rrrbY7C՗y`b^{ 6PF !0QQQ,Y2k^:?C|o߾MٿBX"Eлw﬛?[#8c dӦMԪUKzG!,ŋ)S :gϭ6^+ѣG,[ƍK5A! >|ӧOg}hN\QkBEGGӲeK Y7ueϔR۷ojժSBat:ʕ#""BǨ"<6\ÃhӦ .\BKhxyx/7)S]v&=&f.22ŋ@=yg gΜ7 ::ZzL!̜۷Ϻ9HZFǣ379r7x#k !f(ɀ':?T}ի:NzN!XFD °Lxt:PǏJƍLi4"##ٽ{wHj`c>`+PG)SׯBp*V)pd—<J ٱuVL/_SNo a"#5 J`*PСCxxxMIIƍ\t+Wpu∉!::LZ- TZKFCH"၇666Bg9r5@8J} ki_wb@dڿS @!}f͚cgg|:9q;wOkkk(Ux{{K@!s㣿) {yp0btO} gk 믿>ϟg͚5ر}tsP ;A~[pvhٜ&B|$x[qpxbZjTZU*G!DѣG7$.j.XU@^sv҅#*⨾rKAT:߈Kp< NކcYիW[BtR:wP@/iq?D$$? f$y!L,]C9]߇|Lٻ 켨s2?@ڵiѢ;vL2rBG`V\ &%qIYT]DX}ݗ3we rFk`8P 5EiXC .OYn,7ug *믿N6mxqvv"ݹs%Kh"ݛݳtA5O˹pw ԭ_T@sirw΀#|z}=rE8x#cՁ5 4uּxyyQHa4ɬYYfyf(hnvKYI?;꬈FwK4rciu/Z@:ۜ܍W&P \]]߿?|HB'N7߰j*t:.:IMUW.j2>(ę{=M|OKJSUuU!2F-xHevz`J: 3% B1'(<[>O,=tܙAQjU ab.__AJJ Z*ͺ܆5-1Pk ,B-4`_ݠI)kG) l>AX$sY+TrP*pK*X`aÆ 6-Z'Y\C~'ƍG||} @xUgĈL4d o%}6Zis| σT SW&p7bzUW?_|aڑ_L Wfܻw/n~thyRuJrqg}ƀȟ?|ʅxA:y1tP"##R| `ؔ!pȥlR@?u $ #ŋ&Mrr2;wd,X[;kh[ޫ-J&}J}W3!C(9xGez7%MԒtP9А34 _!wFPC}ש:-;iA@ll,>>>TR,:_M˖-8p qQ:SāFT \~Ǯ3c Z-UTFr _зo_.]DG ~{waԩL8U)?WFr̙\`h,]_Ç7];3^C}i۶;wcV5&[E.GÆ.Bgp:*phi=w TJ=\5˫Kס ijh3>`T P nk0tPFe`ƍիIMMEn&|1|*ȨQW%]&'/0rp*XkOѩu F>q88M@́V@2еi-5\~96h.BF}JL{4B׺˗+W=z43f !!FMi MNGờ۴iÏ?5E h4~斿r4 yaڲ}R x艺NB0t;etf%hDs 3O@jX>}ׂRS@TzQti?,XVZѻwoRSS #f?B/,ըjM=iӸpUV`aK=z*^s,I8|Y%vQlLJ7n&#} v(s7?OUJT:^y#j@nn,w!XD8jB:Nhٲ%}ʊ0Hd,ϧxF :L2{QzuI/,ʑ#Ghݺ5K,AK@XQ}-;Vxo .܇|tܙc2~xش)>ۈQk/.E00rі9bU$0y/'G2F#ۗUgZ/N:mi27oޤ@y tƍNtOfY_cUT]}#wœPHIU#C aРAUPD2j( B͢zw_VXF[@zoSYݻOFe͵s-0ukw*6dmRZXx/z %N"<Xre=.\~˗/3j(\\\X$sLs96p?t(D3|pʖ-ٳ++ aJΜ9CݺuHMIbH]8N:5,?G-]Ȁ`׮];.Xng Byz=K+ʪ&EN91P 4,i+ӿZ3<`rrrbС?aÆǠ$pCzjS5X}S}W#LƴiСC- ztQ L>&[}777~.]S?_2 r)jىH7[Mst 3xW͎r+…epsl{;S ZIo Z l,:ʁ֯_/G*=:uݻ=;^ N~tWߟAq]XaTk׮bŊ]"?0MpW:Ԅ>{ZWF ֬Yɓ'_8n?7v\{o,݋~U3t56β1jHXJLy׬Y#Gl*UyJ6mN/@Ii5 35Х$1~xʔ)IJJGPPm۶%**6e|6e-5?UV,_ӦM?ݘA*;n*FZV+ <dW?^֭[IHH#SflBʕ9:-sTzJST&Tw2h Yzt0pjԨoaڛʿ,NmÛћPX1ONxx8o+UY&0ղP/ ;;aҿx8ͬ8/12i94mڔC1}tuj̈́fd35~W7U?""ӤIåSE>}:5kĉT,[2^5H"=郵ff)Brg'3^mX !.[FeCzi4 }!"" [;{慁D LOdr^Q[a۷Atxҥ AAAӯVL; e'j%tZ>3"""2dHv'0dG֡;y;аDR9!xiڝQ#xPL ܄=-]>p}yN8!GTD CZ-g{ 8KZ{nݺ?ҩ_t:~79{,=w,z_L" ڤބF7'6m|y]<(Llpm*F6TPp &fg,yw)GTNˌ3puueE2 Ms(vۗ[nIlݽ{:0p@1yJk[~5Vֶ1ǏӮ];?wrrO؂.2ָO^8 NO{>L1mfrt{Z޽{si Nc͘}P~Z/l:UȆ`gʌ3$Çի)[3*~3:/W3/G ȑ#9`%~;ĶVШ$ҡ47DY)ÿ9&.Bٷor ;~\{ 71Qy䳆 U"N޽{|'TZ;vH ϟO|2^VD5ɯd KOZ'O&88 {?#[)f֜I3Jˌ-r:(TgJCߙFh0Tb.\x+WfΝ,X]Sau(n lchҤ ݻwyTbb"}=z ..OjŽIfHWx;vĉlr<2&= HJFfh)dW+£Tr MFhd eYnݺqi ZF U0Sո5% P|y&LݕP׮]QFL4|60=ٚo9,_+V{Ecb(kMFFT0r95),|oo(P1cJ  @uMւܿ?5krT cVʾ}(&[Ѽ_SdZ Ю];;[ok  LI/F"6@ jqW-͘(錿g9Pٱc3gΤpyJ:_%1E`Kw-&թSK! 5a7oNTTͽ៾nޯii6V`AfϞ͟I_6#1RCC9XյQ԰;^c2` 0GѣGh4?&%%qʣjnAf W^&ٌęi_LHzur*8TpvN3ʶ!QG.@RRgΜ#2w\lBٲe9|jςn[+>MYu 4رcҩfLѺuk&MD~[ JK[i5 g¸`kkǸqؼy3ŋ7}&%9*H2RQopSi=9];7!,7JeZ~q4i҄PFPV4}.嬪V޽U2x2Ƴ~CP}X]|yBBB8p+U3;w<Ɍ7p42:k'Q T7k/7e:՜ àPB[cbcccvpլYk-nT*?awvWFQӞ={a:5j6mۛ(Um`5G5 `ӦMҩ&bƌ|y-n|&P&?5D܁J*BV̲w/ST]s MJFqή*/@yzWq]72y45mڔcǎ1x`R*0fdހ4ϟ_W^2ˮ]ƺupoM7eC d2u=v1D'xw L2foYl-:#1PUooglHƨ\Lޤi3}Pm:t Zs8~h k͝;6l WqE4Ϛ)og6)>wJj+hV=/_>lK*˺`YdJPTv!Cy(>|4on􆓲F@< JR*~9d$[.GO>Q՚&g%;tQF8^5F釡|VZEE6.HJ>> >J ^Ǐg޽+Wݗ pϯ ^Nj*|||%DDDi& REe: ͐ RIuZFźu(XG6~8OV:} *rbH2<@E7GC&Zjqǣr+4^nd*& v8KZjťKSsٳtX L3"Xx g :d  D,g7bs*1y`RചLj|$H_ KX2e ŊcE4EÔC[S5XQU,6mbŊN8'?艉̞=NkBgBxZں"xyykntb+Z@H/|gPz_&oL͚5@] &~MRQVDŽ `߾}ҩd,)cc"%%˧2M4Q}}}ٽ{7e˖rȑ'6YK6cLjJ ȫ&9^}.lٲٳ#G9C%i1eK  |gذayz@LL .Dհ蓗^7o>=ssOqG-9=}+ֲ ,}x>$^eHH fĈٳer, j΄1Lр—.~5j'rѢES4 [f5TvVSS | CXX5ksYOr'?sv͗HN&Y=1ߏ-[d8;; ؿ?))0 /L\li8Zjd(cL6I&~zq*O՘rAT 9)s|yO "3>VsWToOfȐ!L6n+a~jkغz !!!TXaÆ7Xtֹ'śO?zt0oY Ț-22>PգYfԫW<_+FE,h72ynX-LS 7oޜ;T 3@](۫nڴsZl;wtRl5SgߜZo~pYጜsN#$$$\3@k ;*HL ҩS'իG>}X~=mCJ05~\SMYZTR#F0dZܹsIHHa@!vCMlJ7X.K$'vY'yi ڽx` *6p/-0 ijzjƌ÷~D܄i{6xKôipww9s&'.=߼2֤$0.ЌI5jDFhذ!E\`չsuH7 b3kbb I>♬:t(GZjGA@dŽW7U?|ڵ2m4m۶q |3zo]a~L2RPAAA,]ׯsu-ZDPPsȞ={nڛ^m;F4?`j&)-tssL⹕/_ݻw駟,\ei8:Я_?vu֬<.aPw]A\pܗ\kYeZ7K[?-35SQ\@AMLQXٗq`X43y^{sϙ{MyGcBBBhӦ zXm7R:\Bڵ> 33SINN&2P݅L!v@Uu. @8;b ݥ=/]u83 tuNK.Ãk׮Ɂ</_.xH7HHQ0YtW nԨ[%`aaU8pk旫`\npVBV< .=j]!4s] P=J*2DqChh(cflo{^ 55Yfѿݻ'V\r)C &IՆ(yB 9`*x`gg'TVU-ĔA}~V4uo|A\]]9|XSz =`|G VZ;U5?>!!!8::r@>G0DGGӻwoƍǏJ .@ @.]0of`I ' & |`υg% ~}$[lCO-1P믿 MN }FO{lrrZzRg_V+VdӦMܹ*U x/o  ׯ_/(z+ -g(E&R%M7] )FիW߿?  T B9̟ٙ?ww%DTTTST; %M`bliڴ[%eN͚5ٷo+W̜A~\|m/]ܹsmۖK#W R@){yl֬n*3gry6&@н>" зo_Epw@ǡ E w!=[1zh_\lyTÇmnz H甹(] t-x"TNA0/@tctX+a f ;ӧ,0@ [JPT ]N4#F… t֍2nk# .} LxyyѮ];Ν;'sݢH@ 96H ^РAܢO@[/m7RN: ֆHȐ[g<(m]bw/@m:`wЬY3*U$V^R:u*AAgqttC ftRtR\GVVIUb `j쇔 ʘ dc@r/G9y$:iYjfk?Ad4.kPΞ=[ Tw o8ʟdzB@;vwD/oLJ:u }IE=mѣG;~#| %Z(6Z tHحA׮]*kzMPPݻwA2G,~Xnnn=zTDyX)D,%)yy?* Iz:h ;Z*N=O yLso@W[}6L69zJbb(TW]|H N B:R*)={''' ..M [>@^K..;Zn͙3g7o9*f@mpO2`^g-Z:t`…;&.@55 K% ,Y®]Z*n@p4J?Z&Ø6ɧ~ʠAX&Q(r[+(xʸL4Q@YVܩJ渹ɻTR>|8 8ۉ"}m1-C(m e˖Ąf]b `m쇤 pT0-ʈCh׮.{j֬o*T;6=YLmb1c9rӢ%:Df*3J X I!`/*aߩS'yJ OТE .?.T|'" ~}U03ݻwӱcGYO@ VZe B߲ ;Ќ/I i{% QR'NpwTP @ @|[.6d_9,66lٲ]vQJ~uhCM3`^gbҥt҅H9ZbŊO2tPU}piY.6[!`/DRrFAHH]v%1 3j4:(/3W YjX)oPXX?(v`Ls/[[[Xd fo'R8FTf͚E~w\x ]^@<eV-])ccc͛/\~7= l!  &P\pvb6X%D"6 HDR5 . |A=S#;Mŋqss嫯"''G RbŢ[+u5\b f|7A~#N<C`1ԃtE38~˭.x1ٸqI&O2Ю .Q 25wܺu BBBHLLdĉT\WWW9s&j•A-vWZCRcL[2lp.@, lD6;RR"ܹ31-2SP+Wȑ#rls`uK l*صkbg!aU ǠW%,u͟*+[n[nDGGӻ(6qTGqIOG1qDҲC2%FX4X^}UFE\\yEO帓$O?lUCR[x ^-FFF<7L6cǒƂnppݯ iii1B!*Uw}ǡC_>nAu~XUca ؾ};vvvݻWsЦM'N`7ZU rwƋ g+k +-tz/)>gϞx{{cib0Xح@R `K̕+WX`gЫW/.]ԩSḮ@mX)FЩ8?tȑ/4i+B퀆gP8nFTG9%H%o䶩, ʻQ\\|;r ɉj^}J 2×_~ɱcd=駟^:zJ "ݻqpp`rpodDO< -i^ (hW=-ryÃ7nж6LgwLBrraӫW/a>ӯS-wf޼y} NNNEO7. dx ~[iWKYj>sK||<#[ɿstڵk̝;WvsРA|||Xv-x ڬ65!h2|Pgl2ڷoOHH">q7"2 -HFll,d,;^K{3cQe֭[YMT̘1݉N~?›!9Sof =!`po^t www/^LVV`)h ,Pj;ԼtBի;QAAA~V[t,<׀E=%aҤI28hт/^΁w!Sa+dffӥK""""\慆f _cm6kk/"CV)'9kY l1PCᎯ&YYnݺEF<<^ Vt;thf̘!; M6\nlo)F Q`` ڵeժU-̌vs233 rLw^X@ QqEe[=BzK%=DFFҮ,6a3i$jйsgBCC>}:9*>տ7` ddd0|:t`;:v숙YS@tgxVi ( \Q-" ɼL8I>kԴ֭['X[[kvV ma d8hVBBBpssc7ʊΝ;<R`R*jVWGPr`\\\شifG=PlSVs}"##`zŋL6lCd~-\uuN9m۶ԩS3 *zj`9@V'#s4@8 ԗ+B tj݉㝴׆[ w@JJ ƍ{_+~z>LF8uU|'e-M^pj Y "dO,=r|PܛrA ,\aTΝ;xzz2g2Y LԢ*k >S ٓ+W0o<2rxh[=7`e0Vj*7o^+ lْf U-ǗE24iY!,aAAwK=iB48K;=JmkQϤ*A[ W ,YBppRB ,YCѸqc.܇ΛTk_WӾ)0|pL£G <kc}e?j~Ξ tVXK;('J$af70`<ssݴuLƎKZZRӓ0f̘Aj<=~Pf8&j6n܈={QF=5픇6.|X{6^qgϞm۶[S#5{o +,~+WGA+EYv-~~~4i҄㷄K`1Ѓ,&F0ff=\UvhҤIщrp9ZvL]=M? )<[ X廂* IDAT' T 听,>3:uDdd$kԇ]J/Oian [ʕ+YrR{1k,1c~oQ q#f*~GZnΝ;T*FYruлT`X@Q+@W[a #Ւ@\v.]`x Mv:Z$+juѤ(Rʊ:~'j & # Pӻ)<|^{Aq֭r1FSNȨ  ^ ,M,\i ;p#A(fڶu&00zg4 Lt@m.\7|S'|ؔ'EzRay+[طo,_\﷓6nܘ^zbr 8٘J|!17WR_2%_.ѣ)nP^e ܄zq1fΜ)S 駟ry\]]Ƀfd=HɯBS[\(sӧzlM{?P^jgKCRÔo|F7lbiQAZתʕ899rqVA~[Bm&Q "ٳgqsseڴiӧ/PAfe@uKQ\h^ҥ o z9&nB6r,܊QuZ _+ NP I׮]={6))wV(SZd`^HT3i$S2ؘ{ ޽;7Vx7'Iz6{*ӪU+o߮wabb¸q㊞\jU0 #5͟*!||T"&ռֆ )l+8y$+>Q]^?}LMMYv-7n\ЬY3RJl V߆>l0E=D& &&QFѻwo"""j,LR4s>2`ڳ (|_| o+%r2zRQh?JB?СC̙CZZ;US#7VZ>|3f1T*SN%4={$>&?Oq!p|4X>##))I/I&D&z0J {dß\v/KkYt5)}3gnn?fUhvjEP+p'<<<[nrPuFqa6oL9N^*o @[’e˰c۶mպoϊ.z!#Ms 9y C)+6"g::`itKg8p+Tl>"/5v'ȟ`dx+$akqgg g5԰D+zp]ƌCnݸpNiU 0 Pl8vK8\7a*è6)%ђD7>FDEE^M=uw_-~?]~gKLLLիWח͛st ׺"A" 'pqq᭷">>^g駟C+@` (@X+-ו˦5fO''' 6Ъ۷oHzrPNC+|NNN;wCʁs }ǘ&~ԏ; b*u6| -[d:DŅ^( o3ջ4Z0}߇R[@ ͪks(9s:0uTbW)Pt<^3- @J&L8ӧOs.c,,,Gpp0;wv" !vwDI`e X|+>7ٙ\{,xY:(aj R{• ` bW@R_SN;wDӽ#^Eo $qF;ibooω'X~=UTR$o?~yU|2o߾\tIg٩SYVSz[Õ?@U`}m =*,\vaDk@S旖@-YYYZ-[i&L,}Iiװ'\6{дiSN>ͤIsT*ӦM#""' OH[+@ ン3ӧO:e˖all\T+@fI7T!5?K@xl&PtS}ii(;i۶-f"1rn'03f?`nOCr95j# gggn&0d2`f6vcy,Y2md| pN.vi]@q7@F{LK,hׯ3bzɥKpGaP~\yQPjٳʕ+6PWWr`I""0i޼9^^^df]ԬY)K`veU`1XEkUk[%Bٴ C5V *[<.x/̚5 {OXYOq jQŕٳgVLbosUƎKJBuUaHQУ!DGG3}tZj֭[uZre.]ZhC KM`E)  \|Cs5`]̷(4?~X>&--˗ӬY3VZENV&][b;dcMfݷ@z6̘1 K QV-~;F6m<ؽpO9 80 \7;v,ݻWǏON RJ0(I/`1髝ʁ5۞oJ[@Pė^ijYUV̝;~@-+z-B$_Xv,&%yyŊTXZHףi!v 6:믿j"Ro6VHWU$E=D6 D Ų?Y{!>M51-&Ɉ*K%H/ѣ¥^zcȂY>gM^z@Kyebٳ СCy~?ס~h\Ξ=ː!Cppp~JL3s<v0T ץ!Q{4/owYEe/خ:,O ߿WWWMD|C!ւ&CFu-1"oU b |||WhIeϞ=x ^u`#\^I4ZhuHOOW -ͭe5mEirm6#cW$KoB?d 0l8r:ub?:ְ7g+H"K`` gϖ%/LϞ= aڵTV#7-K՟03؈e(C|M|M7nW_}X 7oҲg1X`b^Uiߞ)j `Zc: nR+(\+gMZh+"J%$ gqj[zCKM G"oc⭷bԯ__022͍ɓ'¹acXA:#TF\A:tooohѢ*U*ϭ^::tCsWkk4 dd&D.Ti%RYZF ~[Z'((}ѣGi_o "["{߾}YF(FժUYf Kĥ K@[oj())"GCwѢE4nܘÇsȑR90{lw^rD@m0|l>_HyRRXatkH/4?]"ϫ%x nաǏO@V×_~ɑ#Gaw+S{a/2EH$/0gnܸ/~Ԏbx7?~<666/۷B߿W J{7WlK\(9lWɈ\"~/! h'c2rپZs@u\|Y>yed|\(;X݅R_zQuO*Uzjƌ#]Rfddd7߰h"06N"IkS`CWN第Ø1cȨFcǎѫW /RDF*v*exOx?݊J ZV5,d:( *+MU+:O!11oooVZŝ;wY0~O1۰u֕/ Yx1k׮%==+3錄ֶQf 6l%so޼ &&@ݼhQm!TvTDbtLMM'hV^ \[}puu+'о}{>&!6 L`(F׸ ~_R?%î'ߛ7-6 B ~gϠVۛhVmj46Zi`ذaYF%zMff&^^^,^4Ϻ5|&~I4KccZhA۶m5?-[^z\~߿_-s mgaR7=|U}hdk.j; 0zqlYb %C#44;vm6MP J$ܠ\kzp-9 YP~}֮]/DR^HNNfڵ,_XT*f'@Z$ p\|O)dnnNƍ133˚NaNB3cƴVk]Y eFEOϑκE XKӲ,]sիWٱc;w#- 16<7o?"ڌ3Xx1+VD")$&&_b 1R nЬjl/,=>95T\cM1{6]O\_XϵVPm pp>RvxLWѣٺuk1عs';v 44?cJ"U{p+1i00| j5899!I$..e˖vZ11 N߮0 +B > 2X ̌_Zlk΋FH"?ESO݀6p㝲]ufyXpTE]3` &((8ٳg56kXˆIKC*󼨁C#LhiYO>Y{g q} HKK&9Fe)E$:\*UF{:S3"2O3i$^}U~:G9rU9_,}߷,[r6mI&!1xn߾͢Eظq#999 EIu37M] @^_5Ra0Qw$g¦PXqZ wޝW_}޽{;!EiNHH\p???nݺUwZQA`jToT'ҋ模N:,[ѣG˭}I^ʒ%KHZG]mm?֋0v0zzJ~|ڦ&[UV&R J7k֌^zѹsgvcqm"""ʕ+?222 ^Jнt Ǭ|?a155wO>)rIy#**˗wߑJ% }Y%éuz*`2miY 3 h'묛!Q ~7!![ZZ@fhذkkk*WJ499x'>>7orMy&?~-F*as#nZ(ʂw?8d͚5nZ>-$bÊ+X~$z7[aTOYs3A=L` NiFYI;-M18)gyH&rBb 2sJX5xݶ~yQ&0ߠA+F! ǚ5kXz5qq"!N*Z 7kv#הޣE-3!2V;n%m'3!9IAfP jZBuKSW[tU*{_L4,;%ܜw}?5D")IIIx{{fM|QuK+MW'ShhG z J|VYO6@(]E*DPa?D'#G/qƲ$b޽|ל>-j̘p;e,HHۅC!Sta8ah%wn3gbnn.;H"?~͛oU*lS;07T~ D(0xWW?#{E>`QĄSpBjԨ!;H"aN<Ɇ ؽ{7))bZuKA+ed$@2v(,&\s嗽=-ONê@x!" … qpp$9gϞeƍl߾]\z7A[:% |"/`TUOjsc88Z/2VGibYp!NNN$rǏ駟عs'&b+喆%~J[Dj.}km#RTJLXOCp2h .\HvdI$@ll,{aΝ=zľ 6 #gœp}0`_Bķ-xtSjP~{ W7Ҝ^auּ3FH$Z#%%/BHHDDDs066YfJNpqqyj???>cMEŧ݈؀)F/S X:ʛy.?~FG[ 2DH$zk׮ݻw!::G||'/7ATX+Rzuj֬Iڵ]6͛7ޞVZaaQd=3!`=&v F n ߽$(ZL;@r8WF &L)Sh\nŐH$￳`BBؿx#vݓUkdVb;.?4&߭[7MСC_"H^ҥK9{~5؛;UL@lՓ_g"Kzի3~xLB˖-eGI$I)Dze_+vg&Uk𹧈2sUQwތ=ÇվD"h֯f~B`//XsK >QCq.U쿞?T*:vȨQ9r$5jԐwD"l߾uqܹ]!wR`` 0 FĂ 8x]$H+W9rL#H$:FPP֭cΝۯs|()i Bk6HQMQp膘o(0Rpwwg >F;L"Ht8nݻ9u?e|b+'xFC](X';5/1&rGDKf;vLD"))):uJ5/((Ep}(ģ P1ߧZjg$F`` Dzzzq";wU4w?$5K ?aԨQg$DILLرc~hhhqӼgNy>S@>@8xD+… 5gAOc&"]Ϧ*'ըQYG"HttN8"~Bּ3GR<#P3Ĺspqq=#H$:DFFǏ?u))Ųȫ~ :Q /Mrr,y~("`g %K.8qBD"hs5CHHƤ?.E >ʯNmn^_CllldH$ܸqPܻw--(!{5wb @9°adH$I)r-=G寿*[ +0_*G_H$ݻ߿$u|I" )OH, 5fmͫ#lKvF_n&ZZZ,)#uuu~YY'Ofܑ?NQ[߉ye8m6V\id$}GRPP0@1$1e<nl޼@%NoL0 .f͚EKK 7p&ǏS\\w(`p/W81OcŦMxꩧ4I9sD"1r+ q%`mtl24ASQQo۹sgv;$ q'(SLСCiꢪ*ޖWSSCOOO&'W&G鷄?^02(/I$PRR,ng11!ބ/YYSCX~==Ѥpq~ ,P#r% q߀_G/)S &VuH2Mu#k,_hkkkh8 kH/}FV(6OExuY FjD _$<iӦq!͛gd4?x ?Cҏٍ#r1YkPM6vZ#1;wGVTTd3@K I0iލ.fϞMCC^{UOmmm<@ 2pK2$<֭c͚5FFWb9{l9̥t[oedƑN*++:;v젷7GJ~)pJHk]/E |sDnuu5/fܑgp 8id%IYIq@O~6n<- ewGaMd@WÄ:u*,Y H$hllDt! IU+ƪ> 9ؼysO k&hp7gO(I7 MhK. 'l?vp~ _4, g6M'灻iyH& o1.~kkp~PNs$M&Ms \^z) f̘i#< _?$Mf7~''4x嗃{79sf xVSKtC$]%D}=Ν;_=XbE0{lQ`(!D$i o&a  E,Iư%܉t$IwrC ;Wp$I‹H@>_Ipw|F^jO$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I4&tv VIENDB`jscribble-1.7.7/artwork/jscribble.svg000066400000000000000000000161211174451527200176470ustar00rootroot00000000000000 image/svg+xml jscribble-1.7.7/artwork/jscribble.xpm000066400000000000000000000135761174451527200176670ustar00rootroot00000000000000/* XPM */ static char * jscribble_logo_xpm[] = { "32 32 236 2", " c None", ". c #616161", "+ c #808080", "@ c #777777", "# c #848484", "$ c #959595", "% c #A2A2A2", "& c #C1C1C1", "* c #F1F1F1", "= c #FFFFFF", "- c #F6F6F6", "; c #7D7D7D", "> c #595959", ", c #757575", "' c #9A9A9A", ") c #CFCFCF", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #EDEDED", "^ c #FBFBFB", "/ c #FEFEFE", "( c #858585", "_ c #7C7C7C", ": c #B8B8B8", "< c #BCBCBC", "[ c #AAAAAA", "} c #D8CEC4", "| c #E6CEB7", "1 c #F2DDC9", "2 c #F4E4D4", "3 c #F2EDE8", "4 c #FDFFFF", "5 c #FBF8F6", "6 c #5D4023", "7 c #B25800", "8 c #F17903", "9 c #F67600", "0 c #CB6E13", "a c #DF6900", "b c #F9830F", "c c #DA9046", "d c #D9CABC", "e c #F5FAFF", "f c #CEA072", "g c #F08721", "h c #F37902", "i c #FA7B00", "j c #FC7C00", "k c #F67900", "l c #B25700", "m c #FB7C00", "n c #CF6200", "o c #8D8E8F", "p c #ECF1F7", "q c #CCAC8D", "r c #F08419", "s c #FB7400", "t c #D3873D", "u c #EDDBC9", "v c #FAFBFC", "w c #FAFCFD", "x c #E5CEB7", "y c #DC7713", "z c #FF7C00", "A c #F57D08", "B c #DB7C1F", "C c #B75A00", "D c #D76900", "E c #DE6E00", "F c #F7F7F7", "G c #F5F2F0", "H c #DABA99", "I c #DD740E", "J c #FA7A00", "K c #E29345", "L c #EEEDED", "M c #F7F5F4", "N c #DB9550", "O c #F77A00", "P c #D0863E", "Q c #F1E3D5", "R c #CBCCCE", "S c #C05F00", "T c #FF7F00", "U c #F37800", "V c #EE7500", "W c #EBEBEB", "X c #F7FAFD", "Y c #D4A06D", "Z c #F87D05", "` c #E67404", " . c #DCBA99", ".. c #F9F8F7", "+. c #E5CD97", "@. c #FF9513", "#. c #F67B04", "$. c #D0A77F", "%. c #A8A8A8", "&. c #FA7C00", "*. c #CC6500", "=. c #F67A00", "-. c #C56100", ";. c #EAEAEA", ">. c #FEFFFF", ",. c #EBDDCF", "'. c #DA7E25", "). c #FF7B00", "!. c #E5892E", "~. c #D9CEC4", "{. c #FFFDFF", "]. c #6D5F20", "^. c #EDC459", "/. c #E1C7B2", "(. c #868686", "_. c #D26800", ":. c #CF6700", "<. c #BB5C00", "[. c #F7FDFF", "}. c #CF9964", "|. c #F77C03", "1. c #FA7800", "2. c #D8AB7F", "3. c #F7F5F3", "4. c #F0EFED", "5. c #F2EDEC", "6. c #717171", "7. c #D06600", "8. c #D06700", "9. c #C46000", "0. c #F9F9F9", "a. c #E5D4C4", "b. c #D57719", "c. c #FF7A00", "d. c #E98727", "e. c #E2D9CF", "f. c #CB6400", "g. c #878787", "h. c #F4F2F0", "i. c #F6F8FA", "j. c #D69556", "k. c #EF7200", "l. c #D6AE87", "m. c #F9F8F8", "n. c #CE6500", "o. c #D46800", "p. c #D86A00", "q. c #9D9D9D", "r. c #FFFEFE", "s. c #DBC4AE", "t. c #DE7E20", "u. c #EBE9E8", "v. c #FBFDFF", "w. c #EAD8C6", "x. c #DC7A19", "y. c #E08730", "z. c #DBD1C9", "A. c #686868", "B. c #D76A00", "C. c #CC6400", "D. c #D16700", "E. c #A2A1A1", "F. c #F3EFEB", "G. c #D2A071", "H. c #F97400", "I. c #FB8007", "J. c #D3B598", "K. c #F4F9FE", "L. c #D1985F", "M. c #F77C04", "N. c #D39D68", "O. c #F5EEE8", "P. c #B1B1B1", "Q. c #BA5C00", "R. c #A2A7AC", "S. c #F7FBFF", "T. c #CCAA89", "U. c #F18216", "V. c #EEE0D3", "W. c #EBDCCC", "X. c #D07F2F", "Y. c #FE7700", "Z. c #F07F11", "`. c #D1A173", " + c #D9DEE5", ".+ c #DB6C00", "++ c #F97B00", "@+ c #B17539", "#+ c #F1DBC6", "$+ c #DCBA98", "%+ c #D49D68", "&+ c #DC7209", "*+ c #FF7900", "=+ c #F07E0F", "-+ c #CFA173", ";+ c #F8FEFF", ">+ c #D4BAA0", ",+ c #EC8826", "'+ c #F87B02", ")+ c #EF7000", "!+ c #C87321", "~+ c #D66800", "{+ c #FC7B00", "]+ c #D66900", "^+ c #DD6D00", "/+ c #FF8000", "(+ c #DC730D", "_+ c #D9AE84", ":+ c #F5EDE4", "<+ c #F7F6F6", "[+ c #F5E8DC", "}+ c #D6AA80", "|+ c #D79555", "1+ c #D79049", "2+ c #997858", "3+ c #9B5714", "4+ c #D39A65", "5+ c #D9B38E", "6+ c #D2BFAD", "7+ c #EEF2F6", "8+ c #F2F2F3", "9+ c #ABABAB", "0+ c #E8EAEC", "a+ c #C7C7C7", "b+ c #9B9B9B", "c+ c #818181", "d+ c #CDCDCD", "e+ c #E9E9E9", "f+ c #4F4F4F", "g+ c #C8C8C8", "h+ c #7F7F7F", "i+ c #B2B2B2", "j+ c #CECECE", "k+ c #C9C9C9", "l+ c #7E7E7E", "m+ c #6D6D6D", " ", " ", " ", " . + ", " @ # $ % & * = = = - ; ", " > , ' ) ! ~ { ] ^ = = = = = / = = = - ( ", " _ : ! = = = = = = = = = = = = = = = = = = = / * ", " < = = = / = = = = = = = = = = = = = = = = = = [ ", " } | 1 2 3 4 = / = = = = = = = = = = = / = = 5 6 ", " 7 8 9 0 a b c d = = = = = = = = = = = / = e f g h i j k l ", " m n o = p q r s t u v = / = = = = = = w x y z A B C D i k ", " E k F = = G H I J K L = / = = = / M N O z P Q R S T ", " U V W = = / = X Y Z ` ...= / / = +.@.#.$.= = %. &.*.", " =.-. ;.= = = / = >.,.'.).!.~.= = {.].^./.>./ = (. _.:.", " O <. ] = = = = = = = [.}.|.1.2.3.4.5.= = / = = 6. 7.8.", " k 9. 0.= = = = = = / = >.a.b.c.d.e.= / = = = = :._.", " k f. g.= = = = = = / = h.= = i.j.|.k.l.m.= / = = n.o.", " k p. q.= = = = = r.= s.t.u.= = v.w.x.z y.z.= / = A. B.C.", " D.=. E.= = / = = F.G.H.I.J.= = = = K.L.M.1.N.O.= P. T Q.", " T R.= = = S.T.U.).'.V.= / = = / = >.W.X.Y.Z.`. + .+++ ", " B.i @+#+$+%+&+*+=+-+;+= = = = = = = / = >.>+,+'+)+!+~+{+]+ ", " ^+/+1.*+c.(+_+:+>.= / = = = = = = = = = = <+[+}+|+1+2+ ", " 3+4+5+6+;+= / = = = = = = = = = = = = = = = = = 7+8+9+ ", " 0+= = = / = = = = = = = = = = = / = = = a+b+c+ ", " d+= / = = = = = = = = = = = / W e+d+; ", " f+= / = = = = = / = = = g+' h+ ", " i+= = = = / W e+j+_ ", " ^ = k+' l+ ", " m+ ", " ", " ", " "}; jscribble-1.7.7/artwork/jscribble_gray.png000066400000000000000000001207041174451527200206610ustar00rootroot00000000000000PNG  IHDRxsRGBbKGD pHYs B(xtIME `( IDATxwXW/A" 6l`%$u5l4jV51Mo6Q7h4h,D#`; 6@üoD4fuqgy朙yι!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!FRBи/w !~15N!B\kWs/r!Bh)Z<; i!B<\~BsssiܸqW&M 33!DJKKs\vM U9'^kժ%"кXzd_H@9Y4m{-[EށBt!^y]RCY:'믿f̙勷E]dB耤$:t۷Ջ/($xS2'zuN!Б#Gӧ?#vgPhN i,--_~},,,UBfϞ6Jf`ɓi"off]jԨ!-'ZVPP@׮]T/|! j="__O\f.nnnJ!tRCjk;::>vW<'KB?mܸcǖ/ |-_EWW'J !1b?zQ$c ι9!nݺ7r+@?QL޽Yd R[B!رaÆ/,}&@2$&&j*R;?8lF̧lܸ w.BQYYYQ~BTqRC3P^` Tprrb 8PjQ!!CsNtȔяu@1Usrrضm!CZbUQMbn#ӧپ};~~~8;;K !D5@II G}$.~nI xoaaW_}ԩSVϧUV\rE( 3t@])Rh@II '&&~Ɇ=BQ͘ҤI~FiԐ~*ڇƪ.\֭[ܹ3RBQ4mڔh.\^ %R TG_ꁬ,֯_Oii)KM !D5ѩS'-[FII R;_]UP(8v111 0 m!HII!22R ( FLBvI&RBQ ҴiSԋJ@Y'u֭EhBj]! -yyy?~\ʹRC~(o t پ};գ}RBaڵkʕ+WYy1 rM@r@_~!??޽{cdd$- JmB+;(x$qЈ#X~= Bahܸ17oT/,1u@0([ Ǒ#Gx7BdffFIIIQCY`#*@BOOO8Bl6lHf#NHTmf9N^pN:qBCdkkA#*6V PN:۷:H!ȠQF K}6޾}}rIi!00uegJT=B;;;8@Nu€$%%ѴiSՋR;gRϭ?l肂~'z) !'22/hN«P -EvBɓ'/z>]JBlmm9r>>>RBa \tI=yD5PY^믿NbbBBȈouE5P'0OiӦ?~zI !KOO͍G\Q}FT_\|W_},i1!scРA'JHX^ūZ>B=TdA' `2zaXXƍCPH !ѣE+4DMMUqqqҳgOi=!SFFFs֨Q?dy=+S|H|׏`BB{ѣQ{{{KKK+XPTTDAAܿ>O|#ၷ7ャ Nv8{zX`P& r.z'(uppN:e_bccC͚512z%OPw7o$==4߿إ@0pSU`֭1Pv޽{qwww[nٗ&z%%%dffɽ{udddQ~;L4h@Ν [nj ccc9;! ^-{-066777\\\pqqF_VAA$&&rUGKwNPͨrRܜ?o -[y渻P(sׯ_'%%G~}r@ap~GFQc4nܸvΜ򈍍%::/RTTz(X JPagg[QF:Kn߾MBBW\!!!۷o?򸕕;w_~ 2MʙCΞ=˦M鸙иqc6mJ&Mhذ^ˉ'HHHPπd *_@gPScǎxzzEizjWZZ# 7o믿krVB謤$6o?@||#///R3߼ycǎq)JKKA9ypʽn$x1V`OPw??'4$$$$pyɧjW^_W^^6B*wm?@hhhY'ΎvC V8pӧO^w!;/5rƆӹsjMMM%668RRR>Xt֍0|p4h g!!g֮]oVvoҒ֭[Ӿ}{6mjdddo>$ F ,jӣGz$;;,K666ߟ#G2|pj׮-%Ј7nzjV\IjjjYE];ml߾wr  r9+ 8[[[=C}EΞ=KLL rD9r$Z*KR Gaٲe޽憟[hUQQv㩂t5x 80|pZn- Ν;GDDϟ/[jmm5jB璙ƍYlYY.333|||["&&-[R'-] 9֭[3bV<Ξ=KDDW^-3PV-|M&NT≒Y`W.]Rn]vJN޽INN@Xu j7ؘ^{^z;DC$22]2qDYQ&..e022ۛ5k&JJJغu+O开7Q6@-y0n87n, -q9s|@p̘1L8///$!P͛Gpp0 |}}իNNNRAd9rɃVU-STTDqqBY&XYYacc=S^=ի[>KDEEqѲ13f#`!tLrr2}[lKKKwN=6)((믿&-- K6 wɉd%%%$&&rE.\7ʲUSSSqqqՕ mW^ѣƖ%޽;s̡_~Iݿ/o<,,,w2OeddpBdcD5TBʕ+DDDJ(S[hooopuu,,,Ҳ,r.**Ν;ܾ}۷os RRR~zVIIIeIcccׯOfh޼9zܾ}cǎq̙zСsaf/!tSf۷gOOİvZP& )0;toZ\\ɓ'9|0wQVmڴw׏J{ϟٳ9sbbbvS7UVx{{<BCC9rx{{2bLLLS-8pX4i Apuu3?ji+P/ԩCPPPO0)))*s>>>M62ԫW$IbS\\̱cػw/6m*055ۛN:HJJ* .xFgϞeԩe6lח1@U`KəXѣٺu+EEECѪ 4i҄mEA>}:ڵ#77˗/sM"""8y$uѻIW^o ޽;Ŋ\r:ʝWPK8h viP;wb .]ʍ7F]v_ ϟ?ϯʵk_>saҤIG@T+ s]jԨkF׮]]rR_NRRR[qqqExzz5kT>҅#naaakuVwii)W&>> __U@ 믉Tgt=@\\xyy_oȕAW2i$RbjՊaÆUMݻ牍˪9]v7{ cu pE-q,,,hӦ ۷iӦ:d`,4ޯ_?! \\_;2OgfܹA oaݔe>ׯ...:}۷t;w.r 駟-C ћ /{>vqqqŕ`F 7%/5o/tR]߿?:,_ .p ZqF~Vץ8pMf4QrJJ gcdd7BnhP܁(H~С΍= yʾ} vڕ6mh.^֭[Jg deӸqc?)--%::TBCCINNv:Q*-r@@\~8V\Ibb">>>jhT">sƌqvvfرt`WŮ]عs'/_&77 ФIn޼[Z8L X:477޹sr 6ԙejŋdffZ>U@=`ѣbٲet {_/P[(퉋UƆ;`bbBLL @:uY!tPq˹wdFB%**m6 }a̘1ԩS _oFFlٲHܹ#F`,Z|xz T(_޽k5nnn:Q5kTnr u*>>mݺ5o^+8<(#HKKƦZܹ7|÷~[6ŀtz@ff&+N;;;1cd:ϙ;w.EEE8991j(T9Bll, ###7nÇduڵk?~/CaBykm׿ʗ'+ >3233y*kX>\kIg9z((_DN.(7o^-&Tʊ^z{{{"""HNN&44۷oS~}Y[ZZM۶m&%%Ç~zjժE6mr)._L``&={dر:9sαe8@FFL4͛7N.\`ǎG2PN:쟖fO֭t[###UPfZ VN ի)..rӡer 0f̘j}b߿l}dd$׮]ĉܿWW*ֹ"5k֤]vxzzFJJ w&88f͚.WV\ɐ!Cvue„ tɠv+))!,,'NIzؼy3C}jʕ+l۶푘}_G;;woo*YNBBBP(̀(3>=p _~Zy6m̙3^ʕ+),,ܜzڣݻ 8ӬY3iTQ%2220at҅cnnn0ӧO믿^ڬY3f͚Ř1cy|嗓B9[W1cFެ^Z,`6FFFFfoV\vY5: @Q(h9[y뭷{.$$$1nnn:sqvv cŊܹs;VByWƆcҳgOZz9y$tЁ˗h"ڷo\ȯ_Ά ԋv8uEZPP… Vي KKK""" +]7 驵,6lPMvKr9RX+3tв%x/^$""{{{5Qܹ3$''իWR eʔ)>>=(D5@rr2+,,/gbggDze e˖Z= nYU( Ν;Z}bOOOշOL@- {kPo1@xMbbbKhӦ ǎcӦM8;;s%ϟOppppp`ܸqL:gggΝ;G^&;꧰)S0frss֭z233Yl۶m#77!CɓdD#?zVWե߿* & y&w@ VL*o&/^d֬Ys!Ν4iBPP‚M6ѢE ,YRQOETzw}GfȐ!z?i͛ŋqttdرJ=FDDhhЦ2.Vz7e"-]# W_MnݸwWfڵ:ؘݻ3gڵkGff&;vԩSҨѣFZ1czrrrXf 7o&//r9Cn ֓˩3UTnb=r?qℜ4E=z5kPvmbbbf+ 2)gϞӆȈ~3f̘u .T%I͚5c 0SSSVX'ׯE<"L{GII {f: )))aΝYCLL ƍө` WO<UTT[ʍ5R}ۥրShlھEEE\|Y΄ZȆ 8x ͚5#%%Yg0|7noݺuܹsҨzLP0`;,,,?~<^gLOOg…;v sss~7ds}3 (GKKKkhX@gPf{4`w4V#Ջh> / &&FgVZL0 &fBۉ@D ޞӧP,X@jj*-Z <<ӧl@Sҹ;z\g߿ubEƣŬ,U_U{`BҒO?hzAVVk׮eڵdggq{{{3gB`…xyy,g/WYt)z:rssYv-?#L43g|b 6ZM/^@+@.](ڛ/j޼9f͚5888×_~I0`AAAoaøq4Fߟ=zU镤$ϟOLL kfΝ,_\/0`((ǁFCUP\/\ g*$ǐ!Cc۶m,]۷oq;991m4N5رc-[dҥZ(^̺u(,,w SSSʱN8~Kff&DGG3h 9 V4`QQgϞn^&htpp@IwU\Dm%K$ًpvvfǎرggg._̼y8|^P?udee1uTtzNCuVZZʕ+;vlY}?EEEl޼~RfΜÇnbi3 Z`ffFݺúf/4*##C53|O\I瓐 gF1d\ٳ)--eϞ=ڵk:{̶L:uNv4iNiOBB]tiӦMZ_X`fffzׯ_/_jo`ҥKZ 6be _zU*nr劜usxxxpM/^޽{+FTg4i҄3gB`ʕk׎HիW0k֬ J&ϢEȠuքmǽ{ԋrPnﲀR[gRU,G2-ԻwoΝ;WvYxNociiСC>}:$$$+0n8 b/ԬY^z=wS:ĪU㭷"<< }R6Հfj^&erMJJJR}{+ۣ_}aaaxyyW_}šCt:#_F "003336l؀7Fqq1ӦM{\'333X\\ƍ ؘSF n Cږ5L-~1@:u4v(Jd[`סCΜ9?O eCؘ~ҢE RRR0`G]qqqѣѣG%dѢEDFFbooOpp0AAAjAC $gggW4ѱծ]sssw@=ssslmm5vɪ[ʭy%ҒyBfHJJ⫯ѣ:=PV-&Měo6mˋ~IUK޽3g;mذaL LHH`Ixx8\"{>"}PaJgooâ>}+pQ8{y'/OΖ_ŋL8|nʢEt~'}{ٳgӮ];N:%bcc9rNNNUիK/O8gʔ)ݻW0](_d/ 9=FFFQx9vեٞ2`lmmYb?$&&`N>mjj믿Δ)Sptt$66>S aڵk?i]sss^yPxoߎB>cɒ%T6F#7\x6@Ү;TÆ ܹs <<6oիu~gƍ={6={> ___ xyyylذ#FT߷gϞ<)-[~LMMYn]T7{\mDy{Jw-շuq$Fի?̝;H 8p ӧOɉXvJPPܶz~w֭[5Y'rJN< IDAT-cرծM/ yr`Q VtP [oEll,qF6lؠ߰aCׯ_}[رcҨPeKKK>ӓ/ғD٤<;.\@z O>ղM U^.k-4$k\\\ػw/˖-ښ(͛LLL d̙ez{'XDGGFݺuұ石hѢJ={V8)0''K!!!iӦڶٳ%=k/ ^4pbc;Cͺ%lDFFұcG233Ylvewg̙bll̒%Kh׮aaaҨҿ6Yh%%%|332UׯӼys5kV%**"ZPPOFf@^ױydC. Wf8q~)&&&=z TgNQm5p ({nO @s>l6 >N8Af͸y& .ȑ#:j4ߧO>( K:t@tttl~lZjEQQQ?(FC(RxULJ`G &N/•+W8pǕxxxиqcvzbر,]TZO?@^^u- *ϗ/tȪFCP <...~'77WwR @WHjVc  f͚lڴ`j֬YhwQk733c„ 4===~\]]5pqq1!!! >~7noF``XDj8 @ɕZZʄm{@32dƪUؿ2{ls̚5twhiiq1~WƎ+|5.j8 *P*%f",IѣEKKwUXy)U'No߾hiixb<==t钘XQ ;r$(e@mmm>3hѢqqq,X@#2:0k,ׯOLL ZbΜ9]O xYYYܸqCTp: 5- ٳg4iܹQ%)Ao%SN[npByX+qʕ׀j8ـ-R2?vvviH+WdXYY÷~Kll_ݺucҤIԮ]\]]Yr%r\L(WX|Ft5l|U =gjsssQD 9]v%::=zIPP;v(CRK1c>>>0ezҎ{իW˟$9*Pj4͔œ*P u?䫯BGG'Nj*g1CCC8@֭ +x!׮]{HR z@MFЬY3 T6s%**  pwwgܹ899H.]9r@P \UB@ɼF(,ɉSN1j( عs'?Lm111aر~W4 @5dee|*@jwR{oWŀd=Ju,⋎_Ԕ~͛7cnnNTT-=)`ڴiX[[sUo4"A -n*FZ« IYJ_ B]*~T'ԊAq5zAzz:VҘAfΜIn(**bܹx{{+F(7fzFu-TY@ %.VqOF*t,--ٻw/+V@OO'Nd/.x9Zl… 5 @%N5(-UGIRdL<ƒXl1}t|||eΜ9t֍D1Ռrx!OP~D@qrr"""Lkגn``=z4Ƅ̦MV#޽)!T&_KHaPZ]<]HW\Y x5-[۷5]\\1c<~#F0aVO'@5( uJ,#Zn-TZ3p@.^HIOOg͚5hoܜ'ҧOXnZܹsbb8/*AV5Ch8@ԯ_Gn: 8t-zKVP Κ5zq 3gQRf?ӓcǎp˟zT͇D%@Ϋ~R&@^^g꩙`8UIh<#,,4@044Tc|}}3g5޽{0~xj(ϝ@z \I (<"S PH\]]5.@ܜO>޽{EPPDEEɭ . y7qBem۶OѼys/fϞMQQQiRtؑɓ'ciiIll,^^^̟?_MG PY52??? $,X-[PV n҈oРӦMà z2].,iii)DPwj@__OOO 4 66^zc֬Y͛%k]"f?5jBӦME? 1e|HLkz(J 8VZI>:`iiɟɺu044$<ԈfΜ9888p}vȑ#y\at=Ve R #R;=*prrO@sI퉋cɒ%k+ ~W\\\8uꔘ\ch\ȗQ53@@z,R*&A d|||pÇ'77͛7qF׾}{O wܡC̙3G#* VjԨܩj< d]-D_,fflٲsssY`qL6;RTT… i۶-7nLMM;UԛBEO6P@  3p@h׮c(C޽裏Y&gϞ͍+W .2@֖0,X.'N`.ؤIfϞ999L2ݻ1+R@ p9pqO@hkk3{l>mi?M 444,m$ρȑ#br%N:OYUw u r bE(`8000A<[ŋ:t(yyyl޼ 6ˌ3hР t҅ӧK U;%@L]dWxW@333RR_U4G㋊S7x7mĦM033ҥK,\Pck׮͔)Sڵ+˖-ӓ1G-$R^Wxq^L& J! \@eС\x??۷kD?---wΤIҥKxzztR%A5kxa\Dd#HRGf͚pQ͛Rűi&1ϰѣ|pI/^̽{49s&1c Dw ~2{`[MKR_ 0s|6l(H[J㏹{ghkk駟riINNf8p@#v 2quuebr{{NUӡbF;RY*-v啾@ܽ{????rnݚ .0ydr9`$%%i;991{l$00^zi/tUkd ^Jr6ڊ'RF={6mpu4hGe^!+Vȑ#r=.]ʱcǐjƌ5#F`ddľ}pvvf˖-br_s`hdd$yzH!j*-<<=FqT_h߾=8::2qD L&O?իb^@?]vfI/RٳqttѣG 됚Jǎ BOO#Gҭ[2ӧOz*:w˗7nٳkVxʱT1sL4iR:h a {@ f5>yD!7 @&Qvm55Q4Or >>>|???n߾Mzmru1L9N5}SZ___,Tŏ7F\RRR*ʙ%PR j*{.7f̙/*]@bb"'NO?ZhAjj*VbϞ=2`>#j֬IDDZbʕվZZR>.IHII]XXXd2r4f ϕ"233 IDATg899UxyyBZZcƌшEKiӦ L0bˊ+MjMf͘3gmڴ!??sU-3|||S> XW[w^J\Q7ϿךВ dee1zh>Caɒ Aajj$!&&&ܽ{ŋsQV 8O>ڵk'sέVuiӦ)УXJiZ)!-"p駟gذa O _SMrruBlll K1)cVzV|HP?gϞмysf͚lm45j?1BZu% &NHAA;v`Ւd0I SLO>~zسgOC?.ij7---;*cow#@8BކHZlz"00 T$zښW駟I ի ޞ۷oxb8U`֬YۓH>}6lXclZjUڦЧ ~-נQڤ_Ha+V`Ŋb+bbb2e `ɒ%ܻwO#v?aӼys6o\eH&1hРWcr]PڤGT ШQ#ͅgݒ@ܼym2o&=%xMгB\E qqq~ZZZ(+:D*Jqq1Ve˖DDD`ffƄ ߿oJVVk׮رcb >c1ͅ ȑ#,ZHc: 3a 1{ɉŋk|:iÆ qUg(+ȮhpFے777ŏI) jp-:tIÃ9s$&&tRnܸAݺu9~8'O/8<[&%%;vкuk>Bfݝp㟳$*. kڴG/3W Ⱦ$*nWJ&VPv+VՕ'N`ffF`` ÇWkqwyV\IZZ>>>DFF)&TŴhтp,Y!'N`SؘaÆGQvmbbbh۶-}ѧOE&3`Ppuu,ZR<\. E-ܸqv1uTdΜ94Hk.~W3f G#f\x ӧqV]tA&vZ5kFpp͇#G,zlutt%ܺ|L p܄ʗ@)**bҥqij֬ɸq:tZ^ף/&U ppp ,,uQF """o믿4fѣ3gΤaÆ$%%1tPt";Z*˛3tuu9q~-W\7~)ڵC.f6mڵkղ;;?Ff,_}e]A]TTdckkeߐܿ_ϽR]#Fo@!D/ϺuŅqѤI,,,d֭PTTć~Ȏ;S*ߟ/rM.\@\\ 4XҬY3\\\HNN&!!}cqppPmԨ?cSio h}]$[*,ӁR[vL)o3~$''3zh|}}9wL0ѣGcffןʕ+ ?JU'''N<ڵk177ڵk,Z)kmm'|رcʕ+tޝnݺqeN__YRå}ry{HLLTtQ<&ӡCIvj$''KI.7SFÆ S;[(,,dժU 0 }}}zɰa$&IALL AAA|JS)ITx{ :t&px݀V={7#G駟r% ۷/>jҘ8u7n$##-ZpAw.&X^^^|$''׉ZcFFFlْ&MJ||<{VZ8;;\Pvmvޭ|%nlW6mJ^TGQt\ WH ]WW^ NK.xxx7|rǑ2f7n1嘳9vr'uVQG&&&׏Ν;Mdd$>Nc,]xyyakkKJJ qqqܹ۷cmmJ_WWWBCCw h뀔tkkkUCQ\\Lpp@1ЩX]uzz*K`kϾ0oߞ6mڈ7r߿ij3GSQQ#~:k׮޽{XXXԩSEaK%00sssùsgΜAKK [[[u]6X[[ĝ;wؼy3!!!XZZ,MWP. P{WP^w8;;C/_hZuUo`rjjdA#2 """(**jEIţW-EB[REu]wȑ#Kkׯ_#GҩS'LLL4^ ٽ{7۷o'77Ν;sZn-&ZJhiiСC{./_ƍ\psssaeeE6m 11۷ouVLMMqrr\XYYӧObk8<2Jr}[r… y5j(WF]=z_~Lؿ?h-xk7nu!""y)vvvn燥%)))U7lPrqէ?]Vhiiƌ#<Rv꿓Jgdd;;;K[rtt$**\[J*[<=0DqФI{=VzCN:|_~IBB5jԠG1 jSAzz:6l(7Oغu+-ӓcǒ牋#<<}}}2 ڴiCݺuy!:t 233iҤIp!Ӷ@:!h{jJeoFQQר#(~jkkKV@7ܹs"w 8RZ+2l0FzMΞ=˘1c;w.qqqҽ{ CIדB:uؼy3'O֘@044G 07npu^JLL kBcE&QN|}}#--s VZŋaÆ&n9qDSK! b;׵kWT:aaa\v J*|W͛_Htt47n(SR)Ex*C???N8!D\.,Y#G%NmV`ͥ]KPPƔrTvŌ3}6͚5O>X[[k$$$p JM|G|#>>RSl~R-,:vH޽U:̟?lgG-nOϞ=_ABCCٷoA Tǎc׮]'׾@;ษ)SY} J DkժH`gʕ+IHHJ ff&[n%&&^zn:QG6_zjקChK.qIE$[!4wfԨQ/ڈ\ط`s{ [lʾ+|ȹs8|󽋋 ÇgX+00ח?8o5-%c2[[[FYi͇"$$J~o7TlTeUȁԐ8JE?*Z53EEE8p GQQI6#Ucbff&۶mŋt֍~AD 4f̘S%^kkkCf4pQQQdffwtt{t֍vk| XAI.]t! Қ"=})qqЦn?j(JΝ;GppHFIxJ$@ .вejRIHH`Æ lذ>-[]vU$Ξ={ΦF,[ѣG~ƱsN̙Í%LM4GU uqq1׮]ŋƒQk׮nOJJã| 9%yz0>wpww{i۶m xvU>XZZ2go6l ʒ\ESHHHVTTDHHAAA߿tommM6m2mmټy37gժU/h Xn_5III@I@s=E+!!+WpUM&MhٲeM6nݺܺu ??? }`Ku>%]݀JLP|e˖tU-*dz|rry>%moT --_~E+Z\J7n>/h6mTԧ+mڴaÆUJ䄆ra WWo߾bTXz5/ѣGd2\\\޽JzЫOMBB/ݼ(OÆ ʕ+ p.`eiذ!fK*,>J `}Y)..pBf͚U%_׮]?`͊XZZプjV۷oebĉ|Sk] x]222X|9˖-###k^n4Dݻǽ{HJJ"==2Ą `ccCÆ iܸZfYBI#7J5BȀ^zѩSJĸ86õJ 6~<{?.=_fMhժJkUvMDDrWWW+ZƢEXz5YYY5v특yb=zDFF999:::ajjF;׮]c puusվ:sy~Wl]Yoρ/9sZ-T\zs2uܹ3mڴ)M7Ľ{~ziWE~~~߫Y&7QF4iҤژr9ݻltuu4iITE\\/$77LFfԩwa͚5B0P4ݻ7;vTŋ\r7nS쌃 4(j֬N4++t?~Lzz:ܹs;wǝ;wxfiذ!ҏK j*[N U$-[ڵkK+988ЩS'U2iii,[L&UgT pBOOOkjQ`v >NXbmm5666X[[Sn]ndddwtR([.4V+uZ[[Ӿ}{<<|4@GGMV˗ٳgrJ@E~MKi7FJɓ@޽?>Z$T=zĎ;ؼy3ǎ(-дiS\]]i֬Ygܾ}[q%e}C+Yh3fAĉ>}tѣϧubjJrr2۷og͜:uL)ukkkiڴ)_ƍ9rׯ+N%_둠oUk.~hƤpQ"##KM~|x{{$&&c8K7 4jԈMҴiSlll4҈ܹs*Ng+ESu^MH͈#pssOqm=ʕ+Whkk3`fΜ @R8s СCDGGboo= 6Fm,>ʕ+()= f׹gE߀G.sE=Z8ĄѣG3eQ_ 1)))>|CqȑҲ Lu֥~`iiIZ$-"'IJJ">>xn޼IJJJEQQ?u-/B>倮 Æ TLNN?~G`ee&L@Z  ݻ}KRd2:t'|»+z6ɓ'ܼy8߿ORRFzzz@eFFFbjjXYYaeeEƍqrrYf]̛7g_Z8*䷷1̠AD' >>ӧOM^^IYڵk3j(iܸ$@ x üyzf?$@{###{=Qd !**ӧOXo߾=Ǐ_~/oAqq1;wd…DFFW ֶcBg'4xwiРƽB._̅ zjI‚>@Q|I $ ,,Eqիτf UCgVZѫW/$DQQ7n ::rrr]taذa 0@@\~uֱqF_gž @cFxzz_m{KLL L&LJC2hРj;>@PϹs) 2(K]޽U ;p)ihB 4!zI mgHAP0CUҨ!B40zm+vnv q8^a@Bs"6yl)999}|+_=ݻٵkIxV^O<=4lؔvOr-,[￟ٳgOdWWc޽VRNNYz5WfIκux78 ']l|ɴ{6co>Yt)w}*ٿ?c߾}A̙C=׿u~anf$i:|0o&ׯ`Pg&c>n)>|&.>ill&=z7^կ}G]JƷC~zx vؑ]L`kG0wx7oe;hhhhN;F[[---Jgg~u]ܸb |AOO$M"{w^BtGNkyӴi̞=;u%f̘Ann9\tuuMWW]]]>}:::Rx ǎ+c-L#&'͝;VHK2M15 8=bdѦ-M7ofҥFFƐ>}tueԑ#~5c| \pX}M6YHUOuuu_YYə3u䣄=i]|_$LIOcCCl۶-nWUUqt:'NZ68*77cǎ1k,##I{ȑLo`Q9NEEEP:"U xw,$i9'D"' [W.%s?"̚5G2}t##IPXXH25'qDp{tQPP׾5"I@^^R)ZZZ2E;Pd¿<\xD$ƍYOH.lV)ԧ>ESS99PH$F3"gx/Uks%R2;cٲeFFҤNQQh~'[^|U'?[Hү?[ [އbo`xx#{ٱcQ4!R]]SUUEooo&J?՗~pZL}PWWŋq LnK'a{\L >74JF3"ax 8cdLO룋;3={<^ZK2oݺ5'!£УyUo0] >ؾ};K,12>}tuuerhDn=M@.dp6ׯtS]]Myy9TVVrLF(GK8xb…{(jhhm۶kUUU>qG52Mdet98p ~K?Hܜ-n+!|SQ.}?@Ҩ555>HА-죭y~%E7x#---x ;Ӊ>j;1Oٴ'6lU:x {(IL <G[@YMoL0,ދ.fΜIKK Ǎ4I>|⸭ļ@{wZtY^.͛GSSӦY_Ic]www(F2|~e0i}]y##1===R$|G@gyX][ݝQG 4PŴihjjb޼yFF(+++**ʨ#ȍcFVԗ_O  Hٮ]H$PRR±c* 'Yo6ַ غuk_]]! #+ ]jg CoT ~_ZZѣG3M#yБ,.{q2`]]-22y{d6-fy&|.֬YË/hTC? -cn02ٴiSbbމބ/YYSzAAK'?12>Lqqq" ^wDd0nO_ŋS[[KN!squH2M5pK\hkooh4 gD/vFV(^~]8@ɓ')((T#rMwL:z,X`d4:ux ?Gҏي#r1Yvx`ppW^y{hL`Ѻ Щc5 2ȏ[TFVTO?kfdFx 3g2G ?Z/YIT3.7-Zdd2UUU>qG52J.g!=@_rK02 X7aMd@Wc2e ۶m{52#466$ 3qV~".]HtՊO7'~sssnݺ?apwdpy\ⷚ$iypkY&U?p@v;Np7g~x$ixkdB[dI0888aCF%IGInݺu&766k׮ ~`…$ nlK&ߏLz ,zzze?vX?)я~m?N?S$MT7)'"?~| (M'i~;H&G&ƹsc.wuuEEE`Annn $\^4}8Y? '(-- ~__3fd # ~%I:̞=;7>G3@$s]tү ^zv0wl~_~9$Ir8s`߾}L{ ֮]$IUr a=N_җ`?<#9sKIDATIw!$Ic&Q y XC8X$aNvoH4,$ # This file is part of jscribble. # # jscribble is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 2 of the License, or (at your option) any later # version. # # jscribble 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along with # jscribble. If not, see . # Reads the JSON file and generates a properties file for the Java program. $file = file_get_contents('config/config.js'); $config = json_decode($file, true); foreach ($config as $item) { echo $item['key'].'='.$item['value']."\n"; } ?> jscribble-1.7.7/doc/000077500000000000000000000000001174451527200142425ustar00rootroot00000000000000jscribble-1.7.7/doc/jscribble.1.rst000066400000000000000000000127551174451527200171040ustar00rootroot00000000000000.. Copyright © 2011-2012 Martin Ueding ######### jscribble ######### ******************************** infinite notepad written in Java ******************************** :Author: Martin Ueding :Date: 2012-04-01 :Manual section: 1 SYNOPSIS ======== ``jscribble [options]`` ``java -jar jscribble.jar [options]`` ``javaws http://martin-ueding.de/download/jscribble/jscribble.jnlp`` DESCRIPTION =========== jscribble is a graphical notepad with as many pages as you want. You can organize your notes within notepads. Best used with a graphics tablet or touchscreen. You can organize your notes into notebooks, which allow you to have several collections of notesheets. At startup, you can select which notepad you want to use. If you do not want to save your notes, you can go into the *scribble* mode. All notes that you take there, will be thrown away when you close the program—without any sheet of paper wasted. Taking notes on paper allows you to draw and write whatever you want. Some people are fast enough in LaTeX to set complicated formulas while in a lecture. Some prefer to draw these by hand but do not like carrying lots of paper with them. jscribble offers screen based note taking with as many pages as you want. Xournal offers more features but is paper size oriented which does not make sense on a 10" netbook screen where one wants to use the whole screen for taking notes. Another focus was set to avoid any mouse navigation. All you can do with your mouse (or pen) is draw, therefore you cannot click anything accidentally. Navigation is done with the keyboard. This stance is weakened a little now, there is a mouse only mode which features panels at the left and right side of the screen to flip pages. You can also advance to the next page using the middle click. Both of these options have to be enabled in the configuration file, though. The eraser was implemented later too, it can be disabled in the config if it causes trouble. It is activated by default since it is very handy. You need the Java Runtime Environment (JRE) to run jscribble. OPTIONS ======= ``-v`` Verbose Mode. ``--key value`` Allows one to overwrite any config key in the default config and the user config. See below for a list of all available config keys DEFAULT CONTROLS ================ To flip between the pages, you can use the arrows keys, space bar, enter and backspace. When the primary mouse button is pressed, a line is drawn, the secondary mouse button erases. All controls are displayed in the online help screen activated by ``h`` or ``F1``. FILES ===== jscribble uses plain PNG images to store your drawings. They are, by default, in the ``~/.local/share/jscribble`` directory. On Windows, that is somewhere in the ``C:\Documents & Settings`` or ``C:\Users`` directory. The notebooks are plain folders, each containing a heap of images. The folder name corresponds to the notebook name. To avoid strange names, the notebook name is restricted to very few characters by default. The images are numbered, zero padded to 6 digits. The program uses ``%06d.png`` to format the number. In case you have more images, the file name will get longer. :: ~/.jscribble/test_notebook/ 000001.png 000002.png ... 000100.png ... 999999.png 1000000.png ... You can delete images from the folder, the program will still find them. You will get something like ``Page 15/13`` if you delete two images in front of the gast one. There is a configuration option that will tell jscribble to automatically compress the file names, that is to renumber them so that they are consecutive. Config File ----------- jscribble supports a user config file that overrides values from the default config file. Create a file called ``config.properties`` in the ``.config/jscribble`` directory in your home directory. Then insert key-value pairs with an equal sign in each line. The format is the standard Java Properties format. Value Types ----------- **String** A string which will get parsed in some way. **Integer** A number, often sizes measured in pixels. **Color** A hexadecimal color with optional alpha part in the front, RRGGBB or AARRGGBB. **Float** A decimal number. **Keyboard Char or Code** A comma separated list of key key codes and key chars. A single character will be interpreted as a literal character on the keyboard, multiple characters will be interpreted as a key code number. **Mouse Mask** A comma separated list of mouse down masks. **Boolean** ``true`` or ``false``. Example Config -------------- :: memory_usage_show=true rule_line_spacing=20 Available Keys -------------- The type is given in brackets, the default value in parentheses. .. include:: keylist.rst SECURITY CONSIDERATIONS ======================= Named notebooks are saved in a folder in the user's home directory. Notebooks that are in the scribble mode are not saved to the user's home directory but in the temporary directory of the system. On Linux, this is usually ``/tmp``. The files are not readable to anyone but the user. If the user's home directory is encrypted, but the temporary folder is not, an attacker might be able to recover images drawn in the scribble mode. BUGS ==== Please report bugs in English or German via email to me. Include the version number which is displayed at the bottom of the help screen within the program. SEE ALSO ======== `Xournal `_ jscribble-1.7.7/doc/keylist.php000066400000000000000000000006551174451527200164450ustar00rootroot00000000000000 # Parse the default config file and insert the comments and default value # here. echo "\n"; $file = file_get_contents('config/config.js'); $config = json_decode($file, true); foreach ($config as $item) { echo "``".$item['key']."``\n\t"; if (!empty($item['comment'])) echo $item['comment']."\n"; echo "\t[".$item['type']."] (".$item['value'].")\n"; } ?> jscribble-1.7.7/generate_version_class000077500000000000000000000017451174451527200201560ustar00rootroot00000000000000#!/bin/bash # Copyright © 2011 Martin Ueding # This file is part of jscribble. # # jscribble is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 2 of the License, or (at your option) any later # version. # # jscribble 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along with # jscribble. If not, see . version=$1 echo "package jscribble;" echo "/**" echo " * Version name dummy." echo " */" echo "public class VersionName {" echo " /**" echo " * Current version number of the VCS." echo " */" echo " public static final String version = \"$version\";" echo "}" echo jscribble-1.7.7/install_files/000077500000000000000000000000001174451527200163255ustar00rootroot00000000000000jscribble-1.7.7/install_files/completion/000077500000000000000000000000001174451527200204765ustar00rootroot00000000000000jscribble-1.7.7/install_files/completion/generate_completion000077500000000000000000000025241174451527200244520ustar00rootroot00000000000000#!/usr/bin/php # This file is part of jscribble. # # jscribble is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 2 of the License, or (at your option) any later # version. # # jscribble 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along with # jscribble. If not, see . _jscribble() { local cur prev COMPREPLY=() _get_comp_words_by_ref cur prev case "$cur" in *) COMPREPLY=( $(compgen -W '-v' -- $cur) \ $(compgen -W ' ' -- $cur) ) ;; esac if (( COMP_CWORD > 0 )) then case "$prev" in ) COMPREPLY=( $(compgen -W 'true false' -- $cur) ) ;; esac fi return 0 } complete -F _jscribble jscribble # vim: ft=sh jscribble-1.7.7/install_files/jscribble000077500000000000000000000014141174451527200202120ustar00rootroot00000000000000#!/bin/bash # Copyright © 2011 Martin Ueding # This file is part of jscribble. # # jscribble is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 2 of the License, or (at your option) any later # version. # # jscribble 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along with # jscribble. If not, see . java -jar /usr/share/jscribble/jscribble.jar "$@" jscribble-1.7.7/install_files/jscribble.desktop000066400000000000000000000002151174451527200216550ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=jscribble GenericName=Infinite Notepad Exec=jscribble Icon=jscribble Terminal=false Categories=Utility jscribble-1.7.7/jscribble.jnlp000066400000000000000000000011411174451527200163160ustar00rootroot00000000000000 jscribble Infinite Notepad Martin Ueding jscribble-1.7.7/jscribble/000077500000000000000000000000001174451527200154345ustar00rootroot00000000000000jscribble-1.7.7/jscribble/NoteBookProgram.java000066400000000000000000000107521174451527200213540ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble; import java.io.File; import javax.swing.JOptionPane; import jscribble.helpers.Config; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; import jscribble.selectionWindow.NoteBookSelectionWindow; /** * The main program. * * @author Martin Ueding */ public class NoteBookProgram { /** * The folder where the images is stored. */ private static File fileDirectory = null; /** * The folder where the config file is stored. */ private static File configDirectory = null; /** * Getter for fileDirectory. */ public static File getFileDirectory(boolean offerMigration) { if (fileDirectory == null) { fileDirectory = new File( System.getProperty("user.home") + File.separator + ".local" + File.separator + "share" + File.separator + NoteBookProgram.getProgramname() ); if (!fileDirectory.exists()) { File oldDotDir = new File( System.getProperty("user.home") + File.separator + "." + NoteBookProgram.getProgramname() ); if (offerMigration && oldDotDir.exists()) { int answer = JOptionPane.showConfirmDialog( null, Localizer.get("Would you like to move the files from .jscribble to .local/share/jscribble?"), Localizer.get("Move files?"), JOptionPane.YES_NO_OPTION ); if (answer == JOptionPane.YES_OPTION) { File oldConfigFile = new File( System.getProperty("user.home") + File.separator + "." + NoteBookProgram.getProgramname() + File.separator + "config.properties" ); File newConfigFile = new File( System.getProperty("user.home") + File.separator + ".config" + File.separator + NoteBookProgram.getProgramname() + File.separator + "config.properties" ); newConfigFile.getParentFile().mkdirs(); oldConfigFile.renameTo(newConfigFile); oldDotDir.renameTo(fileDirectory); } else { fileDirectory = oldDotDir; } } } } return fileDirectory; } /** * Getter for configDirectory. */ public static File getConfigDirectory() { if (configDirectory == null) { configDirectory = new File( System.getProperty("user.home") + File.separator + ".config" + File.separator + NoteBookProgram.getProgramname() ); } return configDirectory; } /** * Returns the name of the program. */ public static String getProgramname() { return Config.getString("program_name"); } /** * Displays the NotebookSelectionWindow. * * @param args CLI arguments */ public static void main(String[] args) { // Parse the command line options. for (int i = 0; i < args.length; i++) { String string = args[i]; if (string.equalsIgnoreCase("-v")) { Logger.setDebug(true); } else { if (string.startsWith("--") && i + 1 < args.length && !args[i + 1].startsWith("--")) { String newValue = args[i + 1]; String key = string.substring(2); Config.set(key, newValue); } } } printVersionIfNeeded(args); Logger.log(getProgramname(), Localizer.get("Starting up.")); showSelectionWindow(); Logger.log(NoteBookProgram.class.getClass().getName(), Localizer.get("Entering interactive mode.")); } /** * Prints version number and exists if there is a "--version" argument. * * @param args CLI arguments */ private static void printVersionIfNeeded(String[] args) { if (args.length > 0 && args[0].equals("--version")) { System.out.println(String.format(Localizer.get("Version: %s"), VersionName.version)); System.exit(0); } } /** * Shows the NotebookSelectionWindow. */ private static void showSelectionWindow() { NoteBookSelectionWindow nsw = new NoteBookSelectionWindow(); nsw.showDialog(); } } jscribble-1.7.7/jscribble/drawPanel/000077500000000000000000000000001174451527200173515ustar00rootroot00000000000000jscribble-1.7.7/jscribble/drawPanel/CommandListener.java000066400000000000000000000071431174451527200233050ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import jscribble.helpers.Config; /** * Listens to the keyboard for the command key and then polls the user for a * command. The command is then executed. * * @author Martin Ueding */ public class CommandListener implements KeyListener, MouseListener { /** * The DrawPanel that is displaying the NoteBook. */ private DrawPanel drawPanel; /** * The listener that is to be notified when something is changed. */ private Redrawer redrawer; /** * Creates a new listener that listens to the given panel * * @param drawPanel panel to listen to */ public CommandListener(DrawPanel drawPanel) { this.drawPanel = drawPanel; drawPanel.addMouseListener(this); } /** * A listener to be called when a setting causes the panel to need * refreshing. * * @param redrawer listener to call after setting change */ public void addChangeListener(Redrawer redrawer) { this.redrawer = redrawer; } /** * Ignored. */ @Override public void keyPressed(KeyEvent ignored) { } /** * Handles various keyboard commands. */ @Override public void keyReleased(KeyEvent event) { if (Config.isKeyForCommand(event, "help_screen_close_key")) { drawPanel.setShowHelp(false); redrawer.actionPerformed(null); } else if (Config.isKeyForCommand(event, "help_screen_toggle_key")) { drawPanel.toggleHelp(); redrawer.actionPerformed(null); } else if (Config.isKeyForCommand(event, "ruling_toggle_key")) { drawPanel.toggleRuling(); redrawer.actionPerformed(null); } else if (Config.isKeyForCommand(event, "ruling_graph_toggle_key")) { drawPanel.toggleGraphRuling(); redrawer.actionPerformed(null); } else if (Config.isKeyForCommand(event, "onion_layer_increase_key")) { drawPanel.onionLayersIncrease(); } else if (Config.isKeyForCommand(event, "onion_layer_decrease_key")) { drawPanel.onionLayersDecrease(); } else if (Config.isKeyForCommand(event, "notebook_close_key")) { drawPanel.shutdown(); } } /** * Ignored. */ @Override public void keyTyped(KeyEvent ignored) { } /** * Checks for third and fourth mouse button. */ @Override public void mouseClicked(MouseEvent event) { if (Config.isButtonForCommand(event, "notebook_go_forward_mouse_button")) { drawPanel.goForward(); } else if (Config.isButtonForCommand(event, "notebook_go_back_mouse_button")) { drawPanel.goBackwards(); } } /** * Ignored. */ @Override public void mouseEntered(MouseEvent ignored) { } /** * Ignored. */ @Override public void mouseExited(MouseEvent ignored) { } /** * Ignored. */ @Override public void mousePressed(MouseEvent ignored) { } /** * Ignored. */ @Override public void mouseReleased(MouseEvent ignored) { } } jscribble-1.7.7/jscribble/drawPanel/DrawPanel.java000066400000000000000000000377161174451527200221070ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import javax.swing.JFrame; import javax.swing.JPanel; import jscribble.VersionName; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; import jscribble.helpers.Config; import jscribble.notebook.BufferedImageWrapper; import jscribble.notebook.NoteBook; /** * Displays the current page of a NoteBook. It also listens to the mouse and * relays the movements to the NoteBook as line drawing commands. It also * features a command listener for more user interaction. * * @author Martin Ueding */ @SuppressWarnings("serial") public class DrawPanel extends JPanel { /** * Color of the help lines. */ private static final Color lineColor = Config.getColor("ruling_line_color"); /** * The spacing between the help lines. */ private static final int lineSpacing = Config.getInteger("ruling_line_spacing"); /** * The NoteBook that is currently displayed. */ private NoteBook notebook; /** * Handles the image output. */ private ImageObserver io = this; /** * Whether to display the help panel. */ private boolean showHelp = false; /** * A list with all the HelpItem to display. */ private HelpItem[] helpItems = { new HelpItem( Config.getString("help_screen_toggle_key"), Localizer.get("show help") ), new HelpItem( Config.getString("help_screen_close_key"), Localizer.get("hide help") ), new HelpItem( Config.getString("notebook_go_forward_key"), Localizer.get("go forward") ), new HelpItem( Config.getString("notebook_go_back_key"), Localizer.get("go backward")), new HelpItem( Config.getString("notebook_goto_first_key"), Localizer.get("goto first") ), new HelpItem( Config.getString("notebook_goto_last_key"), Localizer.get("goto last") ), new HelpItem( Config.getString("notebook_close_key"), Localizer.get("save & exit") ), new HelpItem( Config.getString("onion_layer_increase_key"), Localizer.get("increase onion layers") ), new HelpItem( Config.getString("onion_layer_decrease_key"), Localizer.get("decrease onion layers") ), new HelpItem( Config.getString("ruling_toggle_key"), Localizer.get("toggle ruling") ), new HelpItem( Config.getString("ruling_graph_toggle_key"), Localizer.get("toggle graph paper") ), }; /** * How many images should be composed in a see through way. */ private int onionMode; /** * A cached image that is used instead of the original images in the onion * mode to conserve performance. Use it via the getter. */ private BufferedImage cachedImage; /** * The wrapper for the current image. Use it via the getter. */ private BufferedImageWrapper imageWrapper; /** * Whether the help splash screen is (still) displayed. */ private boolean showHelpSplash = Config.getBoolean("help_splash_enable"); /** * Which type of ruling is used. */ private RulingType ruling = RulingType.NONE; /** * Runtime to obtain memory usage. */ private Runtime r; /** * Thread that handles redrawing after the erasing stops. */ private InvalidationThread invalidationThread; /** * Parent frame that needs to be closed when the user hits the close button. */ private JFrame parent; /** * Creates a new display panel that will listen to changes from a specific * NoteBook. * * @param notebook The NoteBook to display. * @param parent Window to close when NoteBook is closed. */ public DrawPanel(NoteBook notebook, JFrame parent) { this.notebook = notebook; this.parent = parent; // Notify this instance when the notebook was is done drawing. notebook.setDoneDrawing(new Redrawer(this)); new PaintListener(this); r = Runtime.getRuntime(); } /** * Draws the help screen if needed. * * @param g Graphics2D to draw in */ private void drawHelp(Graphics2D g) { if (!showHelp) { return; } // Draw a dark rectangle to write the help text on. g.setColor(Config.getColor("help_screen_background_color")); int helpMargin = Config.getInteger("help_screen_margin"); int helpBorderRadius = Config.getInteger("help_screen_border_radius"); g.fillRoundRect( helpMargin, helpMargin, getWidth() - helpMargin * 2, getHeight() - helpMargin * 2, helpBorderRadius, helpBorderRadius); g.setColor(Color.WHITE); // Iterate through the help items and display them. int i = 0; int vspacing = Config.getInteger("help_screen_vspacing"); int spacing = Config.getInteger("help_screen_spacing"); int padding = Config.getInteger("help_screen_padding"); for (HelpItem h : helpItems) { g.drawString(h.helptext, padding, i * vspacing + padding); g.drawString(h.key, spacing + padding, i * vspacing + padding); i++; } // Print the version identifier. g.setColor(Color.GRAY); g.drawString(String.format(Localizer.get("Version %s"), VersionName.version), padding, getHeight() - padding); } /** * Draws a help splash screen at the beginning. * * @param g Graphics2D to draw in */ private void drawHelpSplash(Graphics2D g) { if (!showHelpSplash) { return; } // Draw a dark rectangle to write the help text on. g.setColor(Config.getColor("help_splash_background_color")); Dimension splashSize = new Dimension( getWidth() - Config.getInteger("help_splash_margin") * 2, Config.getInteger("help_splash_height")); int helpSplashBorderRadius = Config.getInteger("help_splash_border_radius"); g.fillRoundRect( (getWidth() - splashSize.width) / 2, (getHeight() - splashSize.height) / 2, splashSize.width, splashSize.height, helpSplashBorderRadius, helpSplashBorderRadius); g.setColor(Color.WHITE); g.drawString(Localizer.get("Press h or F1 to get help."), (getWidth() - splashSize.width) / 2 + Config.getInteger("help_splash_margin"), getHeight() / 2 + 5); } /** * Draws a line onto the current sheet. If onion mode is used, it will be * cached in another image. To the user, there will be no difference. * * @param line Line to draw. */ public void drawLine(Line2D line) { if (hasCachedImage()) { getImageWrapper().drawLine(line); } notebook.drawLine(line); showHelpSplash = false; } /** * Draws the helping lines if needed. * * @param g Graphics2D to draw on */ private void drawLines(Graphics2D g) { if (ruling != RulingType.NONE) { g.setColor(lineColor); // Vertical lines. if (ruling == RulingType.GRAPH) { for (int i = lineSpacing; i < getWidth(); i += lineSpacing) { g.drawLine(i, 0, i, getHeight()); } } // Horizontal lines. for (int i = lineSpacing; i < getHeight(); i += lineSpacing) { g.drawLine(0, i, getWidth(), i); } } } /** * Draws the memory usage onto the screen. * * @param g Graphics2D to draw on */ private void drawMemoryUsage(Graphics2D g) { if (!Config.getBoolean("memory_usage_show")) { return; } g.drawString( String.format( Localizer.get("%d MiB used, %d MiB free, %d MiB total"), (r.totalMemory() - r.freeMemory()) / 1024 / 1024, r.freeMemory() / 1024 / 1024, r.totalMemory() / 1024 / 1024 ), Config.getInteger("memory_usage_position_left"), getHeight() - Config.getInteger("memory_usage_position_bottom") ); } /** * Draws the number of onion layers as a string. * * @param g Graphics2D to draw on */ private void drawOnionInfo(Graphics2D g) { if (!isOnionMode()) { return; } g.drawString( String.format(Localizer.get("Onion Layers: %d"), onionMode), Config.getInteger("onion_info_position_left"), Config.getInteger("onion_info_position_top") ); } /** * Draws the page number on top. * * @param g Graphics2D to draw on */ private void drawPageNumber(Graphics2D g) { g.setColor(Color.BLUE); g.drawString(String.format(Localizer.get("Page %d/%d"), notebook.getCurrentSheet().getPagenumber(), notebook.getSheetCount()), getWidth() / 2, Config.getInteger("page_number_position_top")); } /** * Draws the scroll panels at the side of the screen if enabled in the * config. * * @param g Context of the current DrawPanel */ private void drawScrollPanels(Graphics2D g) { // Do nothing if the option is not set. if (!Config.getBoolean("scroll_panels_show")) { return; } try { // Read the dimension of the panel from the config file. int scrollPanelRadius = Config.getInteger("scroll_panel_width"); int scrollPanelPadding = Config.getInteger("scroll_panel_padding"); // Draw the panels on the sides. g.setColor(Config.getColor("scroll_panel_color")); g.fillRoundRect(-scrollPanelRadius, scrollPanelPadding, 2 * scrollPanelRadius, getHeight() - 2 * scrollPanelPadding, scrollPanelRadius, scrollPanelRadius); g.fillRoundRect(getWidth() - scrollPanelRadius, scrollPanelPadding, 2 * scrollPanelRadius, getHeight() - 2 * scrollPanelPadding, scrollPanelRadius, scrollPanelRadius); } catch (NumberFormatException e) { Logger.handleError(Localizer.get( "Malformed entry in config file.")); } } /** * Erases a line on the NoteBook. If a cachedImage is used, the line is * erased on that image as well. * * @param line Line to erase. */ public void eraseLine(Line2D line) { if (hasCachedImage()) { getImageWrapper().eraseLine(line); /* * The user might have erased some of the underlying ruling or * onion layers. Refreshing the picture with all its layers takes * too much time to do with each repaint. Schedule the picture for * expiration if that did not happen yet. If it is scheduled * already, keep it alive for a little longer. */ getInvalidationThread().keepAlive(); } notebook.eraseLine(line); showHelpSplash = false; } /** * Returns the cached image. This can be the original image if there is no * onion mode used, or the layered image if used. If there is no image yet, * it will be created and composed. * * @return Image which contains all the drawing information */ private BufferedImage getCachedImage() { // If the onion mode is not enabled, the original image can be used. if (!isOnionMode() && ruling == RulingType.NONE) { return notebook.getCurrentSheet().getImg(); } if (cachedImage == null) { // Create a new blank image. cachedImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY); Graphics2D g2 = (Graphics2D) cachedImage.getGraphics(); g2.setColor(Config.getColor("notebook_background_color")); g2.fillRect(0, 0, getWidth(), getHeight()); // Go back as many pages as there should be onion layers. int wentBack = 0; for (; wentBack < onionMode; wentBack++) { int prevPageNumber = notebook.getCurrentSheet() .getPagenumber(); notebook.goBackwards(); if (prevPageNumber == notebook.getCurrentSheet() .getPagenumber()) { break; } } // Set the layers to a given opacity. g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_ATOP, (float)(Config.getDouble("onion_mode_opacity") / Math.max(onionMode, 1)))); // Iterate through from the bottom to the top layer and compose // the images onto the cache image. while (wentBack > 0) { g2.drawImage(notebook.getCurrentSheet().getImg(), 0, 0, io); // Move on to the next NoteSheet. wentBack--; notebook.goForward(); } drawLines(g2); g2.drawImage(notebook.getCurrentSheet().getImg(), 0, 0, io); } return cachedImage; } /** * Retrieves and initializes the BufferedImageWrapper for the current cached * image. * * @return BufferedImageWrapper of cachedImage */ private BufferedImageWrapper getImageWrapper() { if (imageWrapper == null) { imageWrapper = new BufferedImageWrapper(cachedImage); } return imageWrapper; } /** * Returns an initializes the InvalidationThread. * @return Initialized InvalidationThread. */ private InvalidationThread getInvalidationThread() { if (invalidationThread == null || !invalidationThread.isAlive()) { invalidationThread = new InvalidationThread(this); invalidationThread.start(); } return invalidationThread; } /** * Goes one page back. */ public void goBackwards() { resetCachedImage(); notebook.goBackwards(); } /** * Goes one page forward. */ public void goForward() { resetCachedImage(); notebook.goForward(); } /** * Goes to the first page. */ public void gotoFirst() { resetCachedImage(); notebook.gotoFirst(); } /** * Goes to the last page. */ public void gotoLast() { resetCachedImage(); notebook.gotoLast(); } /** * Determines whether a cached image is currently used. * * @return Whether a cached image is used. */ private boolean hasCachedImage() { return cachedImage != null; } /** * Whether there are any onion layers displayed. * * @return Whether there are onion layers. */ private boolean isOnionMode() { return onionMode > 0; } /** * Decreases the onion layers and does additional housekeeping. */ public void onionLayersDecrease() { // Do nothing if there are no layers displayed currently. if (!isOnionMode()) { return; } resetCachedImage(); onionMode--; repaint(); } /** * Increases the onion layers and does additional housekeeping. */ public void onionLayersIncrease() { resetCachedImage(); onionMode++; repaint(); } /** * Draws the NoteSheet and page number. If lines are on, they are drawn on * top of the image as well. * * @param graphics graphics context (usually given by Java itself). */ protected void paintComponent(Graphics graphics) { Graphics2D g = (Graphics2D)graphics; g.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); // Draw the current image. g.drawImage(getCachedImage(), 0, 0, io); drawPageNumber(g); drawOnionInfo(g); drawScrollPanels(g); drawHelp(g); drawHelpSplash(g); drawMemoryUsage(g); } /** * Resets the cached image after changing pages for instance. */ protected void resetCachedImage() { cachedImage = null; imageWrapper = null; showHelpSplash = false; } /** * Sets whether the help dialog is displayed. */ public void setShowHelp(boolean showHelp) { this.showHelp = showHelp; } /** * Saves the NoteBook and closes the window. */ public void shutdown() { notebook.saveToFiles(); parent.setVisible(false); } /** * Toggles the display of graph ruling. */ public void toggleGraphRuling() { ruling = ruling == RulingType.GRAPH ? RulingType.NONE : RulingType.GRAPH; resetCachedImage(); } /** * Whether to display the help panel. */ public void toggleHelp() { showHelp = !showHelp; showHelpSplash = false; } /** * Toggles the display of (line) ruling. */ public void toggleRuling() { ruling = ruling == RulingType.LINE ? RulingType.NONE : RulingType.LINE; resetCachedImage(); } } jscribble-1.7.7/jscribble/drawPanel/HelpItem.java000066400000000000000000000030311174451527200217200ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.event.KeyEvent; /** * A container for a key and help text. * * @author Martin Ueding */ public class HelpItem { /** * The buttons(s) that cause some action. */ public String key; /** * The action the buttons cause. */ public String helptext; /** * Generates a new HelpItem. */ public HelpItem(String keys, String helptext) { this.helptext = helptext; String[] parts = keys.split(","); StringBuilder sb = new StringBuilder(); for (int i = 0; i < parts.length; i++) { String part = parts[i]; if (i > 0) { sb.append(", "); } if (part.length() == 1) { sb.append(part.toUpperCase()); } else { sb.append(KeyEvent.getKeyText(Integer.parseInt(part))); } } this.key = sb.toString(); } } jscribble-1.7.7/jscribble/drawPanel/InvalidationThread.java000066400000000000000000000035071174451527200237720ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import jscribble.helpers.Config; /** * Waits until no more events come in and repaints the DrawPanel. * * @author Martin Ueding */ public class InvalidationThread extends Thread { /** * Whether the Thread should wait another turn. */ boolean keepAlive = true; /** * The DrawPanel to repaint. */ private DrawPanel drawPanel; /** * Creates a new Thread that repaints the DrawPanel after a no more events. * * @param drawPanel Panel to redraw. */ public InvalidationThread(DrawPanel drawPanel) { super(); this.drawPanel = drawPanel; } /** * Tells the Thread that another event came in and that the picture is not to be repainted yet. */ public void keepAlive() { keepAlive = true; } /** * Waits until no more events come in and repaints the DrawPanel. */ public void run() { while (keepAlive) { keepAlive = false; try { sleep(Config.getInteger("notebook_erase_timeout")); } catch (InterruptedException e) { e.printStackTrace(); } } drawPanel.resetCachedImage(); drawPanel.repaint(); } } jscribble-1.7.7/jscribble/drawPanel/MovementListener.java000066400000000000000000000057021174451527200235200ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import jscribble.helpers.Config; /** * Handles movement commands from the keyboard. * * @author Martin Ueding */ public class MovementListener implements KeyListener { /** * The DrawPanel that displays the current NoteBook. */ private final DrawPanel drawPanel; /** * Creates a MovementListener that relays to the given DrawPanel. * * @param drawPanel Notify this. */ public MovementListener(DrawPanel drawPanel) { this.drawPanel = drawPanel; } /** * Determines whether a given KeyEvent should fire going back a page. * * @param event KeyEvent to process * @return Whether this should fire going back a page. */ private boolean isKeyGoBack(KeyEvent event) { return Config.isKeyForCommand(event, "notebook_go_back_key"); } /** * Determines whether a given KeyEvent should fire going forward a page. * * @param event KeyEvent to process * @return Whether this should fire going forward a page. */ private boolean isKeyGoForward(KeyEvent event) { return Config.isKeyForCommand(event, "notebook_go_forward_key"); } /** * Determines whether a given KeyEvent should fire going to the first page. * * @param event KeyEvent to process * @return Whether this should fire going to the first page. */ private boolean isKeyGotoFirst(KeyEvent event) { return Config.isKeyForCommand(event, "notebook_goto_first_key"); } /** * Determines whether a given KeyEvent should fire going to the last page. * * @param event KeyEvent to process * @return Whether this should fire going to the last page. */ private boolean isKeyGotoLast(KeyEvent event) { return Config.isKeyForCommand(event, "notebook_goto_last_key"); } /** * Ignored. */ public void keyPressed(KeyEvent event) {} /** * Handles various keys. */ public void keyReleased(KeyEvent event) { if (isKeyGoForward(event)) { drawPanel.goForward(); } if (isKeyGoBack(event)) { drawPanel.goBackwards(); } if (isKeyGotoFirst(event)) { drawPanel.gotoFirst(); } if (isKeyGotoLast(event)) { drawPanel.gotoLast(); } } /** * Ignored. */ public void keyTyped(KeyEvent event) {} } jscribble-1.7.7/jscribble/drawPanel/NoteBookClosingAdapter.java000066400000000000000000000034141174451527200245560ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; import jscribble.notebook.NoteBook; /** * Closes a given NoteBook when its DrawPanel is closed. * * @author Martin Ueding */ public class NoteBookClosingAdapter extends WindowAdapter { private final NoteBook notebook; private final JFrame f; /** * Creates a NoteBookClosingAdapter that closes a given NoteBook and its window. * * @param notebook NoteBook to close. * @param f Window of the NoteBook to close. */ public NoteBookClosingAdapter(NoteBook notebook, JFrame f) { this.notebook = notebook; this.f = f; } /** * Closes all the NoteBook instances. */ public void windowClosing(WindowEvent winEvt) { notebook.saveToFiles(); Logger.log(getClass().getName(), String.format(Localizer.get("Closing NoteBook \"%s\"."), notebook.getName())); f.setVisible(false); } } jscribble-1.7.7/jscribble/drawPanel/PaintListener.java000066400000000000000000000073621174451527200230050ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Line2D; import jscribble.helpers.Config; /** * Listens to mouse movements on the displaying panel and updates the NoteBook. * * @author Martin Ueding */ public class PaintListener implements MouseMotionListener, MouseListener { /** * The last position of the pointer. Since the line commands needs two * points, but the mouseDragged() only gives the current location, the * class needs to remember where the pointer was before. */ private Point lastPosition = new Point(-1, -1); /** * The panel to notify when something is drawn. */ private DrawPanel drawPanel; /** * Generates a new Listener that relays its commands to a given DrawPanel. * * @param drawPanel Relay to this. */ public PaintListener(DrawPanel drawPanel) { this.drawPanel = drawPanel; drawPanel.addMouseListener(this); drawPanel.addMouseMotionListener(this); } /** * Draws a single dot when the mouse is clicked. Handles the scroll panels * in the mouse only mode. Erases on single right click. */ @Override public void mouseClicked(MouseEvent event) { int x = event.getX(); if (Config.getBoolean("scroll_panels_show")) { if (x <= Config.getInteger("scroll_panel_width")) { drawPanel.goBackwards(); return; } if (x >= drawPanel.getWidth() - Config.getInteger("scroll_panel_width")) { drawPanel.goForward(); return; } } if (Config.isButtonForCommand(event, "notebook_draw_mouse_button")) { Line2D line = new Line2D.Float(event.getPoint(), event.getPoint()); drawPanel.drawLine(line); } else if (Config.getBoolean("notebook_erase_enable") && Config.isButtonForCommand(event, "notebook_erase_mouse_button")) { Line2D line = new Line2D.Float(event.getPoint(), event.getPoint()); drawPanel.eraseLine(line); } } /** * Tells the NoteBook to draw a line on it. */ public void mouseDragged(MouseEvent event) { if (Config.isButtonForCommand(event, "notebook_draw_mouse_button")) { Line2D line = new Line2D.Float(lastPosition, event.getPoint()); drawPanel.drawLine(line); } else if (Config.getBoolean("notebook_erase_enable") && Config.isButtonForCommand(event, "notebook_erase_mouse_button")) { Line2D line = new Line2D.Float(lastPosition, event.getPoint()); drawPanel.eraseLine(line); } lastPosition = event.getPoint(); } /** * Ignored. */ @Override public void mouseEntered(MouseEvent ignored) { } /** * Ignored. */ @Override public void mouseExited(MouseEvent ignored) { } /** * Sets last mouse position so that the next line is not drawn across the * screen. */ public void mouseMoved(MouseEvent event) { lastPosition = event.getPoint(); } /** * Ignored. */ @Override public void mousePressed(MouseEvent ignored) { } /** * Ignored. */ @Override public void mouseReleased(MouseEvent ignored) { } } jscribble-1.7.7/jscribble/drawPanel/Redrawer.java000066400000000000000000000026251174451527200217740ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JPanel; /** * Listens to changes from the NoteBook and updates the panel. * * @author Martin Ueding */ public class Redrawer implements ActionListener { /** * Panel which is to be redrawn. */ private JPanel panel; /** * Creates a new Redrawer that tells the given Panel to redraw. * * @param panel panel to redraw when notified */ public Redrawer(JPanel panel) { this.panel = panel; } /** * Redraws the previously set panel. */ @Override public void actionPerformed(ActionEvent e) { panel.repaint(); } } jscribble-1.7.7/jscribble/drawPanel/RulingType.java000066400000000000000000000016201174451527200223150ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.drawPanel; /** * Different type of ruling. * * There is graph ruling, line ruling or plain page. */ public enum RulingType { NONE, GRAPH, LINE; } jscribble-1.7.7/jscribble/helpers/000077500000000000000000000000001174451527200170765ustar00rootroot00000000000000jscribble-1.7.7/jscribble/helpers/Config.java000066400000000000000000000167301174451527200211550ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.helpers; import java.awt.Color; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; import jscribble.NoteBookProgram; /** * Serves as an interface to the config file. Provides several convenience * functions for various types in lookup. * * @author Martin Ueding */ public class Config { /** * Main config used for user specific settings. */ private static Properties userConfig; /** * Default config that is used if the user did not specify this in his * config file. */ private static Properties defaultConfig; /** * Config options specified at the command line. */ private static Properties sessionConfig; /** * Looks up a boolean value in the config file. * * @param key Key to look up. * @return Config value or default as boolean. */ public static boolean getBoolean(String key) { return Boolean.parseBoolean(retrieve(key)); } /** * Gets the default config, initializes if needed. * * @return Initialized config. */ private static Properties getDefaultConfig() { if (defaultConfig == null) { initDefaultConfig(); } return defaultConfig; } /** * Looks up a integer value in the config file. * * @param key Key to look up. * @return Config value or default as integer. */ public static int getInteger(String key) { return Integer.parseInt(retrieve(key)); } /** * Looks up a hexadecimal integer value from the config and converts it * into a Color. * * @param key Key to look up. * @return Config value as Color. */ public static Color getColor(String key) { int color = (int) Long.parseLong(retrieve(key), 16); return new Color(color, isColorWithAlpha(color)); } /** * Determines whether a given color has an alpha part. * * @param color The color to check for alpha part. * @return Whether there is an alpha part. */ private static boolean isColorWithAlpha(int color) { return color > 0xFFFFFF || color < 0; } /** * Looks up a string value in the config file. * * @param key Key to look up. * @return Config value or default as string. */ public static String getString(String key) { return retrieve(key); } /** * Gets the config, initializes if needed. * * @return Initialized config. */ private static Properties getUserConfig() { if (userConfig == null) { initUserConfig(); } return userConfig; } /** * Loads the default config from the bundled file. */ private static void initDefaultConfig() { defaultConfig = new Properties(); try { defaultConfig.load(Config.class.getResourceAsStream("/jscribble/default_config.properties")); } catch (FileNotFoundException e) { Logger.handleError(Localizer.get("Could not find the config file. (This should *not* happen!)")); e.printStackTrace(); } catch (IOException e) { Logger.handleError(Localizer.get( "IO error while reading config file.")); e.printStackTrace(); } } /** * Loads the user config if there is one. */ private static void initUserConfig() { userConfig = new Properties(); try { File configfile = new File(NoteBookProgram.getConfigDirectory() + File.separator + getString("user_config_filename")); if (configfile.exists()) { Logger.log(Config.class.getClass().getName(), String.format(Localizer.get("Loading user configuration file from %s."), configfile.getName())); userConfig.load(new FileInputStream(configfile)); } else { Logger.log(Config.class.getClass().getName(), String.format(Localizer.get("There is no user config in %s."), configfile.getAbsolutePath())); } } catch (FileNotFoundException e) { Logger.handleError(Localizer.get("Could not find the config file. (This should *not* happen!)")); e.printStackTrace(); } catch (IOException e) { Logger.handleError(Localizer.get( "IO error while reading config file.")); e.printStackTrace(); } } /** * Retrieves a string from either the user or default config. * * @param key Parameter name to look up. * @return Value. */ private static String retrieve(String key) { if (sessionConfig != null && sessionConfig.containsKey(key)) { return sessionConfig.getProperty(key); } else if (getUserConfig().containsKey(key)) { return getUserConfig().getProperty(key); } else if (getDefaultConfig().containsKey(key)) { return getDefaultConfig().getProperty(key); } else { Logger.handleError(String.format( Localizer.get("There is no default setting for %s."), key )); return ""; } } /** * Wrapper to retrieve a double. * * @param key Parameter name to look up. * @return Value. */ public static double getDouble(String key) { return Double.parseDouble(retrieve(key)); } /** * Checks whether a pressed key should trigger a command. * * @param event Pressed key. * @param command Command in question. * @return Whether this should trigger. */ public static boolean isKeyForCommand(KeyEvent event, String command) { String raw_array = retrieve(command); if (raw_array.length() == 0) { return false; } String[] parts = raw_array.split(","); for (String part : parts) { if (part.length() == 1) { if (event.getKeyChar() == part.charAt(0)) { Logger.log(Config.class.getName(), String.format(Localizer.get("%c is a valid key for %s."), event.getKeyChar(), command)); return true; } } else if (event.getKeyCode() == Integer.parseInt(part)) { Logger.log(Config.class.getName(), String.format(Localizer.get("%s is a valid key for %s."), KeyEvent.getKeyText(event.getKeyChar()), command)); return true; } } return false; } /** * Checks whether a pressed mouse button should trigger a command. * * @param event Pressed mouse button. * @param command Command in question. * @return Whether this should trigger. */ public static boolean isButtonForCommand(MouseEvent event, String command) { String raw_array = retrieve(command); if (raw_array.length() == 0) { return false; } String[] parts = raw_array.split(","); for (String part : parts) { if (event.getModifiersEx() == Integer.parseInt(part)) { Logger.log(Config.class.getName(), String.format(Localizer.get("%s is a valid key for %s."), MouseEvent.getModifiersExText(event.getModifiersEx()), command)); return true; } } return false; } /** * Override a config setting for this session. * * @param key Key to override. * @param value New value. */ public static void set(String key, String value) { if (sessionConfig == null) { sessionConfig = new Properties(); } sessionConfig.setProperty(key, value); } } jscribble-1.7.7/jscribble/helpers/FileComparator.java000066400000000000000000000023741174451527200226560ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.helpers; import java.io.File; import java.text.Collator; import java.util.Comparator; /** * Compares two files by their file names. */ public class FileComparator implements Comparator { /** * Collator to compare strings. */ private Collator c = Collator.getInstance(); /** * Compares two files by their filenames. */ public int compare(File o1, File o2) { if (o1 == o2) { return 0; } File f1 = (File) o1; File f2 = (File) o2; return c.compare(f1.getName(), f2.getName()); } } jscribble-1.7.7/jscribble/helpers/Localizer.java000066400000000000000000000036221174451527200216700ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.helpers; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * Localizes strings. * * @author Martin Ueding */ public class Localizer { /** * Bundle containing the l10n into. */ static ResourceBundle bundle; /** * Translate a string. * * @param ident English language string. * @return Native language string. */ public static String get(String ident) { // Try to load the ResourceBundle. if (bundle == null) { try { bundle = ResourceBundle.getBundle("l10n/jscribble"); } catch (ExceptionInInitializerError e) { Logger.log(Localizer.class.getName(), "Error: " + e.getMessage()); bundle = null; } catch (MissingResourceException e) { Logger.log(Localizer.class.getName(), "Error: " + e.getMessage()); bundle = null; } } // Do not translate if there is no translation around. if (bundle == null) { return ident; } else { try { return bundle.getString(ident); } catch (MissingResourceException e) { Logger.log(Localizer.class.getName(), e.getMessage()); return ident; } } } } jscribble-1.7.7/jscribble/helpers/Logger.java000066400000000000000000000044721174451527200211670ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.helpers; import java.awt.HeadlessException; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.JOptionPane; /** * Handles logging and error reporting * * @author Martin Ueding */ public class Logger { /** * Whether to show debug information by default. This can be overridden by * the "-v" command line option. */ private static boolean debug = false; /** * Handles some error message centrally, right now it just displays a * dialog box with the error message. * * @param errorMessage error message */ public static void handleError(String errorMessage) { log("ERROR", errorMessage); try { JOptionPane.showMessageDialog(null, errorMessage); } // When running unit tests in headless mode, any errors that show up // will try to display a message dialog, which will make the test crash. // With this try-catch, the test will not fail because of that. catch (HeadlessException ignored) {} System.exit(1); } /** * Writes a message to a log file. * * @param reportingClass name of the reporting class * @param message message */ public static void log(String reportingClass, String message) { if (debug) { SimpleDateFormat formatter = new SimpleDateFormat(Config.getString("date_format")); String date = formatter.format(new Date()); String output = date + " " + reportingClass + ":\t" + message; System.out.println(output); } } /** * Switched debug mode on or off. * * @param b New value for debug mode. */ public static void setDebug(boolean b) { debug = b; } } jscribble-1.7.7/jscribble/notebook/000077500000000000000000000000001174451527200172545ustar00rootroot00000000000000jscribble-1.7.7/jscribble/notebook/BufferedImageWrapper.java000066400000000000000000000054751174451527200241600ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import jscribble.helpers.Config; /** * Wraps drawing on an image. * * @author Martin Ueding */ public class BufferedImageWrapper { /** * Image to draw onto. */ private BufferedImage img; /** * Graphics context for the image. */ private Graphics2D graphics; /** * Stroke for drawing. */ private Stroke drawStroke = new BasicStroke( Config.getInteger("notebook_draw_stroke_width")); /** * Stroke for erasing. */ private Stroke eraseStroke = new BasicStroke( Config.getInteger("notebook_erase_stroke_width")); /** * Background color. */ private Color background = Config.getColor("notebook_background_color"); /** * Foreground color. */ private Color foreground = Config.getColor("notebook_foreground_color"); /** * Creates a new wrapper around the given image. * * @param image Image to wrap. */ public BufferedImageWrapper(BufferedImage image) { img = image; graphics = (Graphics2D) img.getGraphics(); graphics.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); } /** * Draws a line on the picture. * * @param line Line to draw. */ public void drawLine(Line2D line) { graphics.setColor(foreground); graphics.setStroke(drawStroke); graphics.drawLine((int) line.getX1(), (int) line.getY1(), (int) line.getX2(), (int) line.getY2()); } /** * Erases a line from the picture. * * @param line Line to erase. */ public void eraseLine(Line2D line) { graphics.setColor(background); graphics.setStroke(eraseStroke); graphics.drawLine((int) line.getX1(), (int) line.getY1(), (int) line.getX2(), (int) line.getY2()); } /** * Getter for the wrapped image. * * @return Image. */ public BufferedImage getImg() { return img; } } jscribble-1.7.7/jscribble/notebook/NoteBook.java000066400000000000000000000302131174451527200216360ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook; import java.awt.Dimension; import java.awt.HeadlessException; import java.awt.event.ActionListener; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.JOptionPane; import jscribble.NoteBookProgram; import jscribble.helpers.Config; import jscribble.helpers.FileComparator; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; /** * A container for several NoteSheet. * * The NoteBook contains at least one NoteSheet and adds new sheets whenever * the forward() function is called. The whole NoteBook can be saved into * individual pictures. * * @author Martin Ueding */ public class NoteBook implements Comparable { // XXX This list cannot cope with running out of memory. // The lists need to be able to shrink if you advance way into the // notebook. /** * A List with all the NoteSheet this NoteBook contains, */ private LinkedList sheets; /** * The currently opened page. */ private int currentSheet = 0; /** * The folder which contains the NoteSheet. */ private File folder; /** * Size of the individual NoteSheet. */ private Dimension noteSize; /** * Default size of the NoteSheet. */ private Dimension noteSizeDefault = new Dimension( Config.getInteger("notebook_default_width"), Config.getInteger("notebook_default_height") ); /** * Listener that needs to be notified after the current sheet is changed. */ private ActionListener doneDrawing; /** * Count of pages. Latest page number is page count. */ private int pagecount = 1; /** * How many images to cache back and front. */ private int cacheWidth = Config.getInteger("notebook_cache_width"); /** * The name of this NoteBook. It is also the folder name. */ private String name; /** * Creates an empty NoteBook with a single NoteSheet. * * @param name name of the NoteBook */ public NoteBook(String name) { sheets = new LinkedList(); this.name = name; // if a NoteBook should be used if (name != null) { folder = new File(NoteBookProgram.getFileDirectory(false).getAbsolutePath() + File.separator + name); loadImagesFromFolder(); } else { name = UUID.randomUUID().toString(); folder = new File(System.getProperty("java.io.tmpdir") + File.separator + name); } } /** * Creates a new NoteBook with the given size. * * @param name Name of the NoteBook. * @param noteSize Size of the NoteSheet. */ public NoteBook(String name, Dimension noteSize) { this(name); this.noteSize = noteSize; } /** * Add an empty sheet if the NoteBook would be empty otherwise. */ private void addPageIfEmpty() { if (sheets.size() == 0) { sheets.add(new NoteSheet(getSize(), pagecount, generateNextFilename(pagecount))); pagecount++; currentSheet = 0; } } /** * Polls the user for the resolution. The user is asked whether he wants * to use his screen size or the default size. */ private void askForResolution() { try { Dimension nativeSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); if (!nativeSize.equals(noteSizeDefault) && JOptionPane.showConfirmDialog( null, String.format( Localizer.get("Would you like to use your native resolution (%dx%d) instead of the default (%dx%d)?"), (int) nativeSize.getWidth(), (int) nativeSize.getHeight(), (int) noteSizeDefault.getWidth(), (int) noteSizeDefault.getHeight() ), Localizer.get("Default Resolution"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { noteSize = nativeSize; } else { noteSize = noteSizeDefault; } } catch (HeadlessException ignored) { noteSize = noteSizeDefault; } } /** * Compares to NoteBook with each other. Sorting is done by their names. */ @Override public int compareTo(NoteBook other) { return getName().compareTo(other.getName()); } /** * Asks the user to delete the NoteBook. */ public boolean delete() { int answer = JOptionPane.showConfirmDialog(null, String.format( Localizer.get("Do you really want to delete \"%s\"?"), name), Localizer.get("Really delete?"), JOptionPane.YES_NO_OPTION); if (answer == 0) { deleteSure(); return true; }; return false; } /** * Delete the NoteBook from the file system. */ public void deleteSure() { if (folder == null) { return; } // Delete all the files in the folder. File[] subfiles = folder.listFiles(); if (subfiles == null) { return; } for (File file : subfiles) { file.delete(); } // Delete the folder itself. folder.delete(); if (folder.exists()) { Logger.log(getClass().getName(), Localizer.get("Could not delete folder.")); } } /** * Draws a line onto the current sheet. * * @param line Line to draw. */ public void drawLine(Line2D line) { getCurrentSheet().drawLine(line); fireDoneDrawing(); } /** * Erases a line from the current sheet. * * @param line Line to erase. */ public void eraseLine(Line2D line) { getCurrentSheet().eraseLine(line); fireDoneDrawing(); } /** * Tell the listener (the DrawPanel) that the NoteBook has changed and * needs to be redrawn. */ private void fireDoneDrawing() { if (doneDrawing != null) { doneDrawing.actionPerformed(null); } } /** * Generates the File for the next NoteSheet. * * @param pagenumber page number to use * @return File object with correct name */ private File generateNextFilename(int pagenumber) { if (folder != null && name != null) { try { return new File(folder.getCanonicalPath() + File.separator + String.format("%06d", pagenumber) + ".png"); } catch (IOException e) { Logger.handleError(Localizer.get( "Could not determine path of NoteBook folder.")); e.printStackTrace(); } } return null; } /** * Gets the NoteSheet object which the currently open page of the NoteBook. */ public NoteSheet getCurrentSheet() { addPageIfEmpty(); if (currentSheet < 0 || currentSheet >= sheets.size()) { Logger.log(getClass().getName(), "IndexOutOfBounds"); } return sheets.get(currentSheet); } /** * Returns the name of the NoteBook. */ public String getName() { return name; } /** * Number of sheets in the NoteBook */ public int getSheetCount() { // If there is no sheets list (should be impossible to achieve this), // then there are no sheets in the NoteBook. if (sheets == null) { return 0; } // If there is a sheet in the NoteBook, but is has not been touched // yet, count it as zero sheets. if (sheets.size() == 1 && !sheets.get(0).touched()) { return 0; } return sheets.size(); } /** * Getter for the size. * * @return Size of the NoteSheet. */ public Dimension getSize() { if (noteSize == null) { askForResolution(); } return noteSize; } /** * Goes back one sheet. */ public void goBackwards() { if (currentSheet > 0) { getCurrentSheet().saveToFile(); if (currentSheet + cacheWidth < sheets.size()) { sheets.get(currentSheet + cacheWidth).freeImage(); } currentSheet--; fireDoneDrawing(); } } /** * Flip the pages forward. It creates a new page if needed. If the current * page is a blank page, no new blank page will be added. */ public void goForward() { // Page sheets that are far away to RAM. getCurrentSheet().saveToFile(); if (currentSheet >= cacheWidth) { sheets.get(currentSheet - cacheWidth).freeImage(); } // If we are within the NoteBook, we just need to advance a step. if (sheets.size() > currentSheet + 1) { currentSheet++; } // If we are the last sheet and it has been touched, the user needs a // new blank sheet. Add it. else if (getCurrentSheet().touched()) { sheets.add(new NoteSheet(getSize(), pagecount, generateNextFilename(pagecount))); currentSheet++; pagecount++; } // The NoteBook is at a blank sheet at its end. There is nothing to do. else { return; } fireDoneDrawing(); } /** * Goes to the first page in the NoteBook. */ public void gotoFirst() { getCurrentSheet().saveToFile(); currentSheet = 0; fireDoneDrawing(); } /** * Goes to the last page in the NoteBook. */ public void gotoLast() { getCurrentSheet().saveToFile(); currentSheet = Math.max(0, sheets.size() - 1); fireDoneDrawing(); } /** * Loads the images from the previously set folder. */ private void loadImagesFromFolder() { if (!folder.exists()) { folder.mkdirs(); // Since the folder was just created, there are not going to be any // pictures in it. return; } // If the user wants it, compress the filenames. if (Config.getBoolean("notebook_auto_compress")) { NoteBookCompressor nbc = new NoteBookCompressor(folder); nbc.compress(); } // try to load all images that match the name File[] allImages = folder.listFiles(new NoteSheetFileFilter()); if (allImages != null && allImages.length > 0) { Arrays.sort(allImages, new FileComparator()); Pattern p = Pattern.compile("(\\d+)\\.png"); for (File file : allImages) { String[] nameparts = file.getName().split(Pattern.quote(File.separator)); String basename = nameparts[nameparts.length - 1]; Matcher m = p.matcher(basename); if (m.matches()) { pagecount = Math.max(pagecount, Integer.parseInt(m.group(1))); sheets.add(new NoteSheet(noteSize, Integer.parseInt(m.group(1)), file)); pagecount++; if (noteSize == null) { try { BufferedImage resolutionSampler = ImageIO.read(file); noteSize = new Dimension(resolutionSampler.getWidth(), resolutionSampler.getHeight()); } catch (IOException e) { Logger.handleError(Localizer.get("Unable to determine resolution from first image in NoteBook.")); e.printStackTrace(); } } } } } } /** * Tells the WriteoutThread that this NoteBook has no more sheets to save. */ private void quitWithWriteoutThread() { sheets.getFirst().stopWriteoutThread(); } /** * Waits for the last image to be written without initializing the saving * itself. * * This is pretty pointless, *unless* to test how whether the * NoteBook actually saves every sheet after moving. Do not use within the * program. */ public void testing_finalize() { quitWithWriteoutThread(); } /** * Persists the whole NoteBook into individual files. */ public void saveToFiles() { Logger.log(getClass().getName(), Localizer.get( "Starting to write out image files.")); for (NoteSheet s : sheets) { s.freeImage(); } quitWithWriteoutThread(); } /** * Sets an action listener to be called when something new was drawn. * * @param doneDrawing ActionListener to be called after drawing a new line. */ public void setDoneDrawing(ActionListener doneDrawing) { this.doneDrawing = doneDrawing; } /** * Returns a string representation of the NoteBook, consisting of the name * and page count. */ public String toString() { return String.format("%s (%d)", name, getSheetCount()); } } jscribble-1.7.7/jscribble/notebook/NoteBookCompressor.java000066400000000000000000000044271174451527200237230ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook; import java.io.File; import java.util.Arrays; import jscribble.helpers.FileComparator; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; /** * Takes a folder which contains a notebook and compresses the file names so * that there are no gaps in the numbering. * * @author Martin Ueding */ public class NoteBookCompressor { File folder; public NoteBookCompressor(File folder) { this.folder = folder; } public void compress() { // Gather all the file names from the folder. File[] allImages = folder.listFiles(new NoteSheetFileFilter()); // If there are no images in this folder, there is nothing to do. if (allImages == null || allImages.length == 0) { return; } // Sort the file names. Arrays.sort(allImages, new FileComparator()); // Stop if it is already in the correct order. if (allImages[allImages.length - 1].getName().equalsIgnoreCase(String.format("%06d.png", allImages.length))) { Logger.log(getClass().getName(), String.format(Localizer.get("Stop processing %s"), folder.getName())); return; } // Rename the files according to their place in the array. for (int i = 0; i < allImages.length; i++) { File image = allImages[i]; image.getParent(); File newName = new File( image.getParent() + File.separator + String.format("%06d.png", i + 1) ); Logger.log(getClass().getName(), String.format(Localizer.get("Rename %s to %s."), image.getName(), newName.getName())); image.renameTo(newName); } } } jscribble-1.7.7/jscribble/notebook/NoteSheet.java000066400000000000000000000230471174451527200220230ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import javax.imageio.ImageIO; import jscribble.NoteBookProgram; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; import jscribble.helpers.Config; import jscribble.notebook.writeoutThread.ImageSwapTask; import jscribble.notebook.writeoutThread.WriteoutThread; /** * Represents a single note sheet. A NoteSheet consist a grayscale image. The * image is displayed, allowing the user to paint on it. Each image has its * individual file name that is used automatically. * * @author Martin Ueding */ public class NoteSheet { /** * Page number for the current page. */ private int pagenumber; /** * The picture for storing the drawing on. */ private BufferedImage img; /** * Graphics context of the image. */ private Graphics2D graphics; /** * The size of this sheet in pixels. */ private Dimension noteSize; /** * Whether a picture has any lines drawn on it. */ private boolean touched = false; /** * Whether the picture was changed after the last save. A newly created * picture is not unsaved since there is nothing worth saving. */ private boolean unsaved = false; /** * Storage point of the image of this sheet. */ private File imagefile; /** * Wrapper to handle drawing on the image. */ private BufferedImageWrapper imageWrapper; /** * A singleton thread that handles all the writing to disk. */ private static WriteoutThread writethread; /** * Creates an empty note sheet. * * @param noteSize size of the sheet * @param pagenumber given page number * @param infile File to save image in */ public NoteSheet(Dimension noteSize, int pagenumber, File infile) { this.noteSize = noteSize; this.pagenumber = pagenumber; this.imagefile = infile; // If no filename or a filename that does not exist yet is given or the // file is empty (like a newly created temporary file), a new image // needs to be created. if (imagefile == null || !imagefile.exists() || imagefile.length() == 0) { initNewImage(); } // If this branch is reached, then a image file does exist and it is // not empty. This sheet has something drawn on it then. else { touched = true; } } /** * Draws a line onto the sheet. The sheet is then marked as "touched". * * @param line Line to draw. */ public void drawLine(Line2D line) { touched = true; unsaved = true; getImageWrapper().drawLine(line); } /** * Erases a line from the sheet. * * @param line Line to erase. */ public void eraseLine(Line2D line) { touched = true; unsaved = true; getImageWrapper().eraseLine(line); } /** * Getter for the file of the image. */ public File getFile() { return imagefile; } /** * Gets the graphics context of the image. */ private Graphics2D getGraphics() { if (graphics == null) { BufferedImage im = getImg(); if (im == null) { Logger.log(getClass().getName(), Localizer.get("BufferedImage is null.")); } graphics = (Graphics2D)(im.getGraphics()); graphics.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); } return graphics; } /** * Retrieves and initializes the BufferedImageWrapper. * * @return Initialized BufferedImageWrapper. */ private BufferedImageWrapper getImageWrapper() { if (imageWrapper == null) { imageWrapper = new BufferedImageWrapper(getImg()); } return imageWrapper; } /** * Gets the image, loads it from disk id needed. */ public BufferedImage getImg() { if (isSwapped()) { loadFromFile(); } if (img == null) { throw new NullPointerException(Localizer.get( "Could not load image from disk.")); } return img; } /** * Get the sheet's page number. */ public int getPagenumber() { return pagenumber; } /** * Generates a new image and allocates a temporary file if none was set. */ private void initNewImage() { if (imagefile == null) { try { // generate a temporary file imagefile = File.createTempFile( NoteBookProgram.getProgramname() + "-", ".png"); imagefile.setReadable(false, false); imagefile.setWritable(false, false); assert(!imagefile.canRead()); assert(!imagefile.canWrite()); imagefile.setReadable(true, true); imagefile.setWritable(true, true); // Since this is only a temporary file, delete if after using // it. imagefile.deleteOnExit(); } catch (IOException e) { Logger.handleError(Localizer.get( "Could not create a temp file.")); e.printStackTrace(); } } img = new BufferedImage(noteSize.width, noteSize.height, BufferedImage.TYPE_BYTE_GRAY); graphics = getGraphics(); graphics.setColor(Config.getColor("notebook_background_color")); graphics.fillRect(0, 0, noteSize.width, noteSize.height); unsaved = false; } /** * Whether the picture is swapped to disk. To save RAM, the pictures might * be swapped into a temporary file if the user is in another part of the * NoteBook. */ private boolean isSwapped() { return img == null; } /** * Loads the image from file. Everything else is left intact. */ public void loadFromFile() { // If the image was scheduled for writing but not written now, force // the thread to write it. If the file is empty, then the // WriteoutThread did not get a change to write the file yet. Join with // the thread. if (!imagefile.exists() || imagefile.length() == 0L) { Logger.log(getClass().getName(), Localizer.get("Image file does not exist.")); if (writethread.isFileInQueue(imagefile)) { stopWriteoutThread(); } } // If the file still does not exist, it has not been written out. if (!imagefile.exists() || imagefile.length() == 0L) { Logger.log(getClass().getName(), Localizer.get( "Image file does" + " not exist after stopping WriteoutThread." )); initNewImage(); } // If the file exists, load it up. else { try { Logger.log(getClass().getName(), String.format(Localizer.get("Loading %s."), imagefile.getAbsolutePath())); img = ImageIO.read(imagefile); } catch (FileNotFoundException e) { Logger.handleError(Localizer.get( "Could not find the note sheet image.")); e.printStackTrace(); } catch (IOException e) { Logger.handleError(Localizer.get( "Could not read the note sheet image.")); e.printStackTrace(); } // The image *should* be loaded by now. if (img == null) { throw new NullPointerException("Could not load im" + "age from disk."); } // Since it was saved, it has to have some lines on it. touched = true; // Reset the BufferedImageWrapper that has an invalid image resetImageWrapper(); } } /** * Resets the BufferedImageWrapper. */ private void resetImageWrapper() { imageWrapper = null; } /** * Saves the picture to a PNG file. The image is then removed from the * heap. */ public void saveToFile() { Logger.log(getClass().getName(), String.format(Localizer.get("Picture %d is %s and %s."), pagenumber, (touched ? Localizer.get("touched") : Localizer.get("untouched")), (unsaved ? Localizer.get("unsaved") : Localizer.get("saved")) ) ); if (touched && unsaved) { Logger.log(getClass().getName(), String.format( Localizer.get("Scheduling %s for writing."), imagefile.getAbsolutePath())); if (writethread == null || !writethread.isAlive()) { writethread = new WriteoutThread(); } writethread.schedule(new ImageSwapTask(img, imagefile)); } unsaved = false; } public void freeImage() { if (unsaved()) { saveToFile(); } // remove the image from the memory img = null; graphics = null; resetImageWrapper(); } /** * Stops the WriteoutThread and waits for it. This ensures that everything * is written to disk properly. */ public void stopWriteoutThread() { try { if (writethread != null) { writethread.stopAfterLast(); writethread.join(); } } catch (InterruptedException e) { Logger.handleError(Localizer.get( "WriteThread was interrupted.")); e.printStackTrace(); } } /** * Whether this sheet has any lines drawn onto it. */ public boolean touched() { return touched; } /** * Whether this sheet has unsaved changes. */ public boolean unsaved() { return unsaved; } } jscribble-1.7.7/jscribble/notebook/NoteSheetFileFilter.java000066400000000000000000000035211174451527200237640ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook; import java.io.File; import java.io.FilenameFilter; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Filters filenames that belong to NoteSheet from a specific NoteBook. * * @author Martin Ueding */ public class NoteSheetFileFilter implements FilenameFilter { /** * The pattern that every filename is matched against. */ private Pattern p = Pattern.compile("(\\d+)\\.png"); /** * Determines whether a file is accepted or not. A file is accepted if it * starts with the correct prefix and matches the regular expression. * * @param arg0 Ignored. * @param arg1 This is checked. */ @Override public boolean accept(File arg0, String arg1) { String[] nameparts = arg1.split(Pattern.quote(File.separator)); String fileBasename = nameparts[nameparts.length - 1]; Matcher m = p.matcher(fileBasename); if (m.matches()) { // Check whether the number is >= 1, since the file // format says numbers start with 1. int number = Integer.parseInt(m.group(1)); if (number >= 1) { return true; } } return false; } } jscribble-1.7.7/jscribble/notebook/writeoutThread/000077500000000000000000000000001174451527200222665ustar00rootroot00000000000000jscribble-1.7.7/jscribble/notebook/writeoutThread/ImageSwapTask.java000066400000000000000000000032621174451527200256340ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook.writeoutThread; import java.awt.image.BufferedImage; import java.io.File; /** * A set of an image and a filename that is supposed to be loaded or saved to * disk. * * @author Martin Ueding */ public class ImageSwapTask { /** * The image that is to be saved. */ private BufferedImage img; /** * The file the image is to be saved to. */ private File outfile; /** * A task for the WriteoutTread. * * @param img image to save * @param outfile file to save the image to */ public ImageSwapTask(BufferedImage img, File outfile) { this.img = img; this.outfile = outfile; } /** * Returns the image that this task is supposed to save to disk. * * @return the image */ public BufferedImage getImg() { return img; } /** * Returns the file that the image is supposed to be written to. * * @return the file to write to */ public File getOutfile() { return outfile; } } jscribble-1.7.7/jscribble/notebook/writeoutThread/WriteoutThread.java000066400000000000000000000077141174451527200261140ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.notebook.writeoutThread; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.concurrent.LinkedBlockingQueue; import javax.imageio.ImageIO; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; /** * In order to make the user interface faster, the writing of unneeded images * is put into a second thread. That way, the UI does not freeze during the * little IO time. * * @author Martin Ueding */ public class WriteoutThread extends Thread { /** * A queue with the tasks that this thread has to save to disk. */ private LinkedBlockingQueue tasks; /** * This flag stops the thread after the last item in the queue. If not set, * the thread will wait for items in the queue to save. */ private boolean stopAfterLastItem = false; /** * Creates and starts the thread. */ public WriteoutThread() { tasks = new LinkedBlockingQueue(); this.start(); } /** * Works on the queue with tasks. The thread waits for the next task. If * you want to terminate the thread when the queue is empty, you have to * push an empty Task Object into the queue. */ public void run() { ImageSwapTask task; while (!stopAfterLastItem || !tasks.isEmpty()) { try { if (stopAfterLastItem) { task = tasks.poll(); } else { task = tasks.take(); } if (task.getImg() != null) { Logger.log(getClass().getName(), String.format(Localizer.get("Writing %s."), task.getOutfile().getAbsolutePath())); ImageIO.write(task.getImg(), "png", new FileOutputStream(task.getOutfile())); } } catch (FileNotFoundException e) { Logger.handleError(Localizer.get( "Could not find the file to write.")); e.printStackTrace(); } catch (IOException e) { Logger.handleError(Localizer.get( "IO error while saving the note image.")); e.printStackTrace(); } catch (InterruptedException e1) { Logger.handleError(Localizer.get( "Writing thread was interupted.")); e1.printStackTrace(); } } Logger.log(getClass().getName(), Localizer.get("Thread dies.")); } /** * Schedules a new task. * * @param t task to schedule */ public void schedule(ImageSwapTask t) { try { tasks.put(t); } catch (InterruptedException e) { Logger.handleError(Localizer.get( "Interrupted while scheduling a disk write task.")); e.printStackTrace(); } } /** * Stops the thread's daemon mode and lets it die when the queue is empty. */ public void stopAfterLast() { stopAfterLastItem = true; schedule(new ImageSwapTask(null, null)); } /** * Checks for a file in the queue. * * @param imagefile File to check for. * @return Whether given file in in queue. */ public boolean isFileInQueue(File imagefile) { for (ImageSwapTask task : tasks) { // There might be an empty task object to clean out the WriteoutThread. If this is caught, ignore it. if (task.getOutfile() == null) { continue; } if (task.getOutfile().equals(imagefile)) { return true; } } return false; } } jscribble-1.7.7/jscribble/selectionWindow/000077500000000000000000000000001174451527200206115ustar00rootroot00000000000000jscribble-1.7.7/jscribble/selectionWindow/DeleteActionListener.java000066400000000000000000000026251174451527200255270ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Tells the NotebookSelectionWindow to perform an action. * * @author Martin Ueding */ class DeleteActionListener implements ActionListener { /** * Window to notify. */ private NoteBookSelectionWindow window; /** * Creates a new listener. * * @param window Window to relay actions to. */ public DeleteActionListener(NoteBookSelectionWindow window) { super(); this.window = window; } /** * Triggers the deletion of a NoteBook. */ @Override public void actionPerformed(ActionEvent arg0) { window.deleteEvent(); } } jscribble-1.7.7/jscribble/selectionWindow/ListListener.java000066400000000000000000000026241174451527200241010ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; /** * Handles actions from the list that displays all NoteBook. * * @author Martin Ueding */ class ListListener extends MouseAdapter { /** * The window to notify. */ private NoteBookSelectionWindow window; /** * Creates a new listener for the given window. * * @param window Window to notify. */ public ListListener(NoteBookSelectionWindow window) { this.window = window; } /** * Opens a NoteBook on a double click. */ public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { window.openEvent(); } } } jscribble-1.7.7/jscribble/selectionWindow/NewActionListener.java000066400000000000000000000026141174451527200250540ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Tells the NotebookSelectionWindow to perform an action. * * @author Martin Ueding */ class NewActionListener implements ActionListener { /** * Window to notify. */ private NoteBookSelectionWindow window; /** * Creates a new listener. * * @param window Window to relay actions to. */ public NewActionListener(NoteBookSelectionWindow window) { super(); this.window = window; } /** * Triggers the deletion of a NoteBook. */ @Override public void actionPerformed(ActionEvent arg0) { window.newEvent(); } } jscribble-1.7.7/jscribble/selectionWindow/NoteBookSelectionWindow.java000066400000000000000000000211521174451527200262330ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GraphicsDevice; import java.awt.GridLayout; import java.awt.Toolkit; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import jscribble.NoteBookProgram; import jscribble.drawPanel.CommandListener; import jscribble.drawPanel.DrawPanel; import jscribble.drawPanel.MovementListener; import jscribble.drawPanel.NoteBookClosingAdapter; import jscribble.drawPanel.Redrawer; import jscribble.helpers.Localizer; import jscribble.helpers.Config; import jscribble.notebook.NoteBook; /** * A window and launcher for individual NoteBook. It searches the * configuration directory for NoteBook entries and provides a list to open * them. A NoteBook can then be opened in a DrawPanel. * * @author Martin Ueding */ public class NoteBookSelectionWindow { /** * Button to handle creation of a new NoteBook. */ private JButton buttonNew; /** * Button to handle opening of a NoteBook. */ private JButton buttonOpen; /** * Button to handle deletion of a NoteBook. */ private JButton buttonDelete; /** * Button to enter the scribble mode. */ private JButton buttonScribble; /** * Frame to display everything in. */ private JFrame frame; /** * List that holds all the found NoteBook from the user's configuration * directory. */ private LinkedList notebooks; /** * List GUI Element to display the NoteBook items in. */ private JList myList; /** * Panel to display the selected NoteBook. */ private DrawPanel panel; /** * Model for the NoteBook list. */ private DefaultListModel listModel = new DefaultListModel(); private ShutdownHook shutdownHook; /** * Creates a new window to select NoteBook from. It automatically searches * the user's configuration directory for NoteBook configuration files. */ public NoteBookSelectionWindow() { notebooks = findNotebooks(); myList = new JList(listModel); myList.addMouseListener(new ListListener(this)); buttonNew = new JButton(Localizer.get("New")); buttonNew.addActionListener(new NewActionListener(this)); buttonOpen = new JButton(Localizer.get("Open")); buttonOpen.addActionListener(new OpenActionListener(this)); buttonDelete = new JButton(Localizer.get("Delete")); buttonDelete.addActionListener(new DeleteActionListener(this)); buttonScribble = new JButton(Localizer.get("Scribble")); buttonScribble.addActionListener(new ScribbleActionListener(this)); GridLayout gl = new GridLayout(1, 4); JPanel buttonPanel = new JPanel(gl); buttonPanel.add(buttonNew); buttonPanel.add(buttonOpen); buttonPanel.add(buttonDelete); buttonPanel.add(buttonScribble); JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.add(new JScrollPane(myList), BorderLayout.CENTER); mainPanel.add(buttonPanel, BorderLayout.SOUTH); frame = new JFrame(Localizer.get("Select your Notebook")); frame.setSize(new Dimension( Config.getInteger("notebook_selection_window_width"), Config.getInteger("notebook_selection_window_height") )); frame.setLocationRelativeTo(null); frame.add(mainPanel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try { frame.setIconImage(ImageIO.read( getClass().getResourceAsStream( "/artwork/jscribble_gray.png"))); } catch (IOException e) { e.printStackTrace(); } shutdownHook = new ShutdownHook(); Runtime.getRuntime().addShutdownHook(shutdownHook); updateOpenButton(); } /** * Creates a new NoteBook and prompts the user for a name and folder to * save the images in. A config file is automatically created in the config * directory. * * @return the new NoteBook */ private NoteBook createNewNotebook() { String nickname = null; Pattern p = Pattern.compile(Config.getString("notebook_name_validation_pattern")); do { nickname = JOptionPane.showInputDialog(Localizer.get( "Nickname of your Notebook:" + " " + "(please only use characters, numbers, _ and -)")); if (nickname == null) { return null; } Matcher m = p.matcher(nickname); if (m != null && m.matches()) { break; } } while (nickname != null); NoteBook nb = new NoteBook(nickname); return nb; } /** * Deletes the currently selected NoteBook in the list. */ protected void deleteEvent() { int selection = myList.getSelectedIndex(); if (selection >= 0) { NoteBook toDelete = new NoteBook(notebooks.get(selection)); boolean wasdeleted = toDelete.delete(); if (wasdeleted) { listModel.remove(selection); updateOpenButton(); } } } /** * Tries to find a configuration directory for this program. * * @return list of NoteBook */ private LinkedList findNotebooks() { LinkedList notebooks = new LinkedList(); if (NoteBookProgram.getFileDirectory(true).exists()) { File[] folders = NoteBookProgram.getFileDirectory(true).listFiles(); for (File folder : folders) { if (folder.isDirectory()) { String justfound = folder.getName(); notebooks.add(justfound); } } Collections.sort(notebooks); for (String notebook : notebooks) { listModel.addElement(notebook); } } else { NoteBookProgram.getFileDirectory(true).mkdirs(); } return notebooks; } /** * Creates a new NoteBook. */ protected void newEvent() { NoteBook newNoteBook = createNewNotebook(); if (newNoteBook != null) { notebooks.add(newNoteBook.getName()); listModel.addElement(newNoteBook); updateOpenButton(); openNotebook(newNoteBook); } } /** * Opens the currently selected NoteBook in the list. */ protected void openEvent() { int selection = myList.getSelectedIndex(); if (selection >= 0) { openNotebook(new NoteBook(notebooks.get(selection))); } } /** * Opens the given NoteBook in a DrawPanel. * * @param notebook NoteBook to open */ private void openNotebook(final NoteBook notebook) { shutdownHook.add(notebook); final JFrame f = new JFrame(String.format(Localizer.get( "Notebook \"%s\""), notebook.getName())); f.setSize(notebook.getSize()); f.setLocationRelativeTo(null); f.addWindowListener(new NoteBookClosingAdapter(notebook, f)); f.setResizable(false); try { f.setIconImage(ImageIO.read( getClass().getResourceAsStream( "/artwork/jscribble.png"))); } catch (IOException e) { e.printStackTrace(); } panel = new DrawPanel(notebook, f); f.add(panel); f.addKeyListener(new MovementListener(panel)); notebook.gotoLast(); CommandListener cl = new CommandListener(panel); f.addKeyListener(cl); cl.addChangeListener(new Redrawer(panel)); if (Toolkit.getDefaultToolkit().getScreenSize().equals(notebook.getSize())) { GraphicsDevice myDevice = java.awt.GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(); if (myDevice.isFullScreenSupported()) { f.setUndecorated(true); f.setSize(Toolkit.getDefaultToolkit().getScreenSize()); myDevice.setFullScreenWindow(f); f.setLocation(0, 0); } } f.setVisible(true); } /** * Starts a scribble mode NoteBook. */ protected void scribbleEvent() { openNotebook(new NoteBook(null)); } /** * Displays the dialogue. */ public void showDialog() { frame.setVisible(true); } /** * Updates the state of the "open" button. This is needed when the last * NoteBook is deleted or the first one created. */ private void updateOpenButton() { buttonOpen.setEnabled(notebooks.size() > 0); } } jscribble-1.7.7/jscribble/selectionWindow/OpenActionListener.java000066400000000000000000000026171174451527200252270ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Tells the NotebookSelectionWindow to perform an action. * * @author Martin Ueding */ class OpenActionListener implements ActionListener { /** * Window to notify. */ private NoteBookSelectionWindow window; /** * Creates a new listener. * * @param window Window to relay actions to. */ public OpenActionListener(NoteBookSelectionWindow window) { super(); this.window = window; } /** * Triggers the deletion of a NoteBook. */ @Override public void actionPerformed(ActionEvent arg0) { window.openEvent(); } } jscribble-1.7.7/jscribble/selectionWindow/ScribbleActionListener.java000066400000000000000000000026331174451527200260510ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Tells the NotebookSelectionWindow to perform an action. * * @author Martin Ueding */ class ScribbleActionListener implements ActionListener { /** * Window to notify. */ private NoteBookSelectionWindow window; /** * Creates a new listener. * * @param window Window to relay actions to. */ public ScribbleActionListener(NoteBookSelectionWindow window) { super(); this.window = window; } /** * Triggers the deletion of a NoteBook. */ @Override public void actionPerformed(ActionEvent arg0) { window.scribbleEvent(); } } jscribble-1.7.7/jscribble/selectionWindow/ShutdownHook.java000066400000000000000000000037231174451527200241150ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package jscribble.selectionWindow; import java.util.LinkedList; import jscribble.helpers.Localizer; import jscribble.helpers.Logger; import jscribble.notebook.NoteBook; /** * Keeps track of all opened NoteBook and saves them on exit. * * @author Martin Ueding */ public class ShutdownHook extends Thread { /** * All opened NoteBook. */ private LinkedList openedNotebooks; /** * Hooks a new adapter to the closing. */ public ShutdownHook() { super(); openedNotebooks = new LinkedList(); } /** * Adds a new NoteBook to the list this hook has to take care of. * * @param notebook Instance to close on exit. */ public void add(NoteBook notebook) { openedNotebooks.add(notebook); } /** * Saves all opened NoteBook. */ public void run() { Logger.log(getClass().getName(), Localizer.get("Shutting down …")); for (NoteBook notebook : openedNotebooks) { notebook.saveToFiles(); Logger.log( getClass().getName(), String.format( Localizer.get("Closing NoteBook \"%s\"."), notebook.getName() ) ); } Logger.log( getClass().getName(), Localizer.get("Everything saved properly. Thanks for waiting!") ); } } jscribble-1.7.7/l10n/000077500000000000000000000000001174451527200142475ustar00rootroot00000000000000jscribble-1.7.7/l10n/de.po000066400000000000000000000206471174451527200152100ustar00rootroot00000000000000# German translations for jscribble package # German messages for jscribble. # Copyright (c) 2011 Martin Ueding # This file is distributed under the same license as the jscribble package. # Maximilian Kirchner , 2011 # Martin Ueding , 2011 # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-11-16 14:41+0100\n" "PO-Revision-Date: 2011-08-08 20:37+0100\n" "Last-Translator: Martin Ueding \n" "Language-Team: German\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: jscribble/NoteBookProgram.java:81 msgid "Starting up." msgstr "Starte." #: jscribble/NoteBookProgram.java:86 msgid "Entering interactive mode." msgstr "Starte interaktiven Modus." #: jscribble/NoteBookProgram.java:96 msgid "Version: %s" msgstr "" #: jscribble/helpers/Config.java:143 jscribble/helpers/Config.java:166 msgid "Could not find the config file. (This should *not* happen!)" msgstr "" "Konnte keine Konfigurationsdatei finden. (Dies sollte *nicht* passieren!)" #: jscribble/helpers/Config.java:148 jscribble/helpers/Config.java:171 msgid "IO error while reading config file." msgstr "Zugriffsfehler beim Einlesen der Konfigurationsdatei." #: jscribble/helpers/Config.java:194 msgid "There is no default setting for %s." msgstr "Es gibt keine Standardeinstellung für %s." #: jscribble/helpers/Config.java:227 msgid "%c is a valid key for %s." msgstr "%c ist eine gültige Taste für %s." #: jscribble/helpers/Config.java:232 jscribble/helpers/Config.java:254 msgid "%s is a valid key for %s." msgstr "%s ist eine gültige Taste für %s." #: jscribble/selectionWindow/ShutdownHook.java:61 msgid "Shutting down …" msgstr "Fahre herunter …" #: jscribble/selectionWindow/ShutdownHook.java:68 #: jscribble/drawPanel/NoteBookClosingAdapter.java:57 msgid "Closing NoteBook \"%s\"." msgstr "Schließe Notizbuch \"%s\"" #: jscribble/selectionWindow/ShutdownHook.java:76 msgid "Everything saved properly. Thanks for waiting!" msgstr "Alles gespeichert. Danke für's warten!" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:119 msgid "New" msgstr "Neu" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:121 msgid "Open" msgstr "Öffnen" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:123 msgid "Delete" msgstr "Löschen" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:125 msgid "Scribble" msgstr "Kritzeln" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:141 msgid "Select your Notebook" msgstr "Wählen Sie Ihr Notizbuch" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:181 msgid "" "Nickname of your Notebook: (please only use characters, numbers, _ and -)" msgstr "" "Names des Notizbuches: (bitte nur Buchstaben, Zahlen, _ und - benutzen)" #: jscribble/selectionWindow/NoteBookSelectionWindow.java:279 msgid "Notebook \"%s\"" msgstr "Notizbuch \"%s\"" #: jscribble/notebook/writeoutThread/WriteoutThread.java:78 msgid "Writing %s." msgstr "Schreibe %s." #: jscribble/notebook/writeoutThread/WriteoutThread.java:86 msgid "Could not find the file to write." msgstr "Konnte die Datei zum Speichern nicht finden." #: jscribble/notebook/writeoutThread/WriteoutThread.java:91 msgid "IO error while saving the note image." msgstr "IO error während des Speichern des Notizblattbildes." #: jscribble/notebook/writeoutThread/WriteoutThread.java:96 msgid "Writing thread was interupted." msgstr "Schreibprozess wurde unterbrochen." #: jscribble/notebook/writeoutThread/WriteoutThread.java:102 msgid "Thread dies." msgstr "Thread läuft aus." #: jscribble/notebook/writeoutThread/WriteoutThread.java:116 msgid "Interrupted while scheduling a disk write task." msgstr "Beim speichern unterbrochen." #: jscribble/notebook/NoteSheet.java:160 msgid "BufferedImage is null." msgstr "BufferedImage ist null" #: jscribble/notebook/NoteSheet.java:193 msgid "Could not load image from disk." msgstr "Konnte Bilddatei nicht laden" #: jscribble/notebook/NoteSheet.java:231 msgid "Could not create a temp file." msgstr "Konnte keine temp-Datei erstellen" #: jscribble/notebook/NoteSheet.java:266 msgid "Image file does not exist." msgstr "Bilddatei existiert nicht." #: jscribble/notebook/NoteSheet.java:275 msgid "Image file does not exist after stopping WriteoutThread." msgstr "Bilddatei existiert nicht nach Beendigung von WriteoutThread" #: jscribble/notebook/NoteSheet.java:286 msgid "Loading %s." msgstr "Lade %s." #: jscribble/notebook/NoteSheet.java:293 msgid "Could not find the note sheet image." msgstr "Konnte das Notizblattbild nicht finden." #: jscribble/notebook/NoteSheet.java:298 msgid "Could not read the note sheet image." msgstr "Konnte das Notizblattbild nicht laden." #: jscribble/notebook/NoteSheet.java:329 msgid "Picture %d is %s and %s." msgstr "Bilddatei %d ist %s und %s." #: jscribble/notebook/NoteSheet.java:331 msgid "touched" msgstr "berührt" #: jscribble/notebook/NoteSheet.java:332 msgid "untouched" msgstr "unberührt" #: jscribble/notebook/NoteSheet.java:333 msgid "unsaved" msgstr "ungespeichert" #: jscribble/notebook/NoteSheet.java:334 msgid "saved" msgstr "gespeichert" #: jscribble/notebook/NoteSheet.java:339 msgid "Scheduling %s for writing." msgstr "Plane %s zum Speichern ein." #: jscribble/notebook/NoteSheet.java:376 msgid "WriteThread was interrupted." msgstr "WriteThread wurde unterbrochen." #: jscribble/notebook/NoteBook.java:159 msgid "" "Would you like to use your native resolution (%dx%d) instead of the default " "(%dx%d)?" msgstr "" "Wollen Sie Ihre Auflösung (%dx%d) anstelle der Standardauflösung (%dx%d) " "benutzen?" #: jscribble/notebook/NoteBook.java:165 msgid "Default Resolution" msgstr "Standardauflösung" #: jscribble/notebook/NoteBook.java:187 msgid "Do you really want to delete \"%s\"?" msgstr "Möchtest du wirklich \"%s\" löschen?" #: jscribble/notebook/NoteBook.java:188 msgid "Really delete?" msgstr "Wirklich löschen?" #: jscribble/notebook/NoteBook.java:221 msgid "Could not delete folder." msgstr "Konnte den Ordner nicht löschen" #: jscribble/notebook/NoteBook.java:271 msgid "Could not determine path of NoteBook folder." msgstr "Konnte den Pfad des NoteBook-Ordners nicht bestimmen" #: jscribble/notebook/NoteBook.java:437 msgid "Unable to determine resolution from first image in NoteBook." msgstr "Konnte die Auflösung nicht vom ersten Bild des Notizbuches erkennen." #: jscribble/notebook/NoteBook.java:471 msgid "Starting to write out image files." msgstr "Beginne Bild-Datei zu speichern" #: jscribble/notebook/NoteBookCompressor.java:58 msgid "Stop processing %s" msgstr "Stoppe Behandlung von %s." #: jscribble/notebook/NoteBookCompressor.java:74 msgid "Rename %s to %s." msgstr "Benenne %s zu %s um." #: jscribble/drawPanel/DrawPanel.java:82 msgid "show help" msgstr "zeige Hilfe" #: jscribble/drawPanel/DrawPanel.java:86 msgid "hide help" msgstr "verstecke Hilfe" #: jscribble/drawPanel/DrawPanel.java:90 msgid "go forward" msgstr "gehe vorwärts" #: jscribble/drawPanel/DrawPanel.java:94 msgid "go backward" msgstr "gehe zurück" #: jscribble/drawPanel/DrawPanel.java:97 msgid "goto first" msgstr "gehe zum Anfang" #: jscribble/drawPanel/DrawPanel.java:101 msgid "goto last" msgstr "gehe zum Ende" #: jscribble/drawPanel/DrawPanel.java:105 msgid "save & exit" msgstr "speichern & beenden" #: jscribble/drawPanel/DrawPanel.java:109 msgid "increase onion layers" msgstr "erhöhe Zwiebelschichten" #: jscribble/drawPanel/DrawPanel.java:113 msgid "decrease onion layers" msgstr "verringere Zwiebelschichten" #: jscribble/drawPanel/DrawPanel.java:117 msgid "toggle ruling" msgstr "schalte Linierung an/aus" #: jscribble/drawPanel/DrawPanel.java:121 msgid "toggle graph paper" msgstr "schalte Karierung an/aus" #: jscribble/drawPanel/DrawPanel.java:222 msgid "Version %s" msgstr "" #: jscribble/drawPanel/DrawPanel.java:250 msgid "Press h or F1 to get help." msgstr "Drücken Sie h oder F1 für Hilfe." #: jscribble/drawPanel/DrawPanel.java:305 msgid "%d MiB used, %d MiB free, %d MiB total" msgstr "%d MiB benutzt, %d MiB frei, %d MiB total" #: jscribble/drawPanel/DrawPanel.java:326 msgid "Onion Layers: %d" msgstr "Zwiebelschichten: %d" #: jscribble/drawPanel/DrawPanel.java:339 msgid "Page %d/%d" msgstr "Seite %d/%d" #: jscribble/drawPanel/DrawPanel.java:376 msgid "Malformed entry in config file." msgstr "Zugriffsfehler beim Einlesen der Konfigurationsdatei." jscribble-1.7.7/makefile000066400000000000000000000137721174451527200152070ustar00rootroot00000000000000# Copyright © Martin Ueding # This file is part of jscribble. # # jscribble is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 2 of the License, or (at your option) any later # version. # # jscribble 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 General Public License for more details. # # You should have received a copy of the GNU General Public License along with # jscribble. If not, see . ########################################################################### # Variables, File Lists # ########################################################################### # Current version of the program. name=jscribble version:=1.7.7 # Find all the Java files in the source tree and generate a matching list of # class files (targets) from that. alljavafiles:=$(shell find . -name "*.java") allclassfiles:=$(alljavafiles:.java=.class) javafiles:=$(shell find jscribble -name "*.java") classfiles:=$(javafiles:.java=.class) # Java compiler to use. javac:=javac -encoding UTF-8 # Output file names. foldername:=$(name)-$(version) signedjar:=$(name)_$(version).jar tarball:=$(name)_$(version).tar.gz .DELETE_ON_ERROR: ########################################################################### # Named Targets # ########################################################################### # Builds the main program. all: program install_files/completion/jscribble doc # Removes all build files. The changelog and the manual page are not included # since they are hard to come by. clean: $(RM) $(allclassfiles) $(RM) *.jar $(RM) *.mo $(RM) -r javadoc $(RM) .testrun $(RM) doc/jscribble.1 $(RM) doc/keylist.rst $(RM) install_files/completion/jscribble $(RM) jscribble/VersionName.java $(RM) jscribble/default_config.properties $(RM) jscribble_*.*.tar.gz $(RM) l10n/de.po~ $(RM) l10n/jscribble.pot $(RM) l10n/jscribble_*.properties doc: doc/jscribble.1 # Extracts all javadoc comments from the source codes and generates HTML pages # with that information. doc-dev: javadoc/index.html # Creates the template for translators. i18n: l10n/jscribble.pot # Installs the jar file and the launcher script into DESTDIR. install: jscribble.jar install_files/completion/jscribble mkdir -p "$(DESTDIR)/usr/share/jscribble" install -m 644 jscribble.jar "$(DESTDIR)/usr/share/jscribble/" mkdir -p "$(DESTDIR)/usr/bin" install -m 755 install_files/jscribble "$(DESTDIR)/usr/bin/" mkdir -p "$(DESTDIR)/etc/bash_completion.d/" install -m 644 install_files/completion/jscribble "$(DESTDIR)/etc/bash_completion.d/" mkdir -p "$(DESTDIR)/usr/share/man/man1/" install -m 644 doc/jscribble.1 "$(DESTDIR)/usr/share/man/man1/" gzip "$(DESTDIR)/usr/share/man/man1/jscribble.1" program: jscribble/default_config.properties jscribble.jar # Creates a jar file which contains the version name, ready for Java Web Start # deployment. signed-jar: $(signedjar) # Creates a tarball which contains all the source code. The changelog and the # manual page are included, although they are build files, since the tools # needed for that are not ubiquitous. tarball: $(tarball) # Runs all available unit tests. test: program $(allclassfiles) junit -text tests.JscribbleTestSuite ########################################################################### # Explicit Rules # ########################################################################### # Signs the jar file with Martin's key. $(signedjar): jscribble.jar jarsigner $< mu cp $< $@ # Put all the files that are tracked in git in a tarball and amend the hard to # come by build files. $(tarball): surrogates.tar .git/HEAD $(RM) $@ git archive --prefix=$(foldername)/ HEAD > $(basename $@ .gz) tar -Af $(basename $@ .gz) $< gzip $(basename $@ .gz) # Creates a changelog file with the information in the git tags. CHANGELOG: .git/HEAD git-changelog > CHANGELOG # Creates the roff manual page. doc/jscribble.1: doc/jscribble.1.rst doc/keylist.rst rst2man $< $@ # Inserts the values and comments from the default config into the manual page. doc/keylist.rst: doc/keylist.php jscribble/default_config.properties php $< > $@ install_files/completion/jscribble: install_files/completion/generate_completion config/config.js $< > $@ # Create standard javadoc. javadoc/index.html: $(alljavafiles) javadoc -d javadoc $^ jscribble/default_config.properties: config/generate_properties config/config.js $< > $@ # Generate a Java file that tells the program its version number. jscribble/VersionName.java: makefile ./generate_version_class $(version) > $@ # Put all the class files into the jar. jscribble.jar: jscribble/VersionName.class $(classfiles) l10n/jscribble_de.properties jscribble/default_config.properties artwork/jscribble.png artwork/jscribble_gray.png jar -cfm $@ manifest.txt $^ # Convert the object into a Java compatible file. l10n/jscribble_de.properties: l10n/de.po msgcat --properties-output -o $@ $< # Extract the strings from all Java source files. l10n/jscribble.pot: $(alljavafiles) xgettext -o $@ -k -k"Localizer.get" $^ --from-code=utf-8 # Tar achive which contains files which cannot be generated with out the git # repository. surrogates.tar: CHANGELOG tar -cf $@ --transform 's,^,/$(foldername)/,' $^ ########################################################################### # Implicit Rules # ########################################################################### # How to compile regular Java files. jscribble/%.class: jscribble/%.java $(javac) $< # How to compile unit tests. tests/%.class: tests/%.java $(javac) -classpath /usr/share/java/junit.jar -sourcepath .:jscribble $< jscribble-1.7.7/manifest.txt000066400000000000000000000000461174451527200160440ustar00rootroot00000000000000Main-Class: jscribble.NoteBookProgram jscribble-1.7.7/precommit000077500000000000000000000001511174451527200154170ustar00rootroot00000000000000#!/bin/bash # Copyright (c) 2012 Martin Ueding set -e set -u astyle -r '*.java' jscribble-1.7.7/tests/000077500000000000000000000000001174451527200146375ustar00rootroot00000000000000jscribble-1.7.7/tests/JscribbleTestSuite.java000066400000000000000000000035651174451527200212640ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests; import junit.framework.Test; import junit.framework.TestSuite; import tests.jscribble.VersionNameTest; import tests.jscribble.drawPanel.HelpItemTest; import tests.jscribble.helpers.FileComparatorTest; import tests.jscribble.notebook.NoteBookCompressorTest; import tests.jscribble.notebook.NoteBookTest; import tests.jscribble.notebook.NoteSheetFileFilterTest; import tests.jscribble.notebook.NoteSheetTest; import tests.jscribble.notebook.WriteoutThreadTest; public class JscribbleTestSuite { public static Test suite() { TestSuite suite = new TestSuite(); // TODO Add test for BufferedImageWrapper. // TODO Add test for InvalidationThread. // TODO Add test for Localizer. // TODO Add test for Logger. // TODO Add test for SettingsWrapper. suite.addTestSuite(FileComparatorTest.class); suite.addTestSuite(HelpItemTest.class); suite.addTestSuite(NoteBookCompressorTest.class); suite.addTestSuite(NoteBookTest.class); suite.addTestSuite(NoteSheetFileFilterTest.class); suite.addTestSuite(NoteSheetTest.class); suite.addTestSuite(VersionNameTest.class); suite.addTestSuite(WriteoutThreadTest.class); return suite; } } jscribble-1.7.7/tests/jscribble/000077500000000000000000000000001174451527200165765ustar00rootroot00000000000000jscribble-1.7.7/tests/jscribble/VersionNameTest.java000066400000000000000000000006411174451527200225300ustar00rootroot00000000000000// Copyright (c) 2011 Martin Ueding package tests.jscribble; import java.util.regex.Pattern; import jscribble.VersionName; import junit.framework.TestCase; public class VersionNameTest extends TestCase { public VersionNameTest() { super(); } public void testVersionName() { Pattern p = Pattern.compile("\\d+(\\.\\d+)+"); assertTrue(p.matcher(VersionName.version).matches()); } }jscribble-1.7.7/tests/jscribble/drawPanel/000077500000000000000000000000001174451527200205135ustar00rootroot00000000000000jscribble-1.7.7/tests/jscribble/drawPanel/HelpItemTest.java000066400000000000000000000041011174451527200237210ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.drawPanel; import java.awt.event.KeyEvent; import jscribble.drawPanel.HelpItem; import junit.framework.TestCase; public class HelpItemTest extends TestCase { public void testChar() { HelpItem hi = new HelpItem("a", "text"); assertEquals("A", hi.key); } public void testCharArray() { HelpItem hi = new HelpItem("a,b", "text"); assertEquals("A, B", hi.key); } public void testKeyCode() { HelpItem hi = new HelpItem(String.valueOf(KeyEvent.VK_ENTER), "text"); assertEquals(KeyEvent.getKeyText(KeyEvent.VK_ENTER), hi.key); } public void testKeyCodeArray() { HelpItem hi = new HelpItem(String.valueOf(KeyEvent.VK_ENTER) + ",0" + String.valueOf(KeyEvent.VK_BACK_SPACE), "text"); assertEquals(KeyEvent.getKeyText(KeyEvent.VK_ENTER) + ", " + KeyEvent.getKeyText(KeyEvent.VK_BACK_SPACE), hi.key); } public void testOneDigitKeyCodeWithoutPadding() { HelpItem hi = new HelpItem(String.valueOf(KeyEvent.VK_BACK_SPACE), "text"); assertFalse(KeyEvent.getKeyText(KeyEvent.VK_BACK_SPACE).equals(hi.key)); } public void testOneDigitKeyCodeWithPadding() { HelpItem hi = new HelpItem("0" + String.valueOf(KeyEvent.VK_BACK_SPACE), "text"); assertEquals(KeyEvent.getKeyText(KeyEvent.VK_BACK_SPACE), hi.key); } public void testText() { HelpItem hi = new HelpItem("a", "text"); assertEquals("text", hi.helptext); } } jscribble-1.7.7/tests/jscribble/helpers/000077500000000000000000000000001174451527200202405ustar00rootroot00000000000000jscribble-1.7.7/tests/jscribble/helpers/FileComparatorTest.java000066400000000000000000000025161174451527200246560ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.helpers; import java.io.File; import jscribble.helpers.FileComparator; import junit.framework.TestCase; public class FileComparatorTest extends TestCase { private FileComparator fc = new FileComparator(); public void testEqual() { File a = new File("test"); File b = new File("test"); assertEquals(0, fc.compare(a, b)); } public void testGreater() { File a = new File("foobar"); File b = new File("test"); assertTrue(fc.compare(a, b) < 0); } public void testLess() { File a = new File("foobar"); File b = new File("test"); assertTrue(fc.compare(b, a) > 0); } } jscribble-1.7.7/tests/jscribble/notebook/000077500000000000000000000000001174451527200204165ustar00rootroot00000000000000jscribble-1.7.7/tests/jscribble/notebook/NoteBookCompressorTest.java000066400000000000000000000047761174451527200257340ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.notebook; import java.io.File; import java.io.IOException; import java.util.Arrays; import jscribble.helpers.FileComparator; import jscribble.notebook.NoteBookCompressor; import jscribble.notebook.NoteSheetFileFilter; import junit.framework.TestCase; /** * Exercises the NoteBookCompressor. * * @author Martin Ueding */ public class NoteBookCompressorTest extends TestCase { public void testCompression() { File folder; try { folder = File.createTempFile("jscribble", ""); String tempname = folder.getAbsolutePath(); folder.delete(); folder = new File(tempname); folder.mkdirs(); folder.deleteOnExit(); // Create some files which are not in direct order. File[] files = { new File(tempname + File.separator + "000001.png"), new File(tempname + File.separator + "000003.png"), new File(tempname + File.separator + "000004.png"), new File(tempname + File.separator + "000005.png"), new File(tempname + File.separator + "000010.png"), new File(tempname + File.separator + "000017.png"), }; for (File file : files) { file.createNewFile(); file.deleteOnExit(); } File[] originalFiles = folder.listFiles(new NoteSheetFileFilter()); assertEquals(files.length, originalFiles.length); NoteBookCompressor nbc = new NoteBookCompressor(folder); nbc.compress(); File[] renamedFiles = folder.listFiles(new NoteSheetFileFilter()); assertEquals(files.length, renamedFiles.length); Arrays.sort(renamedFiles, new FileComparator()); assertEquals(files.length, renamedFiles.length); for (int i = 0; i < renamedFiles.length; i++) { assertEquals(String.format("%06d.png", i + 1), renamedFiles[i].getName()); } } catch (IOException e) { e.printStackTrace(); } } } jscribble-1.7.7/tests/jscribble/notebook/NoteBookTest.java000066400000000000000000000304341174451527200236450ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.notebook; import java.awt.Dimension; import java.awt.geom.Line2D; import java.io.File; import java.io.IOException; import java.util.UUID; import jscribble.helpers.Logger; import jscribble.notebook.NoteBook; import jscribble.notebook.NoteSheet; import junit.framework.TestCase; /** * Exercises the NoteBook. * * @author Martin Ueding */ public class NoteBookTest extends TestCase { public NoteBookTest() { super(); } /** * Generates a temporary NoteBook that has a name. * * @return Named temporary NoteBook. */ private NoteBook createNamedTempNoteBook() { return new NoteBook(UUID.randomUUID().toString(), new Dimension(300, 300)); } /** * Creates a NoteBook stored in a temporary folder np name. * * @return Unnamed temporary NoteBook. */ private NoteBook createTempNoteBook() { return new NoteBook(null, new Dimension(300, 300)); } /** * Creates a NoteBook, draws on the page, flips and does not save. Then * checks whether the Image was saved. */ public void testAutomaticSaveOnPageFlipForward() { NoteBook b = createNamedTempNoteBook(); assertEquals(0, b.getSheetCount()); assertNotNull(b); String name = b.getName(); assertNotNull(name); int previousColor = b.getCurrentSheet().getImg().getRGB(100, 100); b.drawLine(new Line2D.Float(100, 100, 100, 200)); assertFalse(previousColor == b.getCurrentSheet().getImg().getRGB(100, 100)); assertEquals(1, b.getSheetCount()); assertEquals(1, b.getCurrentSheet().getPagenumber()); b.goForward(); assertEquals(2, b.getCurrentSheet().getPagenumber()); b.testing_finalize(); b = null; assertNull(b); NoteBook c = new NoteBook(name); assertNotNull(c); assertEquals(1, c.getSheetCount()); assertNotNull(c.getCurrentSheet()); assertNotNull(c.getCurrentSheet().getImg()); c.gotoFirst(); assertFalse(c.getCurrentSheet().getImg().getRGB(100, 100) == previousColor); c.deleteSure(); } /** * Creates a NoteBook, draws on the page, flips, draws and flips back. * Then the NoteBook is closed without saving and tested whether the data * is still there. */ public void testAutomaticSaveOnPageFlipBackwards() { // Create a new NoteBook. NoteBook b = createNamedTempNoteBook(); assertEquals(0, b.getSheetCount()); assertNotNull(b); String name = b.getName(); assertNotNull(name); // Determine foreground and background color with a line. int backgroundColor = b.getCurrentSheet().getImg().getRGB(100, 100); b.drawLine(new Line2D.Float(100, 100, 100, 200)); int foregroundColor = b.getCurrentSheet().getImg().getRGB(100, 100); assertFalse(backgroundColor == foregroundColor); assertEquals(foregroundColor, b.getCurrentSheet().getImg().getRGB(100, 100)); // Check page numbers. assertEquals(1, b.getSheetCount()); assertEquals(1, b.getCurrentSheet().getPagenumber()); b.goForward(); assertEquals(2, b.getCurrentSheet().getPagenumber()); // Draw another line somewhere else. assertEquals(backgroundColor, b.getCurrentSheet().getImg().getRGB(50, 50)); b.drawLine(new Line2D.Float(50, 50, 50, 50)); assertEquals(foregroundColor, b.getCurrentSheet().getImg().getRGB(50, 50)); // Go back. assertEquals(2, b.getSheetCount()); assertEquals(2, b.getCurrentSheet().getPagenumber()); b.goBackwards(); assertEquals(1, b.getCurrentSheet().getPagenumber()); b.testing_finalize(); // Get rid of the NoteBook. b = null; assertNull(b); // Load the NoteBook from disk. NoteBook c = new NoteBook(name); assertNotNull(c); assertEquals(2, c.getSheetCount()); assertNotNull(c.getCurrentSheet()); assertNotNull(c.getCurrentSheet().getImg()); // Check the page number. c.gotoLast(); assertEquals(2, c.getCurrentSheet().getPagenumber()); // Check whether there is only the line from the second sheet. assertEquals(foregroundColor, c.getCurrentSheet().getImg().getRGB(50, 50)); assertEquals(backgroundColor, c.getCurrentSheet().getImg().getRGB(100, 100)); c.deleteSure(); } /** * There was an error in a previous version that a newly created sheet * which is still empty will be saved if you go back. When you go forward * again, the program tries to load the image which does not exist. This * test should cover this case. */ public void testBackWithEmptyLastSheet() { NoteBook nb = createTempNoteBook(); int numAdvance = 15; // Advance several pages. for (int i = 0; i < numAdvance; i++) { nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.goForward(); } // Go back. for (int i = numAdvance; i > 0; i--) { nb.goBackwards(); nb.getCurrentSheet().getImg(); } numAdvance += 5; // Advance several pages. for (int i = 0; i < numAdvance; i++) { nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.goForward(); } // There just should not be any error, that is it. } /** * Tests whether the current sheet of a new NoteBook is not null. */ public void testCurrentSheet() { NoteBook nb = createTempNoteBook(); assertNotNull(nb.getCurrentSheet()); } /** * Creates a NoteBook with many pages and deletes one of them. The NoteBook * is then reloaded from the configuration file. The NoteBook should now * have one page less than before. */ public void testDeletionOfPictureFile() { NoteBook nb = createNamedTempNoteBook(); File[] filenames = new File[20]; nb.drawLine(new Line2D.Float(0, 0, 0, 0)); for (int i = 0; i < filenames.length; i++) { nb.goForward(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); filenames[i] = nb.getCurrentSheet().getFile(); } nb.saveToFiles(); int oldSheetCount = nb.getSheetCount(); // delete a file from the notebook for (File file : filenames) { assertTrue(String.format("File %s should exist.", file.getAbsolutePath()), file.exists()); } filenames[3].delete(); assertFalse(filenames[3].exists()); NoteBook reloaded = new NoteBook(nb.getName()); assertEquals(oldSheetCount - 1, reloaded.getSheetCount()); Logger.log(getClass().getName(), "Trying to delete test files."); for (File file : filenames) { file.delete(); } nb.deleteSure(); } /** * Tests whether an newly created NoteBook has zero sheets in it, even if * you get the first (untouched) page. */ public void testEmptySheetCount() { NoteBook nb = createTempNoteBook(); assertEquals(0, nb.getSheetCount()); nb.getCurrentSheet(); assertEquals(0, nb.getSheetCount()); } /** * Tests the forward and backward functions in the NoteBook. */ public void testGoBackwards() { NoteBook nb = createTempNoteBook(); // Try going back although the notebook is already at the first page. assertEquals(1, nb.getCurrentSheet().getPagenumber()); nb.goBackwards(); assertEquals(1, nb.getCurrentSheet().getPagenumber()); // Go one page forward. nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.goForward(); assertEquals(2, nb.getCurrentSheet().getPagenumber()); // Try to go once more, which should not work nb.goForward(); assertEquals(2, nb.getCurrentSheet().getPagenumber()); // Go back to the start. nb.goBackwards(); assertEquals(1, nb.getCurrentSheet().getPagenumber()); int numAdvance = 30; // Advance several pages. for (int i = 0; i < numAdvance; i++) { nb.goForward(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); assertEquals(i + 2, nb.getCurrentSheet().getPagenumber()); } // Go back again for (int i = numAdvance; i > 0; i--) { nb.goBackwards(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); assertEquals(Math.max(1, i), nb.getCurrentSheet().getPagenumber()); } } /** * Tests whether going to first and lasts works. */ public void testGotoLast() { NoteBook nb = createTempNoteBook(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); int numAdvance = 30; // Advance several pages. for (int i = 0; i < numAdvance; i++) { nb.goForward(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); assertEquals(i + 2, nb.getCurrentSheet().getPagenumber()); } nb.gotoFirst(); assertEquals(1, nb.getCurrentSheet().getPagenumber()); nb.gotoLast(); assertEquals(nb.getSheetCount(), nb.getCurrentSheet().getPagenumber()); } /** * Tests whether a reloaded NoteBook is the same as the saved one. */ public void testLoadFromConfig() { NoteBook nb = createNamedTempNoteBook(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.saveToFiles(); NoteBook reloaded = new NoteBook(nb.getName()); assertEquals(nb.getName(), reloaded.getName()); nb.gotoFirst(); reloaded.gotoFirst(); try { assertEquals(nb.getCurrentSheet().getFile().getCanonicalPath(), reloaded.getCurrentSheet().getFile().getCanonicalPath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } assertEquals(nb.getSheetCount(), reloaded.getSheetCount()); nb.deleteSure(); } /** * Tests whether the page number advances when you go a page forward. */ public void testPageNumber() { NoteBook nb = createTempNoteBook(); assertEquals(1, nb.getCurrentSheet().getPagenumber()); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); assertEquals(1, nb.getCurrentSheet().getPagenumber()); nb.goForward(); assertEquals(2, nb.getCurrentSheet().getPagenumber()); } /** * Tests whether saving the NoteBook actually creates image files. This * test draws a line onto the first page. */ public void testSavingAfterDrawing() { NoteBook nb = createTempNoteBook(); NoteSheet current = nb.getCurrentSheet(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.saveToFiles(); assertTrue(current.getFile().exists()); assertNotSame(0, current.getFile().length()); } /** * Tests whether saving the NoteBook actually creates image files. This * test draws a line and advances one page. It should only save one file. */ public void testSavingAfterDrawingAndAdvance() { NoteBook nb = createTempNoteBook(); NoteSheet current = nb.getCurrentSheet(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.goForward(); nb.saveToFiles(); assertTrue(current.getFile().exists()); assertNotSame(0, current.getFile().length()); current = nb.getCurrentSheet(); assertTrue(current.getFile().exists()); assertNotSame(0, current.getFile().length()); } /** * Tests whether saving a new NoteBook without any lines creates no files. */ public void testSavingAfterNew() { NoteBook nb = createTempNoteBook(); NoteSheet current = nb.getCurrentSheet(); nb.saveToFiles(); assertTrue(current.getFile().exists()); assertEquals(String.format("File %s should be empty.", current.getFile().getAbsolutePath()), 0, current.getFile().length()); } /** * Tests whether saving the NoteBook actually creates image files. This * test draws a line on page one and two and checks whether two pages are * created. */ public void testSavingAfterTwoDrawingAndAdvance() { NoteBook nb = createTempNoteBook(); NoteSheet current = nb.getCurrentSheet(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.goForward(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); nb.saveToFiles(); assertTrue(current.getFile().exists()); assertNotSame(0, current.getFile().length()); current = nb.getCurrentSheet(); assertTrue(current.getFile().exists()); assertNotSame(0, current.getFile().length()); } /** * Checks whether a new NoteBook with a line on the first page has one * page. */ public void testSheetCountAfterFirstLine() { NoteBook nb = createTempNoteBook(); nb.drawLine(new Line2D.Float(0, 0, 0, 0)); assertEquals(1, nb.getSheetCount()); } /** * Tests whether a new NoteBook has an untouched first page. */ public void testUntouchedFirstPage() { NoteBook nb = createTempNoteBook(); assertFalse(nb.getCurrentSheet().touched()); } } jscribble-1.7.7/tests/jscribble/notebook/NoteSheetFileFilterTest.java000066400000000000000000000036531174451527200257740ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.notebook; import jscribble.notebook.NoteSheetFileFilter; import junit.framework.TestCase; public class NoteSheetFileFilterTest extends TestCase { private NoteSheetFileFilter filter = new NoteSheetFileFilter(); public void testLetters() { assertFalse(filter.accept(null, "asdfgh.png")); } public void testZero() { assertFalse(filter.accept(null, "000000.png")); } public void testLongNumber() { assertTrue(filter.accept(null, "1234567890.png")); } public void testAlphanumeric() { assertFalse(filter.accept(null, "asd123.png")); } public void testNegativeNumber() { assertFalse(filter.accept(null, "-123456.png")); } public void testShort() { assertTrue(filter.accept(null, "1.png")); } public void testSimple() { assertTrue(filter.accept(null, "000001.png")); } public void testSpaces() { assertFalse(filter.accept(null, " 000001.png")); assertFalse(filter.accept(null, "000001.png ")); } public void testWrongSuffix() { assertFalse(filter.accept(null, "00000.jpg")); assertFalse(filter.accept(null, "000001.jpg")); } public void testNoSuffix() { assertFalse(filter.accept(null, "00000")); assertFalse(filter.accept(null, "000001")); } } jscribble-1.7.7/tests/jscribble/notebook/NoteSheetTest.java000066400000000000000000000061561174451527200240270ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.notebook; import java.awt.Dimension; import java.awt.geom.Line2D; import java.io.File; import java.io.IOException; import jscribble.notebook.NoteSheet; import junit.framework.TestCase; /** * Exercises the NoteSheet. * * @author Martin Ueding */ public class NoteSheetTest extends TestCase { public NoteSheetTest() { super(); } /** * Generates a temporary NoteSheet for testing. */ private NoteSheet getTempNoteSheet() { return new NoteSheet(new Dimension(1024, 600), 0, null); } /** * Tests whether drawing a line causes a change in color in the image. */ public void testDrawing() { NoteSheet n = getTempNoteSheet(); assertNotNull(n); assertNotNull(n.getImg()); int previousColor = n.getImg().getRGB(100, 100); n.drawLine(new Line2D.Float(100, 100, 100, 200)); assertFalse(n.getImg().getRGB(100, 100) == previousColor); } /** * Tests whether a line gets erased. */ public void testErasing() { NoteSheet n = getTempNoteSheet(); assertNotNull(n); assertNotNull(n.getImg()); int previousColor = n.getImg().getRGB(100, 100); n.drawLine(new Line2D.Float(100, 100, 100, 200)); int rgbarray[] = n.getImg().getRGB(100, 100, 1, 1, null, 0, 1); assertTrue(rgbarray.length > 0); assertFalse(rgbarray[0] == previousColor); // Erase and make sure it was is the background color. n.eraseLine(new Line2D.Float(100, 100, 100, 200)); int newrgbarray[] = n.getImg().getRGB(100, 100, 1, 1, null, 0, 1); assertTrue(newrgbarray[0] == previousColor); } /** * Tests whether a new NoteSheet is untouched and does not need any saving. */ public void testTouched() { NoteSheet n = getTempNoteSheet(); assertFalse(n.touched()); assertFalse(n.unsaved()); n.drawLine(new Line2D.Float(0, 0, 0, 0)); assertTrue(n.touched()); assertTrue(n.unsaved()); } /** * Creates a single NoteSheet with an existing temporary file and tests * whether it is untouched and does not need any saving. */ public void testTouchedWithEmptyTempfile() { try { File tempfile = File.createTempFile("JUnit-", ".png"); tempfile.createNewFile(); NoteSheet n = new NoteSheet(new Dimension(100, 100), 0, tempfile); assertFalse(n.unsaved()); assertFalse(n.touched()); n.drawLine(new Line2D.Float(0, 0, 0, 0)); assertTrue(n.touched()); assertTrue(n.unsaved()); } catch (IOException e) { e.printStackTrace(); } } } jscribble-1.7.7/tests/jscribble/notebook/WriteoutThreadTest.java000066400000000000000000000037631174451527200251040ustar00rootroot00000000000000// Copyright © 2011 Martin Ueding /* * This file is part of jscribble. * * jscribble is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your option) * any later version. * * jscribble 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * jscribble. If not, see . */ package tests.jscribble.notebook; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import jscribble.notebook.writeoutThread.ImageSwapTask; import jscribble.notebook.writeoutThread.WriteoutThread; import junit.framework.TestCase; /** * Exercises the WriteoutThread. * * @author Martin Ueding */ public class WriteoutThreadTest extends TestCase { public WriteoutThreadTest() { super(); } /** * Schedules a single task and tests whether it is written to disk. */ public void testSingleWriteout() { WriteoutThread wt = new WriteoutThread(); File outfile = null; try { outfile = File.createTempFile("JUnit-testSingleWriteout-", ".png"); } catch (IOException e1) { e1.printStackTrace(); } assertNotNull(outfile); assertTrue(outfile.exists()); assertEquals(0L, outfile.length()); wt.schedule(new ImageSwapTask(new BufferedImage(10, 10, BufferedImage.TYPE_BYTE_GRAY), outfile)); assertTrue(wt.isAlive()); wt.stopAfterLast(); try { wt.join(); } catch (InterruptedException e) { e.printStackTrace(); } assertFalse(wt.isAlive()); assertTrue(outfile.exists()); assertTrue(outfile.length() > 0); outfile.delete(); assertFalse(outfile.exists()); } } /jscribble-1.7.7/CHANGELOG0000644000175000017500000000741311744515313012613 0ustar mumuv1.7.7 * Be more careful before using JOptionPane. v1.7.6 * Add pre-commit script. * Add readme file with installation instructions. * Convert man page to reST. * Prevent crash in headless mode when logging a text. * Use XDG standard directories, offer migration (.config, .local/share). * Use canonical path in test. - Remove Doxygen file and makefile target. - Rename finalize method, not deprecated any more. v1.7.5 * Clean up makefile, exit on errors. - Remove unused links from manual page. v1.7.4 * Use pandoc instead of ronn. v1.7.3 * Reoder manual page. v1.7.2 * Faster startup. v1.7.1 * Document file format. * Fix FileFilter not to match 000000.png. - Update tests for FileFilter. v1.7 * Filename numbering compression. (opt-in) v1.6.6 * High resolution icons. - License in auxilary files. v1.6.5 * Fix permissions of files via "make install". v1.6.4 * Do not depend on ronn at this time for "make install". v1.6.3 * Install manual page with "make install". - Cleaner jscribble.pot. v1.6.2 * Reorganisation of files in source tree (new artwork, config and l10n directory). - Fix spelling and grammar mistakes in manual page. v1.6.1 * Fix prefix of CHANGELOG in tarball v1.6 * Enable overriding of config keys on the command line. * Add bash completion for config keys. v1.5.5 * Automatic save on every page change to prevent data loss. - Gray logo for selection window. - Unified test suite. - Fix race condition in WriteoutThread queue checking. v1.5.4 * Save everything, even if program is interrupted. * Close notebook on "q" key. - Show assigned key from the (user) config file in help screen. v1.5.3 * Add Java Webstart. * Create extensive manual page. - Fix drawing dots (broken since v1.5.2). - Allow movements with extra mouse buttons (enable in config). - Add config option to disable eraser. v1.5.2 * Create more config options, e. g. mouse buttons and keyboard keys. * Repaint ruling and onion layers after erasing. v1.5.1 * Create config for most settings, overwriteable by user. * Optional memory usage display. v1.5 * Support for any screen size. v1.4 * Add ruling and graph paper. * Add splash screen for help. v1.3 * Add eraser on right click. - Sort notebooks in the selection window. v1.2.2 * Multiple layers in onion mode. - Add window icon in notebook view too. v1.2.1 * Use git describe version number. v1.1.1 * Add "make install" target. v1.1 * Add German localization. * Add scroll panels for touch only devices. * Use a config file. - Add -v flag to activate log messages. - Add logo to main window. - Add simple man page. - Delete the temporary files after the programs exists. - Disallow to resize the window. - Fix null pointer exception when clicking cancel on new dialog. - Fix temp file permissions. v1.0.1 * Add desktop entry. * Add launcher script * Add logo for the program. v1.0 * Do not close application after closing notebook. * Drastically simplify file structure, tests are still buggy. * Open notebook on double click. * Save all notebooks that are opened when closing the opening dialog. - Add version flag to CLI. - Bug fix blank page reloading error. - Fix case where going back and forth faster than WriteoutThread could handle writing. v0.3 * Add default directory option. * Add delete function. * Add help message. * Add more keys to control program. * Draw only with primary mouse button. - Ask user when the default directory is not valid any more. - Display page count in overview. v0.2.1 * Add option to write out loading and writing. v0.1 * Initial release.