diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-06-07 23:30:05 +0900 |
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-06-07 23:30:05 +0900 |
| commit | 17b259df9cb6b28779d4881b2b6c805ee2e48eea (patch) | |
| tree | 5ed61937459cb7081089111b0242c01ec178f1f3 /reader | |
| parent | 1cba8bce178eb2d6719c6f7f21e2c9352c5513a6 (diff) | |
| download | tde-ebook-reader-17b259df9cb6b28779d4881b2b6c805ee2e48eea.tar.gz tde-ebook-reader-17b259df9cb6b28779d4881b2b6c805ee2e48eea.zip | |
Rename to tde-ebook-reader
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'reader')
722 files changed, 75832 insertions, 0 deletions
diff --git a/reader/LICENSE b/reader/LICENSE new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/reader/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <signature of Ty Coon>, 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 Library General +Public License instead of this License. diff --git a/reader/data/default/config.desktop.xml b/reader/data/default/config.desktop.xml new file mode 100644 index 0000000..670a4eb --- /dev/null +++ b/reader/data/default/config.desktop.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<config> + <group name="Style"> + <option name="Base:fontFamily" value="Georgia"/> + <option name="Base:fontSize" value="16"/> + </group> + <group name="Scrollings"> + <option name="Delay" value="0"/> + </group> + <group name="Options"> + <option name="LeftMargin" value="50"/> + <option name="RightMargin" value="50"/> + <option name="KeyDelay" value="0"/> + <option name="BookPath" value="~/Books:~/FBooks"/> + <option name="DownloadDirectory" value="~/Books"/> + </group> +</config> diff --git a/reader/data/default/external.desktop.xml b/reader/data/default/external.desktop.xml new file mode 100644 index 0000000..424e676 --- /dev/null +++ b/reader/data/default/external.desktop.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ExternalPrograms> + <section name="Web Browser"> + <program name="%browser" protocol="execute"> + <action name="openLink" command="%command"/> + <option name="command" defaultValue="sensible-browser %1 &"/> + </program> + </section> +</ExternalPrograms> diff --git a/reader/data/default/fullscreen_toolbar.desktop.xml b/reader/data/default/fullscreen_toolbar.desktop.xml new file mode 100644 index 0000000..72da2c2 --- /dev/null +++ b/reader/data/default/fullscreen_toolbar.desktop.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<toolbar> +</toolbar> diff --git a/reader/data/default/keymap.desktop.xml b/reader/data/default/keymap.desktop.xml new file mode 100644 index 0000000..b795bd8 --- /dev/null +++ b/reader/data/default/keymap.desktop.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<keymap> + <binding key="<L>" action="showLibrary"/> + <binding key="<W>" action="showNetLibrary"/> + <binding key="<O>" action="preferences"/> + <binding key="<LeftArrow>" action="undo"/> + <binding key="<RightArrow>" action="redo"/> + <binding key="<C>" action="toc"/> + <binding key="<Ctrl>+<F>" action="search"/> + <binding key="<F>" action="search"/> + <binding key="<P>" action="findPrevious"/> + <binding key="<F3>" action="findNext"/> + <binding key="<N>" action="findNext"/> + <binding key="<PageDown>" action="pageForward"/> + <binding key="<PageUp>" action="pageBackward"/> + <binding key="<DownArrow>" action="lineForward"/> + <binding key="<UpArrow>" action="lineBackward"/> + <binding key="<MouseScrollDown>" action="mouseScrollForward"/> + <binding key="<MouseScrollUp>" action="mouseScrollBackward"/> + <binding key="<Ctrl>+<Home>" action="gotoHome"/> + <binding key="<Home>" action="gotoSectionStart"/> + <binding key="<End>" action="gotoSectionEnd"/> + <binding key="<Esc>" action="cancel"/> + <binding key="<=>" action="increaseFont"/> + <binding key="<->" action="decreaseFont"/> + <binding key="<D>" action="toggleIndicator"/> + <binding key="<Return>" action="toggleFullscreen"/> + <binding key="<A>" action="addBook"/> + <binding key="<I>" action="bookInfo"/> + <binding key="<R>" action="rotate"/> + <binding key="<Ctrl>+<DownArrow>" action="nextTOCSection"/> + <binding key="<Ctrl>+<UpArrow>" action="previousTOCSection"/> + <binding key="<Ctrl>+<C>" action="copyToClipboard"/> + <binding key="<G>" action="gotoPageNumber"/> + <binding key="<Z>" action="debugNL"/> +</keymap> diff --git a/reader/data/default/menubar.xml b/reader/data/default/menubar.xml new file mode 100644 index 0000000..bbe89f5 --- /dev/null +++ b/reader/data/default/menubar.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<menubar> + <item id="bookInfo"/> + <item id="toc"/> + <submenu id="library"> + <item id="showLibrary"/> + <item id="previousBook"/> + <item id="showRecent"/> + <item id="addBook"/> + <item id="showHelp"/> + </submenu> + <submenu id="navigate"> + <item id="gotoHome"/> + <item id="gotoPageNumber"/> + <item id="gotoSectionStart"/> + <item id="gotoSectionEnd"/> + <item id="nextTOCSection"/> + <item id="previousTOCSection"/> + <item id="undo"/> + <item id="redo"/> + </submenu> + <submenu id="selection"> + <item id="copyToClipboard"/> + <item id="openInDictionary"/> + <item id="clearSelection"/> + </submenu> + <submenu id="search"> + <item id="search"/> + <item id="findPrevious"/> + <item id="findNext"/> + </submenu> + <submenu id="view"> + <item id="rotate"/> + <item id="toggleFullscreen"/> + <item id="toggleIndicator"/> + </submenu> + <item id="preferences"/> + <item id="quit"/> +</menubar> diff --git a/reader/data/default/styles.desktop.xml b/reader/data/default/styles.desktop.xml new file mode 100644 index 0000000..b12fbeb --- /dev/null +++ b/reader/data/default/styles.desktop.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<DefaultStyles> + <style id="0" name="Regular Paragraph" firstLineIndentDelta="40" allowHyphenations="true"/> + <style id="1" name="Title" fontSizeDelta="10" bold="true" spaceBefore="2" spaceAfter="7" alignment="center" allowHyphenations="false"/> + <style id="3" name="Poem Title" fontSizeDelta="2" bold="true" spaceBefore="6" spaceAfter="6" leftIndent="40" allowHyphenations="false"/> + <style id="2" name="Section Title" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/> + <style id="31" name="Header 1" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/> + <style id="32" name="Header 2" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/> + <style id="5" name="Annotation" fontSizeDelta="-2" firstLineIndentDelta="20" allowHyphenations="true"/> + <style id="6" name="Epigraph" fontSizeDelta="-2" italic="true" leftIndent="80" allowHyphenations="true"/> + <style id="4" name="Subtitle" bold="true" allowHyphenations="true"/> + <style id="33" name="Header 3" bold="true" allowHyphenations="true"/> + <style id="34" name="Header 4" bold="true" allowHyphenations="true"/> + <style id="13" name="Author" leftIndent="20" allowHyphenations="false"/> + <style id="14" name="Date" leftIndent="40" allowHyphenations="false"/> + <style id="7" name="Stanza" spaceBefore="6" spaceAfter="6" alignment="linestart" allowHyphenations="false"/> + <style id="8" name="Verse" leftIndent="20" alignment="linestart" allowHyphenations="false"/> + <style id="10" name="Image" spaceBefore="8" alignment="center"/> + <style id="23" name="Contents Table" spaceAfter="7" leftIndent="20" firstLineIndentDelta="-20" alignment="linestart"/> + <style id="25" name="Library Entry" alignment="linestart" allowHyphenations="false"/> + <style id="9" name="Preformatted text" family="Courier" alignment="linestart" allowHyphenations="false"/> + + <style id="12" partial="true" name="Cite" italic="true"/> + <style id="15" partial="true" name="Internal Hyperlink" allowHyphenations="false" hyperlink="internal"/> + <style id="37" partial="true" name="External Hyperlink" allowHyphenations="false" hyperlink="external"/> + <style id="38" partial="true" name="Link to Another Book" allowHyphenations="false" hyperlink="book"/> + <style id="16" partial="true" name="Footnote" fontSizeDelta="-6" vShift="10" allowHyphenations="false" hyperlink="internal"/> + <style id="17" partial="true" name="Emphasis" italic="true"/> + <style id="18" partial="true" name="Strong" bold="true"/> + <style id="35" name="Header 5" bold="true"/> + <style id="36" name="Header 6" bold="true"/> + <style id="19" partial="true" name="Subscript" fontSizeDelta="-4" vShift="-4" allowHyphenations="false"/> + <style id="20" partial="true" name="Superscript" fontSizeDelta="-4" vShift="10" allowHyphenations="false"/> + <style id="21" partial="true" name="Code" italic="true" allowHyphenations="false"/> + <style id="22" partial="true" name="StrikeThrough"/> + <style id="27" partial="true" name="Italic" italic="true"/> + <style id="28" partial="true" name="Bold" bold="true"/> + <style id="29" partial="true" name="Definition" italic="true"/> + <style id="30" partial="true" name="Definition Description" italic="true"/> +</DefaultStyles> diff --git a/reader/data/default/toolbar.desktop.xml b/reader/data/default/toolbar.desktop.xml new file mode 100644 index 0000000..822d9ee --- /dev/null +++ b/reader/data/default/toolbar.desktop.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<toolbar> + <button id="showReading"/> + <separator/> + <toggleButton id="byAuthor" group="booksOrder" default="yes"/> + <toggleButton id="byTag" group="booksOrder"/> + <separator/> + <menuButton id="showLibrary"/> + <button id="addBook"/> + <button id="showNetworkLibrary"/> + <separator/> + <button id="advancedSearchOnNetwork"/> + <textField id="searchOnNetwork" parameterId="networkSearchPattern" maxWidth="25"/> + <separator/> + <button id="gotoHome"/> + <button id="undo"/> + <button id="redo"/> + <textField id="gotoPageNumberWithParameter" parameterId="pageIndex" maxWidth="5" symbols="digits"/> + <separator/> + <button id="toc"/> + <separator/> + <button id="search"/> + <button id="findPrevious"/> + <button id="findNext"/> + <separator/> + <menuButton id="preferences"/> + <separator/> + <button id="rotate"/> + <separator/> + <button id="showHelp"/> + <!-- + <fillSeparator/> + <searchField id="filterLibrary" parameterId="libraryFilter" maxWidth="15"/> + --> +</toolbar> diff --git a/reader/data/default/toolbar.full.xml b/reader/data/default/toolbar.full.xml new file mode 100644 index 0000000..99cb8a0 --- /dev/null +++ b/reader/data/default/toolbar.full.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<toolbar> + <button id="showReading"/> + <separator/> + <button id="showLibrary"/> + <button id="showRecent"/> + <button id="addBook"/> + <separator/> + <button id="gotoHome"/> + <button id="undo"/> + <button id="redo"/> + <separator/> + <button id="toc"/> + <separator/> + <button id="search"/> + <button id="findPrevious"/> + <button id="findNext"/> + <separator/> + <button id="bookInfo"/> + <button id="preferences"/> + <separator/> + <button id="rotate"/> + <separator/> + <button id="showHelp"/> +</toolbar> diff --git a/reader/data/default/toolbar.short.xml b/reader/data/default/toolbar.short.xml new file mode 100644 index 0000000..4950710 --- /dev/null +++ b/reader/data/default/toolbar.short.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<toolbar> + <button id="showReading"/> + <separator/> + <button id="showLibrary"/> + <button id="showRecent"/> + <button id="addBook"/> + <separator/> + <button id="gotoHome"/> + <button id="undo"/> + <button id="redo"/> + <separator/> + <button id="toc"/> + <separator/> + <button id="search"/> + <button id="findPrevious"/> + <button id="findNext"/> + <separator/> + <button id="bookInfo"/> + <button id="preferences"/> + <separator/> + <button id="rotate"/> +</toolbar> diff --git a/reader/data/formats/fb2/ReaderVersion.ent b/reader/data/formats/fb2/ReaderVersion.ent new file mode 100644 index 0000000..5475a8e --- /dev/null +++ b/reader/data/formats/fb2/ReaderVersion.ent @@ -0,0 +1 @@ +<!ENTITY ReaderVersion "VERSION"> diff --git a/reader/data/formats/fb2/fb2genres.xml b/reader/data/formats/fb2/fb2genres.xml new file mode 100644 index 0000000..1fa028a --- /dev/null +++ b/reader/data/formats/fb2/fb2genres.xml @@ -0,0 +1,933 @@ +<?xml version="1.0" encoding="koi8-r"?> +<fbgenrestransfer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://alexs.ru/fb2/genrestable/GT.xsd"> + <genre value="sf"> + <root-descr lang="en" genre-title="SF, Fantasy" detailed="Alternate History, Cyberpunk, Fantasy, Science Fiction"/> + <root-descr lang="ru" genre-title="æÁÎÔÁÓÔÉËÁ, æÜÎÔÅÚÉ" detailed="îæ, æÜÎÔÅÚÉ, íÉÓÔÉËÁ, ëÉÂÅÒÐÁÎË"/> + <subgenres> + <subgenre value="sf_history"> + <genre-descr lang="en" title="Alternative history"/> + <genre-descr lang="ru" title="áÌØÔÅÒÎÁÔÉ×ÎÁÑ ÉÓÔÏÒÉÑ"/> + <genre-alt value="fantasy_alt_hist" format="fb2.0"/> + </subgenre> + <subgenre value="sf_action"> + <genre-descr lang="en" title="Action SF"/> + <genre-descr lang="ru" title="âÏÅ×ÁÑ æÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_epic"> + <genre-descr lang="en" title="Epic SF"/> + <genre-descr lang="ru" title="üÐÉÞÅÓËÁÑ æÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_heroic"> + <genre-descr lang="en" title="Heroic SF"/> + <genre-descr lang="ru" title="çÅÒÏÉÞÅÓËÁÑ ÆÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_detective"> + <genre-descr lang="en" title="Detective SF"/> + <genre-descr lang="ru" title="äÅÔÅËÔÉ×ÎÁÑ æÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_cyberpunk"> + <genre-descr lang="en" title="Cyberpunk"/> + <genre-descr lang="ru" title="ëÉÂÅÒÐÁÎË"/> + <genre-alt value="sf_cyber_punk" format="fb2.0"/> + </subgenre> + <subgenre value="sf_space"> + <genre-descr lang="en" title="Space SF"/> + <genre-descr lang="ru" title="ëÏÓÍÉÞÅÓËÁÑ æÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_social"> + <genre-descr lang="en" title="Social SF"/> + <genre-descr lang="ru" title="óÏÃÉÁÌØÎÁÑ ÆÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_horror"> + <genre-descr lang="en" title="Horror & Mystic"/> + <genre-descr lang="ru" title="õÖÁÓÙ É íÉÓÔÉËÁ"/> + <genre-alt value="gay_mystery" format="fb2.0"/> + <genre-alt value="horror" format="fb2.0"/> + <genre-alt value="horror_antology" format="fb2.0"/> + <genre-alt value="horror_british" format="fb2.0"/> + <genre-alt value="horror_fantasy" format="fb2.0"/> + <genre-alt value="horror_erotic" format="fb2.0"/> + <genre-alt value="horror_ghosts" format="fb2.0"/> + <genre-alt value="horror_graphic" format="fb2.0"/> + <genre-alt value="horror_occult" format="fb2.0"/> + <genre-alt value="horror_ref" format="fb2.0"/> + <genre-alt value="horror_usa" format="fb2.0"/> + <genre-alt value="horror_vampires" format="fb2.0"/> + <genre-alt value="teens_horror" format="fb2.0"/> + </subgenre> + <subgenre value="sf_humor"> + <genre-descr lang="en" title="Humor SF"/> + <genre-descr lang="ru" title="àÍÏÒÉÓÔÉÞÅÓËÁÑ ÆÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="sf_fantasy"> + <genre-descr lang="en" title="Fantasy"/> + <genre-descr lang="ru" title="æÜÎÔÅÚÉ"/> + <genre-alt value="romance_fantasy" format="fb2.0"/> + <genre-alt value="romance_sf" format="fb2.0"/> + <genre-alt value="romance_time_travel" format="fb2.0"/> + </subgenre> + <subgenre value="sf"> + <genre-descr lang="en" title="Science Fiction"/> + <genre-descr lang="ru" title="îÁÕÞÎÁÑ æÁÎÔÁÓÔÉËÁ"/> + <genre-alt value="gaming" format="fb2.0"/> + <genre-alt value="sf_writing" format="fb2.0"/> + </subgenre> + <subgenre value="child_sf"> + <genre-descr lang="en" title="Science Fiction for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÁÑ æÁÎÔÁÓÔÉËÁ"/> + <genre-alt value="teens_sf" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="detective"> + <root-descr lang="en" genre-title="Detectives, Thrillers" detailed="Police Stories, Ironical, Espionage, Crime"/> + <root-descr lang="ru" genre-title="äÅÔÅËÔÉ×Ù, âÏÅ×ÉËÉ" detailed="ðÏÌÉÃÅÊÓËÉÅ, ÉÒÏÎÉÞÅÓËÉÅ, ÛÐÉÏÎÓËÉÅ, ËÒÉÍÉÎÁÌØÎÙÅ"/> + <subgenres> + <subgenre value="det_classic"> + <genre-descr lang="en" title="Classical Detective"/> + <genre-descr lang="ru" title="ëÌÁÓÓÉÞÅÓËÉÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_police"> + <genre-descr lang="en" title="Police Stories"/> + <genre-descr lang="ru" title="ðÏÌÉÃÅÊÓËÉÊ äÅÔÅËÔÉ×"/> + <genre-alt value="thriller_police" format="fb2.0"/> + </subgenre> + <subgenre value="det_action"> + <genre-descr lang="en" title="Action"/> + <genre-descr lang="ru" title="âÏÅ×ÉËÉ"/> + </subgenre> + <subgenre value="det_irony"> + <genre-descr lang="en" title="Ironical Detective"/> + <genre-descr lang="ru" title="éÒÏÎÉÞÅÓËÉÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_history"> + <genre-descr lang="en" title="Historical Detective"/> + <genre-descr lang="ru" title="éÓÔÏÒÉÞÅÓËÉÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_espionage"> + <genre-descr lang="en" title="Espionage Detective"/> + <genre-descr lang="ru" title="ûÐÉÏÎÓËÉÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_crime"> + <genre-descr lang="en" title="Crime Detective"/> + <genre-descr lang="ru" title="ëÒÉÍÉÎÁÌØÎÙÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_political"> + <genre-descr lang="en" title="Political Detective"/> + <genre-descr lang="ru" title="ðÏÌÉÔÉÞÅÓËÉÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="det_maniac"> + <genre-descr lang="en" title="Maniacs"/> + <genre-descr lang="ru" title="íÁÎØÑËÉ"/> + </subgenre> + <subgenre value="det_hard"> + <genre-descr lang="en" title="Hard-boiled Detective"/> + <genre-descr lang="ru" title="ëÒÕÔÏÊ äÅÔÅËÔÉ×"/> + </subgenre> + <subgenre value="thriller"> + <genre-descr lang="en" title="Thrillers"/> + <genre-descr lang="ru" title="ôÒÉÌÌÅÒÙ"/> + <genre-alt value="thriller_mystery" format="fb2.0"/> + </subgenre> + <subgenre value="detective"> + <genre-descr lang="en" title="Detective"/> + <genre-descr lang="ru" title="äÅÔÅËÔÉ×"/> + <genre-alt value="mystery" format="fb2.0"/> + </subgenre> + <subgenre value="sf_detective"> + <genre-descr lang="en" title="Detective SF"/> + <genre-descr lang="ru" title="äÅÔÅËÔÉ×ÎÁÑ æÁÎÔÁÓÔÉËÁ"/> + <genre-alt value="teens_mysteries" format="fb2.0"/> + </subgenre> + <subgenre value="child_det"> + <genre-descr lang="en" title="Detectives & Thrillers"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ ïÓÔÒÏÓÀÖÅÔÎÙÅ"/> + </subgenre> + <subgenre value="love_detective"> + <genre-descr lang="en" title="Detective Romance"/> + <genre-descr lang="ru" title="ïÓÔÒÏÓÀÖÅÔÎÙÅ ìÀÂÏ×ÎÙÅ òÏÍÁÎÙ"/> + </subgenre> + </subgenres> + </genre> + <genre value="prose"> + <root-descr lang="en" genre-title="Prose" detailed="Classical, History, Contemporary"/> + <root-descr lang="ru" genre-title="ðÒÏÚÁ" detailed="ëÌÁÓÓÉËÁ, ÉÓÔÏÒÉÞÅÓËÁÑ, ÓÏ×ÒÅÍÅÎÎÁÑ"/> + <subgenres> + <subgenre value="prose_classic"> + <genre-descr lang="en" title="Classics Prose"/> + <genre-descr lang="ru" title="ëÌÁÓÓÉÞÅÓËÁÑ ðÒÏÚÁ"/> + <genre-alt value="literature" format="fb2.0"/> + <genre-alt value="literature_books" format="fb2.0"/> + <genre-alt value="literature_british" format="fb2.0"/> + <genre-alt value="literature_classics" format="fb2.0"/> + <genre-alt value="literature_drama" format="fb2.0"/> + <genre-alt value="literature_essay" format="fb2.0"/> + <genre-alt value="literature_antology" format="fb2.0"/> + <genre-alt value="literature_saga" format="fb2.0"/> + <genre-alt value="literature_short" format="fb2.0"/> + <genre-alt value="literature_usa" format="fb2.0"/> + <genre-alt value="literature_world" format="fb2.0"/> + </subgenre> + <subgenre value="prose_history"> + <genre-descr lang="en" title="Historical Prose"/> + <genre-descr lang="ru" title="éÓÔÏÒÉÞÅÓËÁÑ ðÒÏÚÁ"/> + <genre-alt value="literature_history" format="fb2.0"/> + <genre-alt value="literature_critic" format="fb2.0"/> + </subgenre> + <subgenre value="prose_contemporary"> + <genre-descr lang="en" title="Contemporary Prose"/> + <genre-descr lang="ru" title="óÏ×ÒÅÍÅÎÎÁÑ ðÒÏÚÁ"/> + <genre-alt value="literature_political" format="fb2.0"/> + <genre-alt value="literature_war" format="fb2.0"/> + <genre-alt value="ref_writing" format="fb2.0"/> + </subgenre> + <subgenre value="prose_counter"> + <genre-descr lang="en" title="Counterculture"/> + <genre-descr lang="ru" title="ëÏÎÔÒËÕÌØÔÕÒÁ"/> + <genre-alt value="literature_gay" format="fb2.0"/> + </subgenre> + <subgenre value="prose_rus_classsic"> + <genre-descr lang="en" title="Russian Classics"/> + <genre-descr lang="ru" title="òÕÓÓËÁÑ ëÌÁÓÓÉËÁ"/> + <genre-alt value="literature_rus_classsic" format="fb2.0"/> + <genre-alt value="prose_rus_classic" format="fb2.0"/> + </subgenre> + <subgenre value="prose_su_classics"> + <genre-descr lang="en" title="Soviet Classics"/> + <genre-descr lang="ru" title="óÏ×ÅÔÓËÁÑ ëÌÁÓÓÉËÁ"/> + <genre-alt value="literature_su_classics" format="fb2.0"/> + </subgenre> + <subgenre value="humor_prose"> + <genre-descr lang="en" title="Humor Prose"/> + <genre-descr lang="ru" title="àÍÏÒÉÓÔÉÞÅÓËÁÑ ðÒÏÚÁ"/> + </subgenre> + <subgenre value="child_prose"> + <genre-descr lang="en" title="Prose"/> + <genre-descr lang="ru" title="äÅÔÓËÁÑ ðÒÏÚÁ"/> + <genre-alt value="teens_literature" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="love"> + <root-descr lang="en" genre-title="Romance" detailed="Historical, Contemporary, Detective"/> + <root-descr lang="ru" genre-title="ìÀÂÏ×ÎÙÅ ÒÏÍÁÎÙ" detailed="éÓÔÏÒÉÞÅÓËÉÅ, ÓÏ×ÒÅÍÅÎÎÙÅ, ÏÓÔÒÏÓÀÖÅÔÎÙÅ"/> + <subgenres> + <subgenre value="love_contemporary"> + <genre-descr lang="en" title="Contemporary Romance"/> + <genre-descr lang="ru" title="óÏ×ÒÅÍÅÎÎÙÅ ìÀÂÏ×ÎÙÅ òÏÍÁÎÙ"/> + <genre-alt value="romance" format="fb2.0"/> + <genre-alt value="romance_multicultural" format="fb2.0"/> + <genre-alt value="romance_series" format="fb2.0"/> + <genre-alt value="romance_anthologies" format="fb2.0"/> + <genre-alt value="romance_contemporary" format="fb2.0"/> + <genre-alt value="literature_women" format="fb2.0"/> + <genre-alt value="romance_romantic_suspense" format="fb2.0"/> + </subgenre> + <subgenre value="love_history"> + <genre-descr lang="en" title="Historical Romance"/> + <genre-descr lang="ru" title="éÓÔÏÒÉÞÅÓËÉÅ ìÀÂÏ×ÎÙÅ òÏÍÁÎÙ"/> + <genre-alt value="romance_regency" format="fb2.0"/> + <genre-alt value="romance_historical" format="fb2.0"/> + </subgenre> + <subgenre value="love_detective"> + <genre-descr lang="en" title="Detective Romance"/> + <genre-descr lang="ru" title="ïÓÔÒÏÓÀÖÅÔÎÙÅ ìÀÂÏ×ÎÙÅ òÏÍÁÎÙ"/> + </subgenre> + <subgenre value="love_short"> + <genre-descr lang="en" title="Short Romance"/> + <genre-descr lang="ru" title="ëÏÒÏÔËÉÅ ìÀÂÏ×ÎÙÅ òÏÍÁÎÙ"/> + </subgenre> + <subgenre value="love_erotica"> + <genre-descr lang="en" title="Erotica"/> + <genre-descr lang="ru" title="üÒÏÔÉËÁ"/> + <genre-alt value="literature_erotica" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="adventure"> + <root-descr lang="en" genre-title="Adventure" detailed="Western, Historical, Sea"/> + <root-descr lang="ru" genre-title="ðÒÉËÌÀÞÅÎÉÑ" detailed="÷ÅÓÔÅÒÎÙ, ÉÓÔÏÒÉÞÅÓËÉÅ, ÍÏÒÓËÉÅ"/> + <subgenres> + <subgenre value="adv_western"> + <genre-descr lang="en" title="Western"/> + <genre-descr lang="ru" title="÷ÅÓÔÅÒÎÙ"/> + <genre-alt value="literature_western" format="fb2.0"/> + </subgenre> + <subgenre value="adv_history"> + <genre-descr lang="en" title="History"/> + <genre-descr lang="ru" title="éÓÔÏÒÉÞÅÓËÉÅ ðÒÉËÌÀÞÅÎÉÑ"/> + </subgenre> + <subgenre value="adv_indian"> + <genre-descr lang="en" title="Indians"/> + <genre-descr lang="ru" title="éÎÄÅÊÃÙ"/> + </subgenre> + <subgenre value="adv_maritime"> + <genre-descr lang="en" title="Maritime Fiction"/> + <genre-descr lang="ru" title="íÏÒÓËÉÅ ðÒÉËÌÀÞÅÎÉÑ"/> + <genre-alt value="literature_sea" format="fb2.0"/> + </subgenre> + <subgenre value="adv_geo"> + <genre-descr lang="en" title="Travel & Geography"/> + <genre-descr lang="ru" title="ðÕÔÅÛÅÓÔ×ÉÑ É çÅÏÇÒÁÆÉÑ"/> + <genre-alt value="gay_travel" format="fb2.0"/> + <genre-alt value="outdoors_travel" format="fb2.0"/> + <genre-alt value="travel" format="fb2.0"/> + <genre-alt value="travel_africa" format="fb2.0"/> + <genre-alt value="travel_asia" format="fb2.0"/> + <genre-alt value="travel_australia" format="fb2.0"/> + <genre-alt value="travel_canada" format="fb2.0"/> + <genre-alt value="travel_caribbean" format="fb2.0"/> + <genre-alt value="travel_europe" format="fb2.0"/> + <genre-alt value="travel_guidebook_series" format="fb2.0"/> + <genre-alt value="travel_lat_am" format="fb2.0"/> + <genre-alt value="travel_middle_east" format="fb2.0"/> + <genre-alt value="travel_polar" format="fb2.0"/> + <genre-alt value="travel_spec" format="fb2.0"/> + <genre-alt value="travel_usa" format="fb2.0"/> + <genre-alt value="travel_rus" format="fb2.0"/> + <genre-alt value="travel_ex_ussr" format="fb2.0"/> + </subgenre> + <subgenre value="adv_animal"> + <genre-descr lang="en" title="Nature & Animals"/> + <genre-descr lang="ru" title="ðÒÉÒÏÄÁ É öÉ×ÏÔÎÙÅ"/> + <genre-alt value="child_animals" format="fb2.0"/> + </subgenre> + <subgenre value="adventure"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="literature_adv" format="fb2.0"/> + <genre-alt value="literature_men_advent" format="fb2.0"/> + </subgenre> + <subgenre value="child_adv"> + <genre-descr lang="en" title="Adventures for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ ðÒÉËÌÀÞÅÎÉÑ"/> + </subgenre> + </subgenres> + </genre> + <genre value="children"> + <root-descr lang="en" genre-title="Children's" detailed="Fairy Tales, Fantasy, Detectives..."/> + <root-descr lang="ru" genre-title="ëÎÉÇÉ ÄÌÑ ÄÅÔÅÊ" detailed="óËÁÚËÉ, ÆÁÎÔÁÓÔÉËÁ, ÄÅÔÅËÔÉ×Ù..."/> + <subgenres> + <subgenre value="child_tale"> + <genre-descr lang="en" title="Fairy Tales"/> + <genre-descr lang="ru" title="óËÁÚËÉ"/> + <genre-alt value="child_3" format="fb2.0"/> + <genre-alt value="literature_fairy" format="fb2.0"/> + </subgenre> + <subgenre value="child_verse"> + <genre-descr lang="en" title="Verses"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ óÔÉÈÉ"/> + </subgenre> + <subgenre value="child_prose"> + <genre-descr lang="en" title="Prose for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÁÑ ðÒÏÚÁ"/> + <genre-alt value="child_4" format="fb2.0"/> + <genre-alt value="child_9" format="fb2.0"/> + <genre-alt value="child_history" format="fb2.0"/> + <genre-alt value="child_characters" format="fb2.0"/> + </subgenre> + <subgenre value="child_sf"> + <genre-descr lang="en" title="Science Fiction for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÁÑ æÁÎÔÁÓÔÉËÁ"/> + </subgenre> + <subgenre value="child_det"> + <genre-descr lang="en" title="Detectives & Thrillers"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ ïÓÔÒÏÓÀÖÅÔÎÙÅ"/> + </subgenre> + <subgenre value="child_adv"> + <genre-descr lang="en" title="Adventures for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ ðÒÉËÌÀÞÅÎÉÑ"/> + <genre-alt value="teens_history" format="fb2.0"/> + <genre-alt value="teens_series" format="fb2.0"/> + </subgenre> + <subgenre value="child_education"> + <genre-descr lang="en" title="Education for Kids"/> + <genre-descr lang="ru" title="äÅÔÓËÁÑ ïÂÒÁÚÏ×ÁÔÅÌØÎÁÑ ìÉÔÅÒÁÔÕÒÁ"/> + <genre-alt value="child_edu" format="fb2.0"/> + <genre-alt value="child_nature" format="fb2.0"/> + </subgenre> + <subgenre value="children"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="child_art" format="fb2.0"/> + <genre-alt value="child_obsessions" format="fb2.0"/> + <genre-alt value="child_people" format="fb2.0"/> + <genre-alt value="child_ref" format="fb2.0"/> + <genre-alt value="child_series" format="fb2.0"/> + <genre-alt value="child_sports" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="poetry"> + <root-descr lang="en" genre-title="Poetry, Dramaturgy" detailed="Poetry, Dramaturgy"/> + <root-descr lang="ru" genre-title="ðÏÜÚÉÑ, äÒÁÍÁÔÕÒÇÉÑ" detailed="ðÏÜÚÉÑ, ÄÒÁÍÁÔÕÒÇÉÑ"/> + <subgenres> + <subgenre value="poetry"> + <genre-descr lang="en" title="Poetry"/> + <genre-descr lang="ru" title="ðÏÜÚÉÑ"/> + <genre-alt value="literature_poetry" format="fb2.0"/> + </subgenre> + <subgenre value="dramaturgy"> + <genre-descr lang="en" title="Dramaturgy"/> + <genre-descr lang="ru" title="äÒÁÍÁÔÕÒÇÉÑ"/> + <genre-alt value="performance" format="fb2.0"/> + </subgenre> + <subgenre value="humor_verse"> + <genre-descr lang="en" title="Humor Verses"/> + <genre-descr lang="ru" title="àÍÏÒÉÓÔÉÞÅÓËÉÅ óÔÉÈÉ"/> + </subgenre> + <subgenre value="child_verse"> + <genre-descr lang="en" title="Verses"/> + <genre-descr lang="ru" title="äÅÔÓËÉÅ óÔÉÈÉ"/> + </subgenre> + </subgenres> + </genre> + <genre value="antique"> + <root-descr lang="en" genre-title="Antique" detailed="Antique literature, Myths, Legends"/> + <root-descr lang="ru" genre-title="óÔÁÒÉÎÎÏÅ" detailed="áÎÔÉÞÎÁÑ ÌÉÔÅÒÁÔÕÒÁ, ÍÉÆÙ, ÌÅÇÅÎÄÙ"/> + <subgenres> + <subgenre value="antique_ant"> + <genre-descr lang="en" title="Antique Literature"/> + <genre-descr lang="ru" title="áÎÔÉÞÎÁÑ ìÉÔÅÒÁÔÕÒÁ"/> + </subgenre> + <subgenre value="antique_european"> + <genre-descr lang="en" title="European Literature"/> + <genre-descr lang="ru" title="å×ÒÏÐÅÊÓËÁÑ óÔÁÒÉÎÎÁÑ ìÉÔÅÒÁÔÕÒÁ"/> + </subgenre> + <subgenre value="antique_russian"> + <genre-descr lang="en" title="Antique Russian Literature"/> + <genre-descr lang="ru" title="äÒÅ×ÎÅÒÕÓÓËÁÑ ìÉÔÅÒÁÔÕÒÁ"/> + </subgenre> + <subgenre value="antique_east"> + <genre-descr lang="en" title="Antique East Literature"/> + <genre-descr lang="ru" title="äÒÅ×ÎÅ×ÏÓÔÏÞÎÁÑ ìÉÔÅÒÁÔÕÒÁ"/> + </subgenre> + <subgenre value="antique_myths"> + <genre-descr lang="en" title="Myths. Legends. Epos"/> + <genre-descr lang="ru" title="íÉÆÙ. ìÅÇÅÎÄÙ. üÐÏÓ"/> + <genre-alt value="nonfiction_folklor" format="fb2.0"/> + </subgenre> + <subgenre value="antique"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + </subgenre> + </subgenres> + </genre> + <genre value="science"> + <root-descr lang="en" genre-title="Science, Education" detailed="Physics, Philosophy, Psychology, Business literature"/> + <root-descr lang="ru" genre-title="îÁÕËÁ, ïÂÒÁÚÏ×ÁÎÉÅ" detailed="æÉÚÉËÁ, ÆÉÌÏÓÏÆÉÑ, ÐÓÉÈÏÌÏÇÉÑ, ÄÅÌÏ×ÁÑ ÌÉÔÅÒÁÔÕÒÁ"/> + <subgenres> + <subgenre value="sci_history"> + <genre-descr lang="en" title="History"/> + <genre-descr lang="ru" title="éÓÔÏÒÉÑ"/> + <genre-alt value="history_africa" format="fb2.0"/> + <genre-alt value="history_america" format="fb2.0"/> + <genre-alt value="history_ancient" format="fb2.0"/> + <genre-alt value="history_asia" format="fb2.0"/> + <genre-alt value="history_australia" format="fb2.0"/> + <genre-alt value="history_europe" format="fb2.0"/> + <genre-alt value="history_study" format="fb2.0"/> + <genre-alt value="history_jewish" format="fb2.0"/> + <genre-alt value="history_middle_east" format="fb2.0"/> + <genre-alt value="histor_military" format="fb2.0"/> + <genre-alt value="history_military_science" format="fb2.0"/> + <genre-alt value="history_russia" format="fb2.0"/> + <genre-alt value="history_usa" format="fb2.0"/> + <genre-alt value="history_world" format="fb2.0"/> + <genre-alt value="nonfiction_antropology" format="fb2.0"/> + <genre-alt value="science_archaeology" format="fb2.0"/> + <genre-alt value="ref_genealogy" format="fb2.0"/> + <genre-alt value="science_history_philosophy" format="fb2.0"/> + </subgenre> + <subgenre value="sci_psychology"> + <genre-descr lang="en" title="Psychology"/> + <genre-descr lang="ru" title="ðÓÉÈÏÌÏÇÉÑ"/> + <genre-alt value="health_mental" format="fb2.0"/> + <genre-alt value="health_psy" format="fb2.0"/> + <genre-alt value="science_behavioral_sciences" format="fb2.0"/> + <genre-alt value="science_psy" format="fb2.0"/> + <genre-alt value="teens_social" format="fb2.0"/> + </subgenre> + <subgenre value="sci_culture"> + <genre-descr lang="en" title="Cultural Science"/> + <genre-descr lang="ru" title="ëÕÌØÔÕÒÏÌÏÇÉÑ"/> + </subgenre> + <subgenre value="sci_religion"> + <genre-descr lang="en" title="Religious Studies"/> + <genre-descr lang="ru" title="òÅÌÉÇÉÏ×ÅÄÅÎÉÅ"/> + </subgenre> + <subgenre value="sci_philosophy"> + <genre-descr lang="en" title="Philosophy"/> + <genre-descr lang="ru" title="æÉÌÏÓÏÆÉÑ"/> + <genre-alt value="nonfiction_philosophy" format="fb2.0"/> + </subgenre> + <subgenre value="sci_politics"> + <genre-descr lang="en" title="Politics"/> + <genre-descr lang="ru" title="ðÏÌÉÔÉËÁ"/> + </subgenre> + <subgenre value="sci_business"> + <genre-descr lang="en" title="Business literature"/> + <genre-descr lang="ru" title="äÅÌÏ×ÁÑ ÌÉÔÅÒÁÔÕÒÁ"/> + <genre-alt value="biz_accounting" format="fb2.0"/> + <genre-alt value="biz_life" format="fb2.0"/> + <genre-alt value="biz_careers" format="fb2.0"/> + <genre-alt value="biz_economics" format="fb2.0"/> + <genre-alt value="biz_finance" format="fb2.0"/> + <genre-alt value="biz_international" format="fb2.0"/> + <genre-alt value="biz_professions" format="fb2.0"/> + <genre-alt value="biz_investing" format="fb2.0"/> + <genre-alt value="biz_management" format="fb2.0"/> + <genre-alt value="biz_sales" format="fb2.0"/> + <genre-alt value="biz_personal_fin" format="fb2.0"/> + <genre-alt value="biz_ref" format="fb2.0"/> + <genre-alt value="biz_small_biz" format="fb2.0"/> + <genre-alt value="professional_finance" format="fb2.0"/> + <genre-alt value="professional_management" format="fb2.0"/> + <genre-alt value="ref_edu" format="fb2.0"/> + </subgenre> + <subgenre value="sci_juris"> + <genre-descr lang="en" title="Jurisprudence"/> + <genre-descr lang="ru" title="àÒÉÓÐÒÕÄÅÎÃÉÑ"/> + <genre-alt value="nonfiction_law" format="fb2.0"/> + <genre-alt value="professional_law" format="fb2.0"/> + </subgenre> + <subgenre value="sci_linguistic"> + <genre-descr lang="en" title="Linguistics"/> + <genre-descr lang="ru" title="ñÚÙËÏÚÎÁÎÉÅ"/> + </subgenre> + <subgenre value="sci_medicine"> + <genre-descr lang="en" title="Medicine"/> + <genre-descr lang="ru" title="íÅÄÉÃÉÎÁ"/> + <genre-alt value="health_aging" format="fb2.0"/> + <genre-alt value="health_alt_medicine" format="fb2.0"/> + <genre-alt value="health_cancer" format="fb2.0"/> + <genre-alt value="professional_medical" format="fb2.0"/> + <genre-alt value="science_medicine" format="fb2.0"/> + </subgenre> + <subgenre value="sci_phys"> + <genre-descr lang="en" title="Physics"/> + <genre-descr lang="ru" title="æÉÚÉËÁ"/> + <genre-alt value="science_physics" format="fb2.0"/> + </subgenre> + <subgenre value="sci_math"> + <genre-descr lang="en" title="Mathematics"/> + <genre-descr lang="ru" title="íÁÔÅÍÁÔÉËÁ"/> + <genre-alt value="science_math" format="fb2.0"/> + </subgenre> + <subgenre value="sci_chem"> + <genre-descr lang="en" title="Chemistry"/> + <genre-descr lang="ru" title="èÉÍÉÑ"/> + <genre-alt value="science_chemistry" format="fb2.0"/> + </subgenre> + <subgenre value="sci_biology"> + <genre-descr lang="en" title="Biology"/> + <genre-descr lang="ru" title="âÉÏÌÏÇÉÑ"/> + <genre-alt value="outdoors_birdwatching" format="fb2.0"/> + <genre-alt value="outdoors_ecology" format="fb2.0"/> + <genre-alt value="outdoors_ecosystems" format="fb2.0"/> + <genre-alt value="outdoors_env" format="fb2.0"/> + <genre-alt value="outdoors_fauna" format="fb2.0"/> + <genre-alt value="outdoors_flora" format="fb2.0"/> + <genre-alt value="outdoors_nature_writing" format="fb2.0"/> + <genre-alt value="outdoors_ref" format="fb2.0"/> + <genre-alt value="science_biolog" format="fb2.0"/> + </subgenre> + <subgenre value="sci_tech"> + <genre-descr lang="en" title="Technical"/> + <genre-descr lang="ru" title="ôÅÈÎÉÞÅÓËÉÅ"/> + <genre-alt value="professional_enginering" format="fb2.0"/> + <genre-alt value="professional_sci" format="fb2.0"/> + <genre-alt value="science_technology" format="fb2.0"/> + </subgenre> + <subgenre value="science"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="nonfiction_edu" format="fb2.0"/> + <genre-alt value="nonfiction_gov" format="fb2.0"/> + <genre-alt value="nonfiction_holidays" format="fb2.0"/> + <genre-alt value="nonfiction_social_sci" format="fb2.0"/> + <genre-alt value="nonfiction_ethnology" format="fb2.0"/> + <genre-alt value="nonfiction_gender" format="fb2.0"/> + <genre-alt value="nonfiction_gerontology" format="fb2.0"/> + <genre-alt value="nonfiction_hum_geogr" format="fb2.0"/> + <genre-alt value="nonfiction_methodology" format="fb2.0"/> + <genre-alt value="nonfiction_research" format="fb2.0"/> + <genre-alt value="nonfiction_social_work" format="fb2.0"/> + <genre-alt value="nonfiction_sociology" format="fb2.0"/> + <genre-alt value="nonfiction_spec_group" format="fb2.0"/> + <genre-alt value="nonfiction_stat" format="fb2.0"/> + <genre-alt value="outdoors_resources" format="fb2.0"/> + <genre-alt value="professional_edu" format="fb2.0"/> + <genre-alt value="science_agri" format="fb2.0"/> + <genre-alt value="science_astronomy" format="fb2.0"/> + <genre-alt value="science_earth" format="fb2.0"/> + <genre-alt value="science_edu" format="fb2.0"/> + <genre-alt value="science_evolution" format="fb2.0"/> + <genre-alt value="science_measurement" format="fb2.0"/> + <genre-alt value="science_eco" format="fb2.0"/> + <genre-alt value="science_ref" format="fb2.0"/> + <genre-alt value="teens_tech" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="computers"> + <root-descr lang="en" genre-title="Computers" detailed="Internet, Programming, Hardware"/> + <root-descr lang="ru" genre-title="ëÏÍÐØÀÔÅÒÙ" detailed="éÎÔÅÒÎÅÔ, ÐÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÅ, ÖÅÌÅÚÏ"/> + <subgenres> + <subgenre value="comp_www"> + <genre-descr lang="en" title="Internet"/> + <genre-descr lang="ru" title="éÎÔÅÒÎÅÔ"/> + </subgenre> + <subgenre value="comp_programming"> + <genre-descr lang="en" title="Programming"/> + <genre-descr lang="ru" title="ðÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÅ"/> + </subgenre> + <subgenre value="comp_hard"> + <genre-descr lang="en" title="Hardware"/> + <genre-descr lang="ru" title="ëÏÍÐØÀÔÅÒÎÏÅ öÅÌÅÚÏ"/> + <genre-alt value="comp_hardware" format="fb2.0"/> + </subgenre> + <subgenre value="comp_soft"> + <genre-descr lang="en" title="Software"/> + <genre-descr lang="ru" title="ðÒÏÇÒÁÍÍÙ"/> + <genre-alt value="comp_software" format="fb2.0"/> + </subgenre> + <subgenre value="comp_db"> + <genre-descr lang="en" title="Databases"/> + <genre-descr lang="ru" title="âÁÚÙ äÁÎÎÙÈ"/> + </subgenre> + <subgenre value="comp_osnet"> + <genre-descr lang="en" title="OS & Networking"/> + <genre-descr lang="ru" title="ïó É óÅÔÉ"/> + <genre-alt value="comp_microsoft" format="fb2.0"/> + <genre-alt value="comp_networking" format="fb2.0"/> + <genre-alt value="comp_os" format="fb2.0"/> + </subgenre> + <subgenre value="computers"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="child_computers" format="fb2.0"/> + <genre-alt value="compusers" format="fb2.0"/> + <genre-alt value="comp_office" format="fb2.0"/> + <genre-alt value="comp_cert" format="fb2.0"/> + <genre-alt value="comp_games" format="fb2.0"/> + <genre-alt value="comp_sci" format="fb2.0"/> + <genre-alt value="comp_biz" format="fb2.0"/> + <genre-alt value="comp_graph" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="reference"> + <root-descr lang="en" genre-title="Reference" detailed="Reference, Encyclopedias, Dictionaries"/> + <root-descr lang="ru" genre-title="óÐÒÁ×ÏÞÎÉËÉ" detailed="óÐÒÁ×ÏÞÎÉËÉ, ÜÎÃÉËÌÏÐÅÄÉÉ, ÓÌÏ×ÁÒÉ"/> + <subgenres> + <subgenre value="ref_encyc"> + <genre-descr lang="en" title="Encyclopedias"/> + <genre-descr lang="ru" title="üÎÃÉËÌÏÐÅÄÉÉ"/> + <genre-alt value="ref_encyclopedia" format="fb2.0"/> + </subgenre> + <subgenre value="ref_dict"> + <genre-descr lang="en" title="Dictionaries"/> + <genre-descr lang="ru" title="óÌÏ×ÁÒÉ"/> + <genre-alt value="ref_dict" format="fb2.0"/> + </subgenre> + <subgenre value="ref_ref"> + <genre-descr lang="en" title="Reference"/> + <genre-descr lang="ru" title="óÐÒÁ×ÏÞÎÉËÉ"/> + <genre-alt value="ref_almanacs" format="fb2.0"/> + <genre-alt value="ref_careers" format="fb2.0"/> + <genre-alt value="ref_catalogs" format="fb2.0"/> + <genre-alt value="ref_cons_guides" format="fb2.0"/> + <genre-alt value="ref_study_guides" format="fb2.0"/> + </subgenre> + <subgenre value="ref_guide"> + <genre-descr lang="en" title="Guidebooks"/> + <genre-descr lang="ru" title="òÕËÏ×ÏÄÓÔ×Á"/> + <genre-alt value="outdoors_field_guides" format="fb2.0"/> + </subgenre> + <subgenre value="reference"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="nonfiction_ref" format="fb2.0"/> + <genre-alt value="family_ref" format="fb2.0"/> + <genre-alt value="references" format="fb2.0"/> + <genre-alt value="ref_etiquette" format="fb2.0"/> + <genre-alt value="ref_langs" format="fb2.0"/> + <genre-alt value="ref_fun" format="fb2.0"/> + <genre-alt value="ref_books" format="fb2.0"/> + <genre-alt value="ref_quotations" format="fb2.0"/> + <genre-alt value="ref_words" format="fb2.0"/> + <genre-alt value="teens_ref" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="nonfiction"> + <root-descr lang="en" genre-title="Nonfiction" detailed="Biography, Memoirs, Publicism"/> + <root-descr lang="ru" genre-title="äÏËÕÍÅÎÔÁÌØÎÏÅ" detailed="âÉÏÇÒÁÆÉÉ, ÍÅÍÕÁÒÙ, ÐÕÂÌÉÃÉÓÔÉËÁ"/> + <subgenres> + <subgenre value="nonf_biography"> + <genre-descr lang="en" title="Biography & Memoirs"/> + <genre-descr lang="ru" title="âÉÏÇÒÁÆÉÉ É íÅÍÕÁÒÙ"/> + <genre-alt value="people" format="fb2.0"/> + <genre-alt value="biography" format="fb2.0"/> + <genre-alt value="biogr_arts" format="fb2.0"/> + <genre-alt value="biogr_ethnic" format="fb2.0"/> + <genre-alt value="biogr_family" format="fb2.0"/> + <genre-alt value="biogr_historical" format="fb2.0"/> + <genre-alt value="biogr_leaders" format="fb2.0"/> + <genre-alt value="biogr_professionals" format="fb2.0"/> + <genre-alt value="biogr_sports" format="fb2.0"/> + <genre-alt value="biogr_travel" format="fb2.0"/> + <genre-alt value="biz_beogr" format="fb2.0"/> + <genre-alt value="gay_biogr" format="fb2.0"/> + <genre-alt value="history_gay" format="fb2.0"/> + <genre-alt value="literature_letters" format="fb2.0"/> + <genre-alt value="teens_beogr" format="fb2.0"/> + </subgenre> + <subgenre value="nonf_publicism"> + <genre-descr lang="en" title="Publicism"/> + <genre-descr lang="ru" title="ðÕÂÌÉÃÉÓÔÉËÁ"/> + </subgenre> + <subgenre value="nonf_criticism"> + <genre-descr lang="en" title="Criticism"/> + <genre-descr lang="ru" title="ëÒÉÔÉËÁ"/> + </subgenre> + <subgenre value="nonfiction"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="gay_nonfiction" format="fb2.0"/> + <genre-alt value="nonfiction_avto" format="fb2.0"/> + <genre-alt value="nonfiction_crime" format="fb2.0"/> + <genre-alt value="nonfiction_events" format="fb2.0"/> + <genre-alt value="nonfiction_politics" format="fb2.0"/> + <genre-alt value="nonfiction_traditions" format="fb2.0"/> + <genre-alt value="nonfiction_demography" format="fb2.0"/> + <genre-alt value="nonfiction_racism" format="fb2.0"/> + <genre-alt value="nonfiction_emigration" format="fb2.0"/> + <genre-alt value="nonfiction_philantropy" format="fb2.0"/> + <genre-alt value="nonfiction_transportation" format="fb2.0"/> + <genre-alt value="nonfiction_true_accounts" format="fb2.0"/> + <genre-alt value="nonfiction_urban" format="fb2.0"/> + <genre-alt value="nonfiction_women" format="fb2.0"/> + <genre-alt value="outdoors_conservation" format="fb2.0"/> + </subgenre> + <subgenre value="design"> + <genre-descr lang="en" title="Art, Design"/> + <genre-descr lang="ru" title="éÓËÕÓÓÔ×Ï, äÉÚÁÊÎ"/> + <genre-alt value="architecture" format="fb2.0"/> + <genre-alt value="art" format="fb2.0"/> + <genre-alt value="art_instr" format="fb2.0"/> + <genre-alt value="artists" format="fb2.0"/> + <genre-alt value="fashion" format="fb2.0"/> + <genre-alt value="graph_design" format="fb2.0"/> + <genre-alt value="photography" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="religion"> + <root-descr lang="en" genre-title="Religion" detailed="Religion, Esoterics"/> + <root-descr lang="ru" genre-title="òÅÌÉÇÉÑ" detailed="òÅÌÉÇÉÑ, ÜÚÏÔÅÒÉËÁ"/> + <subgenres> + <subgenre value="religion_rel"> + <genre-descr lang="en" title="Religion"/> + <genre-descr lang="ru" title="òÅÌÉÇÉÑ"/> + <genre-alt value="child_religion" format="fb2.0"/> + <genre-alt value="chris_bibles" format="fb2.0"/> + <genre-alt value="chris_pravoslavie" format="fb2.0"/> + <genre-alt value="chris_catholicism" format="fb2.0"/> + <genre-alt value="chris_living" format="fb2.0"/> + <genre-alt value="chris_history" format="fb2.0"/> + <genre-alt value="chris_clergy" format="fb2.0"/> + <genre-alt value="chris_edu" format="fb2.0"/> + <genre-alt value="chris_evangelism" format="fb2.0"/> + <genre-alt value="chris_fiction" format="fb2.0"/> + <genre-alt value="chris_holidays" format="fb2.0"/> + <genre-alt value="chris_jesus" format="fb2.0"/> + <genre-alt value="chris_mormonism" format="fb2.0"/> + <genre-alt value="chris_orthodoxy" format="fb2.0"/> + <genre-alt value="outdoors_conservation" format="fb2.0"/> + <genre-alt value="chris_protestantism" format="fb2.0"/> + <genre-alt value="chris_ref" format="fb2.0"/> + <genre-alt value="chris_theology" format="fb2.0"/> + <genre-alt value="chris_devotion" format="fb2.0"/> + <genre-alt value="literature_religion" format="fb2.0"/> + <genre-alt value="religion" format="fb2.0"/> + <genre-alt value="religion_bibles" format="fb2.0"/> + <genre-alt value="Christianity" format="fb2.0"/> + <genre-alt value="religion_fiction" format="fb2.0"/> + <genre-alt value="religion_new_age" format="fb2.0"/> + <genre-alt value="religion_religious_studies" format="fb2.0"/> + <genre-alt value="romance_religion" format="fb2.0"/> + <genre-alt value="teens_religion" format="fb2.0"/> + </subgenre> + <subgenre value="religion_esoterics"> + <genre-descr lang="en" title="Esoterics"/> + <genre-descr lang="ru" title="üÚÏÔÅÒÉËÁ"/> + <genre-alt value="religion_occult" format="fb2.0"/> + <genre-alt value="religion_spirituality" format="fb2.0"/> + </subgenre> + <subgenre value="religion_self"> + <genre-descr lang="en" title="Self-perfection"/> + <genre-descr lang="ru" title="óÁÍÏÓÏ×ÅÒÛÅÎÓÔ×Ï×ÁÎÉÅ"/> + </subgenre> + <subgenre value="religion"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="religion_east" format="fb2.0"/> + <genre-alt value="religion_buddhism" format="fb2.0"/> + <genre-alt value="religion_earth" format="fb2.0"/> + <genre-alt value="religion_hinduism" format="fb2.0"/> + <genre-alt value="religion_islam" format="fb2.0"/> + <genre-alt value="religion_judaism" format="fb2.0"/> + <genre-alt value="religion_other" format="fb2.0"/> + </subgenre> + <subgenre value="sci_religion"> + <genre-descr lang="en" title="Religious Studies"/> + <genre-descr lang="ru" title="òÅÌÉÇÉÏ×ÅÄÅÎÉÅ"/> + </subgenre> + </subgenres> + </genre> + <genre value="humor"> + <root-descr lang="en" genre-title="Humor" detailed="Prose, Verses, Anecdote"/> + <root-descr lang="ru" genre-title="àÍÏÒ" detailed="ðÒÏÚÁ, ÓÔÉÈÉ, ÁÎÅËÄÏÔÙ"/> + <subgenres> + <subgenre value="humor_anecdote"> + <genre-descr lang="en" title="Anecdote"/> + <genre-descr lang="ru" title="áÎÅËÄÏÔÙ"/> + </subgenre> + <subgenre value="humor_prose"> + <genre-descr lang="en" title="Humor Prose"/> + <genre-descr lang="ru" title="àÍÏÒÉÓÔÉÞÅÓËÁÑ ðÒÏÚÁ"/> + </subgenre> + <subgenre value="humor_verse"> + <genre-descr lang="en" title="Humor Verses"/> + <genre-descr lang="ru" title="àÍÏÒÉÓÔÉÞÅÓËÉÅ óÔÉÈÉ"/> + </subgenre> + <subgenre value="humor"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="family_humor" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> + <genre value="home"> + <root-descr lang="en" genre-title="Home, Family" detailed="Cooking, Pets, Hobby"/> + <root-descr lang="ru" genre-title="äÏÍ, óÅÍØÑ" detailed="ëÕÌÉÎÁÒÉÑ, ÄÏÍÁÛÎÉÅ ÖÉ×ÏÔÎÙÅ, ÈÏÂÂÉ"/> + <subgenres> + <subgenre value="home_cooking"> + <genre-descr lang="en" title="Cooking"/> + <genre-descr lang="ru" title="ëÕÌÉÎÁÒÉÑ"/> + <genre-alt value="cooking" format="fb2.0"/> + <genre-alt value="cook_baking" format="fb2.0"/> + <genre-alt value="cook_can" format="fb2.0"/> + <genre-alt value="cook_art" format="fb2.0"/> + <genre-alt value="cook_drink" format="fb2.0"/> + <genre-alt value="cook_gastronomy" format="fb2.0"/> + <genre-alt value="cook_meals" format="fb2.0"/> + <genre-alt value="cook_natura" format="fb2.0"/> + <genre-alt value="cook_outdoor" format="fb2.0"/> + <genre-alt value="cook_pro" format="fb2.0"/> + <genre-alt value="cook_quick" format="fb2.0"/> + <genre-alt value="cook_ref" format="fb2.0"/> + <genre-alt value="cook_regional" format="fb2.0"/> + <genre-alt value="cook_appliances" format="fb2.0"/> + <genre-alt value="cook_diet" format="fb2.0"/> + <genre-alt value="cook_spec" format="fb2.0"/> + <genre-alt value="cook_veget" format="fb2.0"/> + <genre-alt value="health_diets" format="fb2.0"/> + </subgenre> + <subgenre value="home_pets"> + <genre-descr lang="en" title="Pets"/> + <genre-descr lang="ru" title="äÏÍÁÛÎÉÅ öÉ×ÏÔÎÙÅ"/> + </subgenre> + <subgenre value="home_crafts"> + <genre-descr lang="en" title="Hobbies & Crafts"/> + <genre-descr lang="ru" title="èÏÂÂÉ, òÅÍÅÓÌÁ"/> + <genre-alt value="home_collect" format="fb2.0"/> + <genre-alt value="outdoors_hiking" format="fb2.0"/> + <genre-alt value="outdoors_hunt_fish" format="fb2.0"/> + </subgenre> + <subgenre value="home_entertain"> + <genre-descr lang="en" title="Entertaining"/> + <genre-descr lang="ru" title="òÁÚ×ÌÅÞÅÎÉÑ"/> + <genre-alt value="entertainment" format="fb2.0"/> + <genre-alt value="entert_comics" format="fb2.0"/> + <genre-alt value="entert_games" format="fb2.0"/> + <genre-alt value="entert_humor" format="fb2.0"/> + <genre-alt value="entert_movies" format="fb2.0"/> + <genre-alt value="entert_music" format="fb2.0"/> + <genre-alt value="nonfiction_pop_culture" format="fb2.0"/> + <genre-alt value="entert_radio" format="fb2.0"/> + <genre-alt value="entert_tv" format="fb2.0"/> + </subgenre> + <subgenre value="home_health"> + <genre-descr lang="en" title="Health"/> + <genre-descr lang="ru" title="úÄÏÒÏרÅ"/> + <genre-alt value="health" format="fb2.0"/> + <genre-alt value="health_beauty" format="fb2.0"/> + <genre-alt value="family_health" format="fb2.0"/> + <genre-alt value="family_fertility" format="fb2.0"/> + <genre-alt value="family_parenting" format="fb2.0"/> + <genre-alt value="family_pregnancy" format="fb2.0"/> + <genre-alt value="family_special_needs" format="fb2.0"/> + <genre-alt value="health_death" format="fb2.0"/> + <genre-alt value="health_dideases" format="fb2.0"/> + <genre-alt value="health_fitness" format="fb2.0"/> + <genre-alt value="health_men" format="fb2.0"/> + <genre-alt value="health_nutrition" format="fb2.0"/> + <genre-alt value="health_personal" format="fb2.0"/> + <genre-alt value="health_recovery" format="fb2.0"/> + <genre-alt value="health_ref" format="fb2.0"/> + <genre-alt value="health_first_aid" format="fb2.0"/> + <genre-alt value="health_self_help" format="fb2.0"/> + <genre-alt value="health_women" format="fb2.0"/> + </subgenre> + <subgenre value="home_garden"> + <genre-descr lang="en" title="Garden"/> + <genre-descr lang="ru" title="óÁÄ É ïÇÏÒÏÄ"/> + </subgenre> + <subgenre value="home_diy"> + <genre-descr lang="en" title="Do it yourself"/> + <genre-descr lang="ru" title="óÄÅÌÁÊ óÁÍ"/> + <genre-alt value="home_expert" format="fb2.0"/> + <genre-alt value="home_design" format="fb2.0"/> + <genre-alt value="home_howto" format="fb2.0"/> + <genre-alt value="home_interior_design" format="fb2.0"/> + </subgenre> + <subgenre value="home_sport"> + <genre-descr lang="en" title="Sports"/> + <genre-descr lang="ru" title="óÐÏÒÔ"/> + <genre-alt value="literature_sports" format="fb2.0"/> + <genre-alt value="outdoors_outdoor_recreation" format="fb2.0"/> + <genre-alt value="outdoors_survive" format="fb2.0"/> + <genre-alt value="sport" format="fb2.0"/> + <genre-alt value="teens_health" format="fb2.0"/> + <genre-alt value="teens_school_sports" format="fb2.0"/> + </subgenre> + <subgenre value="home_sex"> + <genre-descr lang="en" title="Erotica, Sex"/> + <genre-descr lang="ru" title="üÒÏÔÉËÁ, óÅËÓ"/> + <genre-alt value="health_sex" format="fb2.0"/> + <genre-alt value="nonfiction_pornography" format="fb2.0"/> + </subgenre> + <subgenre value="home"> + <genre-descr lang="en" title="Other"/> + <genre-descr lang="ru" title="ðÒÏÞÅÅ"/> + <genre-alt value="gay_parenting" format="fb2.0"/> + <genre-alt value="home_cottage" format="fb2.0"/> + <genre-alt value="home_weddings" format="fb2.0"/> + <genre-alt value="family" format="fb2.0"/> + <genre-alt value="family_adoption" format="fb2.0"/> + <genre-alt value="family_aging_parents" format="fb2.0"/> + <genre-alt value="family_edu" format="fb2.0"/> + <genre-alt value="family_activities" format="fb2.0"/> + <genre-alt value="family_relations" format="fb2.0"/> + <genre-alt value="family_lit_guide" format="fb2.0"/> + <genre-alt value="women_divorce" format="fb2.0"/> + <genre-alt value="women_domestic" format="fb2.0"/> + <genre-alt value="women_child" format="fb2.0"/> + <genre-alt value="women_single" format="fb2.0"/> + </subgenre> + </subgenres> + </genre> +</fbgenrestransfer> diff --git a/reader/data/formats/html/html.ent b/reader/data/formats/html/html.ent new file mode 100644 index 0000000..e9f8655 --- /dev/null +++ b/reader/data/formats/html/html.ent @@ -0,0 +1,253 @@ +<htmlEntities> + <entity name="nbsp" number="160"/> + <entity name="iexcl" number="161"/> + <entity name="cent" number="162"/> + <entity name="pound" number="163"/> + <entity name="curren" number="164"/> + <entity name="yen" number="165"/> + <entity name="brvbar" number="166"/> + <entity name="sect" number="167"/> + <entity name="uml" number="168"/> + <entity name="copy" number="169"/> + <entity name="ordf" number="170"/> + <entity name="laquo" number="171"/> + <entity name="not" number="172"/> + <entity name="shy" number="173"/> + <entity name="reg" number="174"/> + <entity name="macr" number="175"/> + <entity name="deg" number="176"/> + <entity name="plusmn" number="177"/> + <entity name="sup2" number="178"/> + <entity name="sup3" number="179"/> + <entity name="acute" number="180"/> + <entity name="micro" number="181"/> + <entity name="para" number="182"/> + <entity name="middot" number="183"/> + <entity name="cedil" number="184"/> + <entity name="sup1" number="185"/> + <entity name="ordm" number="186"/> + <entity name="raquo" number="187"/> + <entity name="frac14" number="188"/> + <entity name="frac12" number="189"/> + <entity name="frac34" number="190"/> + <entity name="iquest" number="191"/> + <entity name="Agrave" number="192"/> + <entity name="Aacute" number="193"/> + <entity name="Acirc" number="194"/> + <entity name="Atilde" number="195"/> + <entity name="Auml" number="196"/> + <entity name="Aring" number="197"/> + <entity name="AElig" number="198"/> + <entity name="Ccedil" number="199"/> + <entity name="Egrave" number="200"/> + <entity name="Eacute" number="201"/> + <entity name="Ecirc" number="202"/> + <entity name="Euml" number="203"/> + <entity name="Igrave" number="204"/> + <entity name="Iacute" number="205"/> + <entity name="Icirc" number="206"/> + <entity name="Iuml" number="207"/> + <entity name="ETH" number="208"/> + <entity name="Ograve" number="210"/> + <entity name="Oacute" number="211"/> + <entity name="Ocirc" number="212"/> + <entity name="Otilde" number="213"/> + <entity name="Ouml" number="214"/> + <entity name="times" number="215"/> + <entity name="Oslash" number="216"/> + <entity name="Ugrave" number="217"/> + <entity name="Uacute" number="218"/> + <entity name="Ucirc" number="219"/> + <entity name="Uuml" number="220"/> + <entity name="Yacute" number="221"/> + <entity name="THORN" number="222"/> + <entity name="szlig" number="223"/> + <entity name="agrave" number="224"/> + <entity name="aacute" number="225"/> + <entity name="acirc" number="226"/> + <entity name="atilde" number="227"/> + <entity name="auml" number="228"/> + <entity name="aring" number="229"/> + <entity name="aelig" number="230"/> + <entity name="ccedil" number="231"/> + <entity name="egrave" number="232"/> + <entity name="eacute" number="233"/> + <entity name="ecirc" number="234"/> + <entity name="euml" number="235"/> + <entity name="igrave" number="236"/> + <entity name="iacute" number="237"/> + <entity name="icirc" number="238"/> + <entity name="iuml" number="239"/> + <entity name="eth" number="240"/> + <entity name="ntilde" number="241"/> + <entity name="ograve" number="242"/> + <entity name="oacute" number="243"/> + <entity name="ocirc" number="244"/> + <entity name="otilde" number="245"/> + <entity name="ouml" number="246"/> + <entity name="divide" number="247"/> + <entity name="oslash" number="248"/> + <entity name="ugrave" number="249"/> + <entity name="uacute" number="250"/> + <entity name="ucirc" number="251"/> + <entity name="uuml" number="252"/> + <entity name="yacute" number="253"/> + <entity name="thorn" number="254"/> + <entity name="yuml" number="255"/> + <entity name="quot" number="34"/> + <entity name="amp" number="38"/> + <entity name="lt" number="60"/> + <entity name="gt" number="62"/> + <entity name="OElig" number="338"/> + <entity name="oelig" number="339"/> + <entity name="Scaron" number="352"/> + <entity name="scaron" number="353"/> + <entity name="Yuml" number="376"/> + <entity name="circ" number="710"/> + <entity name="tilde" number="732"/> + <entity name="ensp" number="8194"/> + <entity name="emsp" number="8195"/> + <entity name="thinsp" number="8201"/> + <entity name="zwnj" number="8204"/> + <entity name="zwj" number="8205"/> + <entity name="lrm" number="8206"/> + <entity name="rlm" number="8207"/> + <entity name="ndash" number="8211"/> + <entity name="mdash" number="8212"/> + <entity name="lsquo" number="8216"/> + <entity name="rsquo" number="8217"/> + <entity name="sbquo" number="8218"/> + <entity name="ldquo" number="8220"/> + <entity name="rdquo" number="8221"/> + <entity name="bdquo" number="8222"/> + <entity name="dagger" number="8224"/> + <entity name="Dagger" number="8225"/> + <entity name="permil" number="8240"/> + <entity name="lsaquo" number="8249"/> + <entity name="rsaquo" number="8250"/> + <entity name="euro" number="8364"/> + <entity name="fnof" number="402"/> + <entity name="Alpha" number="913"/> + <entity name="Beta" number="914"/> + <entity name="Gamma" number="915"/> + <entity name="Delta" number="916"/> + <entity name="Epsilon" number="917"/> + <entity name="Zeta" number="918"/> + <entity name="Eta" number="919"/> + <entity name="Theta" number="920"/> + <entity name="Iota" number="921"/> + <entity name="Kappa" number="922"/> + <entity name="Lambda" number="923"/> + <entity name="Mu" number="924"/> + <entity name="Nu" number="925"/> + <entity name="Xi" number="926"/> + <entity name="Omicron" number="927"/> + <entity name="Pi" number="928"/> + <entity name="Rho" number="929"/> + <entity name="Sigma" number="931"/> + <entity name="Tau" number="932"/> + <entity name="Upsilon" number="933"/> + <entity name="Phi" number="934"/> + <entity name="Chi" number="935"/> + <entity name="Psi" number="936"/> + <entity name="Omega" number="937"/> + <entity name="alpha" number="945"/> + <entity name="beta" number="946"/> + <entity name="gamma" number="947"/> + <entity name="delta" number="948"/> + <entity name="epsilon" number="949"/> + <entity name="zeta" number="950"/> + <entity name="eta" number="951"/> + <entity name="theta" number="952"/> + <entity name="iota" number="953"/> + <entity name="kappa" number="954"/> + <entity name="lambda" number="955"/> + <entity name="mu" number="956"/> + <entity name="nu" number="957"/> + <entity name="xi" number="958"/> + <entity name="omicron" number="959"/> + <entity name="pi" number="960"/> + <entity name="rho" number="961"/> + <entity name="sigmaf" number="962"/> + <entity name="sigma" number="963"/> + <entity name="tau" number="964"/> + <entity name="upsilon" number="965"/> + <entity name="phi" number="966"/> + <entity name="chi" number="967"/> + <entity name="psi" number="968"/> + <entity name="omega" number="969"/> + <entity name="thetasym" number="977"/> + <entity name="upsih" number="978"/> + <entity name="piv" number="982"/> + <entity name="bull" number="8226"/> + <entity name="hellip" number="8230"/> + <entity name="prime" number="8242"/> + <entity name="Prime" number="8243"/> + <entity name="oline" number="8254"/> + <entity name="frasl" number="8260"/> + <entity name="weierp" number="8472"/> + <entity name="image" number="8465"/> + <entity name="real" number="8476"/> + <entity name="trade" number="8482"/> + <entity name="alefsym" number="8501"/> + <entity name="larr" number="8592"/> + <entity name="uarr" number="8593"/> + <entity name="rarr" number="8594"/> + <entity name="darr" number="8595"/> + <entity name="harr" number="8596"/> + <entity name="crarr" number="8629"/> + <entity name="lArr" number="8656"/> + <entity name="uArr" number="8657"/> + <entity name="rArr" number="8658"/> + <entity name="dArr" number="8659"/> + <entity name="hArr" number="8660"/> + <entity name="forall" number="8704"/> + <entity name="part" number="8706"/> + <entity name="exist" number="8707"/> + <entity name="empty" number="8709"/> + <entity name="nabla" number="8711"/> + <entity name="isin" number="8712"/> + <entity name="notin" number="8713"/> + <entity name="ni" number="8715"/> + <entity name="prod" number="8719"/> + <entity name="sum" number="8721"/> + <entity name="minus" number="8722"/> + <entity name="lowast" number="8727"/> + <entity name="radic" number="8730"/> + <entity name="prop" number="8733"/> + <entity name="infin" number="8734"/> + <entity name="ang" number="8736"/> + <entity name="and" number="8743"/> + <entity name="or" number="8744"/> + <entity name="cap" number="8745"/> + <entity name="cup" number="8746"/> + <entity name="int" number="8747"/> + <entity name="there4" number="8756"/> + <entity name="sim" number="8764"/> + <entity name="cong" number="8773"/> + <entity name="asymp" number="8776"/> + <entity name="ne" number="8800"/> + <entity name="equiv" number="8801"/> + <entity name="le" number="8804"/> + <entity name="ge" number="8805"/> + <entity name="sub" number="8834"/> + <entity name="sup" number="8835"/> + <entity name="nsub" number="8836"/> + <entity name="sube" number="8838"/> + <entity name="supe" number="8839"/> + <entity name="oplus" number="8853"/> + <entity name="otimes" number="8855"/> + <entity name="perp" number="8869"/> + <entity name="sdot" number="8901"/> + <entity name="lceil" number="8968"/> + <entity name="rceil" number="8969"/> + <entity name="lfloor" number="8970"/> + <entity name="rfloor" number="8971"/> + <entity name="lang" number="9001"/> + <entity name="rang" number="9002"/> + <entity name="loz" number="9674"/> + <entity name="spades" number="9824"/> + <entity name="clubs" number="9827"/> + <entity name="hearts" number="9829"/> + <entity name="diams" number="9830"/> +</htmlEntities> diff --git a/reader/data/help/MiniHelp.desktop.bg.fb2 b/reader/data/help/MiniHelp.desktop.bg.fb2 new file mode 100644 index 0000000..12d046c --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.bg.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>ОтноÑно Reader</book-title> <lang>bg</lang></title-info></description> +<body> +<title><p>ОтноÑно Reader &ReaderVersion;</p></title> +<p>Reader е програма за четене на електронни книги на PDA/UMPC/PC и операционни ÑиÑтеми Linux и Windows XP. Reader поддържа нÑколко формата за електронни книги: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, и други. Поддържа Ñъщо и директно четене от Ñледните архиви: <code>zip</code>, <code>tar</code>, <code>gzip</code> и <code>bzip2</code>.</p> +<p>Reader Ñе разпроÑтранÑва Ñвободно под лицензa <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<p>Ðко хареÑвате програмата и бихте желали да подкрепите нейното развитие, Ð¼Ð¾Ð»Ñ <a l:href="http://www.fbreader.org/donation/make.php">направете дарение</a>.</p> +<empty-line /> +<subtitle><p>Как да започнете</p></subtitle> +<p>Reader Ñледи за книги във формат <code>ePub</code>, <code>fb2</code> и <code>OpenReader</code> в папките, зададени в наÑтойките на <code>Папка за Ñъхранение на книгите</code>. Първо трÑбва да наÑтроите тези папки. Отворете наÑтройките (проÑто кликнете на <image l:href="#settings.png" voffset="-6" /> в лентата Ñ Ð¸Ð½Ñтрументи) и променете Ð¿ÑŠÑ‚Ñ Ð² наÑтройката <code>Папка за Ñъхранение на книгите</code> в раздела <code>Библиотека</code>. Тази наÑтройка Ñъдържа ÑпиÑъка Ñ Ð¿Ð°Ð¿ÐºÐ¸ Ñъдржащи <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> или файлове архиви. Папките в ÑпиÑъка Ñа разделени Ñ Ð´Ð²Ð¾ÐµÑ‚Ð¾Ñ‡Ð¸Ñ.</p> +<p>Отворете <code>Библиотека</code> (кликнете на <image l:href="#books.png" voffset="-6" />), изберете книга от ÑпиÑъка и започнете да четете.</p> +<p>За да четете файл в друг формат, трÑбва го добавите в библиотеката. Кликнете на <code>ДобавÑне на файл в библиотеката</code> (<image l:href="#addbook.png" />), изберете файл и редактирайте информациÑта на файла. Ð¡Ð»ÐµÐ´Ð²Ð°Ñ‰Ð¸Ñ Ð¿ÑŠÑ‚ може да отворите този файл използвайки <code>Библиотека</code> (<image l:href="#books.png" voffset="-6" />).</p> +<empty-line /> +<subtitle><p>Свързани Ñайтове</p></subtitle> +<p>Повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° тази програма може да намерите на <a l:href="http://www.fbreader.org">домашната Ñтраница на Reader</a>.</p> +<p>Ðко желаете да бъдете уведомÑвани за нови верÑии, Ð¼Ð¾Ð»Ñ Ð°Ð±Ð¾Ð½Ð¸Ñ€Ð°Ð¹Ñ‚Ðµ Ñе на <a l:href="http://freshmeat.net/projects/fbreader">проекта Reader на freshmeat</a>.</p> +<p>Ðко имате нÑкакви въпроÑи или предложениÑ, Ð¼Ð¾Ð»Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ð¹Ñ‚Ðµ <a l:href="http://groups.google.com/group/fbreader">групата на Reader в googlegroups</a>.</p> +</body> +<binary id="settings.png" content-type="image/png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary id="books.png" content-type="image/png"> +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 +==== +</binary> +<binary id="addbook.png" content-type="image/png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwUYkGhT +VwAACFpJREFUWMOtl0mMnVeZhp8z/PMd69at0RU7cdmJHRwldhoMLJgUETCI +VjdNN0IsWIAEEkJCAsECBGKBRLOjV91qNYEgEIhByIJuIYQUhZBBmIDJ4MR2 +OXZVuQbXcO9/7/3Hcw6LRqyCKMDf+nyvHr36zvudIzhg/T69KAeNQStJk9SK +6uG0GC1vDG+du7a++tCVyyvMT8//8PSpB758V2fuxdl4IZ/xZquD6IqDAnzi +qU+8+yn12w+v1NffoazUU1GHkwvHOdJY4OmfPsnVi5cxmeN0dCb/6Hs/fvc7 +T73j+kF09YEdMM/9+En7GESWJIppxxoRl4SBwJqCShjK0HFp7+XQBrZxUF15 +0IPGVBBaVArxQNDci5gZz3JMnmDaLOKbDrVNqOOaXOTmtgMkpkGiu5gF2I4K +brqMAocnfChLRJ0T+RbjWXJT3n6AurND4GrEEKhrcrXFnthB08ZzfZSLUdrh +lT4zVbs+qO6BZ8CXEW6ocbHADxWTfMLm7gb5TE6326WXzDDxRsTLmuvt9frr +N34QD9Jhcbw9S7+1RDuYdsf8OXsggH//1ddcJXbYU1vE4hBCOH40eoTS1JA7 +rG8xypLqlJqK1507y4NvexACy0r6G9aClZVBuapmkkV25Ygv/c8nmY1muPDi +L06fvuctz/5FgP+69B+M/A2qZEKUHCIsfNZaL5GHGl/4lEVJrUte3H+eb6z9 +N71ihsXeIcgdvSnBOqu6jhKO1wsc8ae4tHqRVd1i895z0YEcWBEvUwUWAhDR +dQKjqT1ASlzhECGICDI/50L2NJFJWLKHUEKxMO5TJZamhDLdpdM7wXR7jkpH +bFaVOxCAlh5WFjACIwzCBoSFpDKaWhd4yqM0FQjYD1L2q5SN0QaNRsy1okdu +BEveHZyI72BCxTBVFGGE7XXkgQCcM0RO4FUBe7VFaw9TTDBU+E0PIQR1ZbDS +ggUUOAvjesJYTLBlRFUqVjsbrLNNJ1mkIIKiOtgQmrjGCgikBjGmUA4jQTUN +NY5qUuNHAdrXZPkEFSqEL7GlBVnjhYbaZOyKHVaHN4hFTNu2aL9KPLwqwIn0 +FDfNKqPuPr1Ri67sc7l7GSMs0dhiOh5l6GCY8Yb4QY5693PTbHJVvkDQrlit +hmgk49pyRdXshBkLdZ+Rtyj+5mV03xNn3O/qizRCyYgKQsnhYJb3HXsv8U6f +377yHOtqhSBXhNMN0nFGkk9xZ3jmSvWK97M3z7/u1w/fc/aR+VZY/U1BJIyG +oKJCgdIgPALn03AJN369zqVfXWXi7RLKO/j8+z7wrx+4/4Pf/f/OHwLwyN+b +hM08I7aOiVeD7xASBukuWztbbNwcItKYVqOBsdPMVkd/cNujWIYhToKnocLg +hGGiarbYZhAIZKeLcQKnayxG3vZldEumZAnoGpgAFdjQsFFtsSNT8khRighf +G8bU0W13oJn5ZUvja9UAT5ExxljD5s4WZTVLpCN8r02rgJ9fXXv0i088U4U2 +2u62Y6a74cWuUuWC374URMHIVNX1o21/+0+34Oq1FVkURVDXtbtyU+oX/A2X +pv3wxZu3VLFTBM1m2v3O6NPn6a0sEQG9CMICEVmW7GHUS4fRK4cotyUuG9O7 +5yxHDv0DnZFHIismwQR0zbSfQDnBVzDfbn/v6MLcR8Q/feWRzwyj7mKhdGcy +GfWSIpiSykxVpu4JnXQslZTJOhde+k8y8SxCgpdFqMRjEg+hhuTWEmZtCmxI +JWLuO/12mr0TVDpBBgItSgKhEKWgU62zNYLcauZU/oy+q99++OXd0ZtaQYhO +FNuNEqksGIMShrq2WGUQQoCRWGkpPYerC8j/aGIZIEwTQQNPVPhYQuXAFti8 +AmnQ2kdZQX/pLg5PL1GVMLn+wnH91Q/945u/8Oj581NTnXPtRkBsHE7DyDjS +WrOWptzM9rgetdkcN8kZoEKPujYgJRQx2b5B5R5+Mo3WA6rKkGcpRSWRytHt +tjh6+BDzvT5b44yd4YRrl68QDzYiDXBnolnsBrRDxWzpkJFH7YWUcZeJ0qTB +Ud50qkVqXuHx8gmqQc211TU2x7fItwpMV+B3A8rApydOMiw11WBCrz/Pwtwc +zdgnG2U8v/k8q2nBYD9luLXBfTMNXwD832NPnT+8MHOuGylsSyGlxDmBFjFK +hiShJqs2QaZQLeFMzdjmTDBkgzGTtYzfX8k5/8wVbswLxuMxWvo0ojYaQZWN +cOWIQDu294b02i1mW5E9Ndf5rAYYW499owlUDOMcTwqEA0GBcCUm8/CtQriI +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.cs.fb2 b/reader/data/help/MiniHelp.desktop.cs.fb2 new file mode 100644 index 0000000..ab246e2 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.cs.fb2 @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>About programu Reader</book-title> <lang>cs</lang></title-info></description> +<body> +<title><p>O programu Reader &ReaderVersion;</p></title> +<p>Reader je program pro Ätenà elektronických knih, který pracuje pod Linuxem/Windows XP PDA/UMPC/PC. Reader podporuje následujÃcà formáty: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, atd. Zvládne též pÅ™Ãmé Ätenà archivů <code>zip</code>, <code>tar</code>, <code>gzip</code> and <code>bzip2</code>.</p> +<p>Reader je Å¡ÃÅ™en pod licencà <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<p>Máte-li zájem o tento program a chcete-li podpoÅ™it jeho vývoj, navÅ¡tivte prosÃm <a l:href="http://www.fbreader.org/donation/make.php">stránku pÅ™ÃspÄ›vků</a>.</p> +<empty-line/> +<subtitle><p>Jak zaÄÃt</p></subtitle> +<p>Reader hledá knihy ve formátech <code>ePub</code>, <code>fb2</code> a <code>OpenReader</code> v cestÄ› zadaných v parametru <code>Složka s knihami</code>. Nejprve nastavte tento parametr. OtevÅ™ete dialog s nastavenÃm (kliknutÃm na položku <image l:href="#settings.png" voffset="-6"/> v panelu nástrojů) a změňte hodnotu parametru <code>Složka s knihami</code> v záložce <code>Knihovna</code>. Uvedený parametr obsahuje seznam adresářů se soubory <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> nebo soubory archivů. Adresáře jsou v seznamu zaÅ™azeny do oddÄ›lených sloupců.</p> +<p>OtevÅ™ete <code>knihovnu</code> (kliknutÃm na <image l:href="#books.png" voffset="-6"/>), vyberte knihu, kterou chcete ÄÃst ze seznamu.</p> + +<p>Pro Ätenà souboru v jiném formátu je nezbytné jeho zaÅ™azenà do knihovny. ZaÄnÄ›te <code>vloženÃm knihy do knihovny.</code> (<image l:href="#addbook.png"/>). Vyberte soubor s knihou a založte informace (metadata), které ji charakterizujÃ. Po zaÅ™azenà už soubor otevÃrejte výhradnÄ› pomocà <code>knihovny</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Odkazy</p></subtitle> +<p>VÃce informacà o programu najdete na <a l:href="http://www.fbreader.org">Domovské stránce programu Reader</a>.</p> +<p>Pro upozornÄ›nà na nové verze se prosÃm pÅ™ihlaste <a l:href="http://freshmeat.net/projects/fbreader">Reader projekt na freshmeatu</a>.</p> +<p>Pro vaÅ¡e otázky a návrhy použijte prosÃm <a l:href="http://groups.google.com/group/fbreader">skupinu vÄ›novanou programu Reader na googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.de.fb2 b/reader/data/help/MiniHelp.desktop.de.fb2 new file mode 100644 index 0000000..07852f1 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.de.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Über Reader</book-title> <lang>de</lang></title-info></description>
+<body>
+<title><p>Über Reader &ReaderVersion;</p></title>
+<p>Reader ist ein Leseprogramm für E-Books für Linux/Windows XP bzw PDA/UMPC/Desktop Computer. Reader unterstützt verschiedene Formate: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, usw. Er kann diese auch direkt aus <code>zip</code>, <code>tar</code>, <code>gzip</code> und <code>bzip2</code> - Archiven lesen.</p>
+<p>Reader wird unter den Bedingungen der <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a> vertrieben.</p>
+<p>Wenn Sie das Programm mögen und die Weiterentwicklung unterstützen wollen, besuchen Sie bitte die <a l:href="http://www.fbreader.org/donation/make.php">Make Donation</a> - Seite.</p>
+<empty-line/>
+<subtitle><p>Die ersten Schritte</p></subtitle>
+<p>Reader sucht im <code>E-Book Verzeichnis</code> nach <code>ePub</code>, <code>fb2</code> und <code>OpenReader</code> Büchern. Zuerst müssen Sie daher diesen Pfad setzen. Öffnen Sie dazu die Einstellungen (einfach auf <image l:href="#settings.png" voffset="-6"/> in der Symbolleiste klicken) und ändern Sie den Inhalt der Option <code>E-Book Verzeichnis</code>, die sich im Reiter <code>Bibliothek</code> befindet. Es können mehrere Verzeichnisse eingetragen werden, die <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> oder Archivdateien enthalten, getrennt durch Colons.</p>
+<p>Öffnen Sie nun die <code>Bibliothek</code> (auf <image l:href="#books.png" voffset="-6"/> klicken), wählen Sie ein Buch aus der Liste aus und schon können Sie es lesen.</p>
+<p>Um eine Datei in einem anderen Format zu lesen, müssen Sie diese der Bibliothek hinzufügen. Öffnen Sie <code>Datei zur Bibliothek hinzufügen</code> (<image l:href="#addbook.png"/>), wählen Sie eine Datei aus und editieren Sie die Datei-Informationen. Beim nächsten Mal können Sie diese Datei einfach in der <code>Bibliothek</code> (<image l:href="#books.png" voffset="-6"/>) öffnen.</p>
+<empty-line/>
+<subtitle><p>Verwandte Internetseiten</p></subtitle>
+<p>Weitere Informationen über dieses Programm finden Sie auf der <a l:href="http://www.fbreader.org">Reader Homepage</a>.</p>
+<p>Wenn Sie über neue Releases informiert werden wollen, tragen Sie sich bitte bei <a l:href="http://freshmeat.net/projects/fbreader">Reader project at freshmeat</a> ein.</p>
+<p>Falls Sie Fragen oder Anregungen haben, benutzen Sie bitte die <a l:href="http://groups.google.com/group/fbreader">Reader group at googlegroups</a>.</p>
+</body>
+<binary content-type="image/png" id="settings.png">
+iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/
+AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFiIVNd73
+uAAACXNJREFUWMO1l2mMndV5x3/nPe9617l37szYM+OVMXbGGHATO6ZesA04
+JjQqNBtKgWwKigNlcZUUukREDUIKJU1oVUSkqIkVURwsI4PsELCJwQFDvWMb
+jBnPeGYym5eZuXOX977bOf3QUiEZV5i2z5dzpOf/6Pw+PHrO/xFcQuzsf+H1
+3f42e/jM2e7yVOC1F+awsHmRv2b2qj+d785/iY8R4qMKh2u9LZt6fnVm0+hj
+JNqkUJhBTk5n4LVBVk1bFn5j5W23Lmtf/eylAhgfVVixJrr2T75BNQUqaxOL
+iM5ZreRnOmw59G/23/3mwWeeGP7R7f9vAHU5NafP78PzpiGTLNK3KEqPfMaE
+tpjDyWH593se2fTEKz/dcCkA5kcVvn56/xzHFgSNEGkLIGKiNsXSq1dwdN9J
+lBFCOuLRsUf+5Z97Hi+ubL3ulcHg1Iod1WfmrOSGvuuyNz7RWmop/48A23uf
+W/HbY9sXlUqlw9//44f3fjB3Ohy6pmpHGK7Gsi1Qmpqq4BZnM7t7Fsf6DxNW
+oRhY7Ozf8cNTzjscyb7OdaWbeGPwFcaHxm8frg6tbs90nP3QJnxt8tVr/vHA
+w7sPnH3bTlREWqRo1dOH5pUWjBpZ6b3VONQ9lh3BkwJhakxh0uK0cuXsxYwN
+j3DovQM0nDptC1qZZnbQn36P9spM8m6Otan1nJw8wblna/9+9/X3r148c7H/
+/rvy/UvLuvw9z1V/varuxERpH9+tMWVM5qaMyfaRZLjlrDGG2WxgSUEiI6Rr
+oEVCpTaFcAVWUZLtTFMrljnnjtI20YllmzRMnxE1xGJvGft79ncMnjvd/ebT
++zdf0ISRDpNYRGS0R0Z4ZFwXO6OomGeom2exUzGmjhAaHMdB2wrtKSaCcSaC
+c+i0xvCg0CjRHs6g4BYpZ8eZtCeYzkw+Zaxg7vQutv3h6Vv+6rV777wAYGX3
+6p9Pq3eGZsNETwlETSC1gWFoLFdgW5KkGmApB9v0ULEGCdliFukaCFOjpMI0
+TWZMdDEkTyNDiyv0Er5ib2Bf401e6n2RKWeSPW/t/toFALdM/1LPZ0t/9uPQ
+Usi0jeOlsR0PLQWNKEQaDvlUCUd50FDY0gItkFIixH+dWoCpGMj00BJPJ21n
++KL8Kk9sf5x/+Nmj9GX7aJYtfGrup3/xoZPwrfKRzLqD6/qJkyKxIuWaSFuC
+AZZlY0kbNRFTpkxbVwnLMZGxRGKQbU1T11VkzcRoUph4zE+uov9cP3u3HkRr
+TZjzuYqFm3fd/satFx3FXz/85RcP9Ry6wU818GUN05Y0Z5tRkxEnDvYgT3no
+aTEVFdH+ifwLS25Y7JZT46sTmZAVeXy7gq/r5MIC1lCK/VsOkbGyVGUZUVJD
+v12xb+FVs64oX3QS9lV68xU5RWD4mJ5FNp1jfHCCngN9NIZAKEGlHpGaFM9/
+t/TQnRu8BzZ0BrN+j4yRiaBarjNbdJFrFCjXJ6m2VRiUw8jI4pt/tOG+Dz5+
+AcCBscOLBmt9S3U+IbYjGmEdERsE5wPC0YQWmcMpGngmLClds+X+dfcPrs+s
+P9HFgq1u7BIZDTrznVQnaxRSzSy6fBH5VAYjgoLTRG3MH7/oX/Do0Ue6v7/j
+wd/U/DqKBGkKhBAEQUClUiMIQMeas7qKFzgsvWzpy+/Xzst3vdwUNdFwKlRU
+lTDn8we/n4Jd5Luf+1tuvuxmRvvPsqf/d5tePLnt2gsAPr/jxh/908EfH99n
+/74jK3PEUxrVAMdywNBYKYN8m4VKKbABQyHlf88wkki9o9R/NpQvKsRGjMwJ
+huvDSBe+dfO3uGvD3YwOjHY8+PRDuzZuv++He8qvSgB5x5YvfeXV8y8/5rfW
+SYox2WoGhMZ0LEIVYQhBc66Z6aVpBI2ArGdRs+sUdMuRd3a8ewRgyX2Lr3jH
+OvJtqSwSCyzl4OAwGY3TG77LGXuY+YUF3LrqNp4f3G4c7Du46kTPiaX3bLxn
+q5EpZD9peS4oA1WRVBoVMAWGZaB1Agl4TorpLR3M6ZxDLluEvOBY460vbN77
+zAyAIWtgbWCFqEBiBQ7ChyiKSFIBQabG8dphdk/t5PWp3dxy22dw5mn29O5c
+v/vYznvNjJdLXOVRn4pocrPIpgahCEgCH8uxsYRFWA1pnd3GmvVreP7AdsLz
+IcOj/Z/73tt3NW48eu3vTsYnvqi0AEvjxinqokJsh8jYICcKRCJmPDdML2/T
+FrQSOJM0zUyRbU0hH/ibBwdS5OckAZUoikZSDTcXJrGt0prE0YSRwrQdGkaI
+KgraO9pwcg5WkyQ/L71QFcObIoIZtmkRqxihYlKGgFgRS5c4NPASG60VdVMT
+mYqju4fonOjkG1d/+4EP9YT3Hrxz6fb3nttWz1enua5L2sxCoPA8D09mUWZE
+YARYWYmyEkIdkE6nMU2TQAtM0SBxEpTnoquKVulRiyYIcgp1PM3I3jOszK19
++Zdffuq6i5rS5b+68oHR/NAjsRuTdly01pgWEKewUybKBtMFLAMhNK7tIYRB
+wc5Rq56hInwC00ZNGSzrvPqlyclyX9VOmH2iM5xbnLd3+Yxrn12WX+5f1JIV
+0qWeMXsMP64jhIFjmSjDwEwLYqmIVUgUC1zTRQoTFWmkEAzGISePn6JyPoIG
+XB7M2fvk3ZvXXbInPBdPtpRVDdO2sUWWuBEThBGm5yMtiekIhBaoWBEmIUJK
+crk0ncPNjPVILCNCiDzGZKbvY7nikejM1XUdIHCgITGVi2enkZGJTAxEbKIi
+iANFEoJKNI7t0VLoRqkcwktBVlLV5/MfC0Da8TWuKdHVkKgSIqKEeq1MUtXQ
+sDBCSVxNSBoKoQVJmOD7AfOdEs3KxEpCIrNKVExaLhngod3fywgVdsskwYw1
+OctFEjEwOMHI6dEBf6LeJxITlETHmjhW+L5PpVKmng1opENqZkxkJLSVWocu
+GaDUMiNfkO2yUouoFMuM6CGCfuGv4/o7an+RzOr7/Ojcxy/7+XfmxZdzPhom
+cCZQ0qcancfNVFGWoins4Kb0HQMPL3/yLz/Wbrip9xcbtx3Z8oMz5ZHM3OL8
+d9d2rfvzr3Z/7cAHNT849tc/2Tr61L1TqSlcK40KFNfOvp53dx1nbeeap/5k
+4We/88lpa8r8b2L/8JszL5Y7VNtv37fvrl1dWzv0ghfm6lW7VuiNRzf2/uvx
+J9f/n2/HF13ZB17K//rUU4/JlLnoypYlm5fnrvrZlaVPVz9q/X8A8yhCVXd4
+BFAAAAAASUVORK5CYII=
+====
+</binary>
+<binary content-type="image/png" id="books.png">
+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
+====
+</binary>
+<binary content-type="image/png" id="addbook.png">
+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
+UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY
+YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU
+jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF
+z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki
+UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu
+/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn
+90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH
+jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit
+4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9
+/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu
+QmCC
+====
+</binary>
+</FictionBook>
diff --git a/reader/data/help/MiniHelp.desktop.en.fb2 b/reader/data/help/MiniHelp.desktop.en.fb2 new file mode 100644 index 0000000..841ed12 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.en.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>About Reader</book-title> <lang>en</lang></title-info></description> +<body> +<title><p>About Reader &ReaderVersion;</p></title> +<p>Reader is an e-book reader for Linux/Windows XP PDA/UMPC/desktop computer. Reader supports several e-book formats: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. Direct reading from <code>zip</code>, <code>tar</code>, <code>gzip</code> and <code>bzip2</code> archives is also supported.</p> +<p>Reader is distributed under the terms of the <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<p>If you like the program and would like to support its development, please visit <a l:href="http://www.fbreader.org/donation/make.php">make donation</a> page.</p> +<empty-line/> +<subtitle><p>How To Start</p></subtitle> +<p>Reader looks for <code>ePub</code>, <code>fb2</code> and <code>OpenReader</code> books in directories listed in the <code>Book Path</code> option. First of all you need to set this path. Open the options dialog (just click on <image l:href="#settings.png" voffset="-6"/> in the toolbar) and change the value of <code>Book Path</code> option in the <code>Library</code> tab. This option contains the list of directories containing <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> or archive files. Directories in the list are separated by colons.</p> +<p>Open <code>library</code> (click on <image l:href="#books.png" voffset="-6"/>), select a book from the list and read it.</p> +<p>To read a file in another format, you need to add it to the library. Start <code>add to library dialog</code> (<image l:href="#addbook.png"/>), select a file and edit the file information. Next time you can open this file using <code>library</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Related sites</p></subtitle> +<p>More information about this program can be found at <a l:href="http://www.fbreader.org">Reader homepage</a>.</p> +<p>If you want to be notified about new releases, please subscribe to <a l:href="http://freshmeat.net/projects/fbreader">Reader project at freshmeat</a>.</p> +<p>If you have any questions or suggestions, please use <a l:href="http://groups.google.com/group/fbreader">Reader group at googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwIdr0Mx +HwAACg1JREFUWMPFl1uopedZx3/v6Tuubx33mn2c2ZNMMulkstudZBwDNqUp +o21i8bYXVa/sRa+KdxW8KAFrJSAEggWxII221KYXNWolxdBIQxqa1Exm2jl1 +9sweZ58P67DX+s7f93qxixAEISL63j8vP57D//k/8P/8xIcNeOv+3UcH46OV +v1nrr1xf31zZTYvVw2l8qsxzIkqCbDw51Wu9+MefffCFZx/7yOh/DPDmlu3e +3RqsvntnfeX9zb2Vtbhc3bVmdaKMAoXwLHYyxTgOMi/ouiHZaAJJjs1KVmY2 +RhcfOvvCp86de/G51eXJfwvwt7+IV9++u7ny3r31lXs7GytW2JX16NQiFqiA +yoKQeI5PM2zRCAKeUNeYb4cst0NaRlMUku+99iZDIm5tD1ChoeNpzva7hxfP +LH7tqTNLX3/u3Nx/ARGf+Mpfv3P5SD856SxQuT4idPF8zTPEdALDYtNhOVLM +uxkndE5LFniipBAPMRNI/GqI7zusxzlf+vq3iJcf5/1Bxv4AMJZWJFlsKs6E +au/xdvgnn3zw9F9+6uJHkg9k4LVXvmvboUecJFjXR/kejg4JXI8g8PB9F+NI +HKNQSiClRFU+A1vSDSNG2ZDad/mzL3yVNz/9NOMbBbfjlEIbgvkFrDH0mj4n +fYdGerR9tt97/rOz5hvPPnkq1wCPXrhAWlbMCAclDJHXJOz6v2K0IAXWVhRF +QZJOSbIMlU2I64xk+9/JiXHDFnWSICYVrm1Q7N4EP6Qwls7SAu2wifIlqbBz +P9u6+RdV3Pjyq7e2/kgDbCdj0vEEv9aYtET6DXZ2M4QQSO3gBT6O56Mdg5QK +P3AJpKKlXVwXVNBmOE5onWjjC8u0jqGjQQqKvfvsxmNGOy3Onl7m6QsfI3Q1 +3/zBP5yqAueLGoDNAZ3AIRdTymZF0oF5r4+UGuU4oDSFhbICIQSOY7Clzyge +YiufYVyzdnuD7Xab2rO4nZwLYhHpBWxPYkZVxWhnnys721zduIMVFRQ+P3rn +OhrgzuYhnWaH6eQIpQoCb8qbFEipkcpgpSLLS6ZJSmVBKsORcRlMpxRoto2g +3szY1gtsbIxgOGYhipCi4mSkOOO1cNx54jRhOJ6QFTkbzRmm9+6gn/nT79rf +/7cJVatBQYQjQOQZSt4mz3Oq0h53ghXYogAEwhj8IsZWUFaaImhwupphUmv2 +r9yF8T57t69ifI+o3yOY6dGaX0A2QjQ13V4Xt6yZbTXRprxNtb9LftBACY1M +E+x4hBe0kVlGVZRoCbKy1FWJlgrfcdmpBwR1hgek3Q7BpMOBZ4iUoG5FOOfO +oR1N7TrspAl3r11DVOBLh07Uwl9e5uITj5Ti6lqy8Oq/vL1Ra42QKdIOUSRk +lcA1mmYjpBOGGAF1keFpRej5nOguEuZDXBVzRxW8+713een6TY5w2djZBnUG +HIUODTp0EEIQaAenVqTjmLbe56tf+sJv6cce9DdvXLuOEgITupSuIrUFzbim +LEustZRlSVEUGGMwxlAUBY4RZJXAD7uckYLJx5+gcfkK/YdX2BhrSCuUdKlq +g6RFe24R2WgySnLidspge40XvvXDz2iASlsqKpxS0MHgWqDbpa5rjDEopajr ++li5hKAsS0odUMcNqnSCFJq5pdNEjR4WF1f7WJOQT/chUVhVY9KQfr/DI4uL +SMfljX++w+Bw/6IGGMWKJE1R2Zi5oEHLNdTFLnVdH6verwCEOFZBay2pCWm4 +mrKyKCnASsbDMVG/ot/pcri7Rh4PwVqKcsrG3iYbV94B7UFVQhCyO7h3PIYn +vIig3aO2OUFoQBQUpovvOzjmg8sjzSCOE5zRFlUO2XSCEzQo8gKpLM3Io1tW +2LqHNJosKxBCQH2cPS0tQmkKVdPy9DHAKDtklEuydEo4lShZk03uEEURjuNg +rcVxHMIwPP4kz+i1+2RpjK8dcD2GW3cJGi7tnk+bksOJS292HmHBVZrA83Gk +QlowxmB9ycW5J9FffvmV3/vKD98iqyU9z+ex2XlORi1McUA3s4RhiNaaAIdY +1VRVRZpm3N07JEtifFdTq5z3bt8jE4o4S6nqnJl2m2YjwnUcXCUJjKEsCvJ4 +ipSS7YNNHvv4CvqN99e/eWtak0qXsE7517fuUezvkTZ9jDHUdf2BZrTWIqXk +3EJIlaVERtNtRkziDKe9xGBYMhpmLHYisumAwfaI6WjIaHDI0WBAXeY4WqGi +JpcXmujZoy2ODgt2pzVITZYn5OmE0REgBFgLjoNxHKqqwlqL7/u8njXRSuIW +BZHcR5cWKQ37v9gijhPWsvtURUan1WSm16YfSGa9JlEjIAwDYhOxsX7n2A98 +/zvfXi/z6hRC0ej1GY2PmKSCCsvhZMJgOiUpSwZpwv5wRJwmTA9rtg72KKgw +tcRYgeP5JFpS+S4zyQG+71PXx2XzfZ9ut8v8/DwLCws0WzO8/oO//7EGiMIG +jX6I74ekRcnCiT6t0EMbQ1Fb0roEbaiEpKhragEcJYyzBCsFRVKwc3+XH//k +J2xOjljb2yZonqAsS5SjcLTGdV2cICJOCq5cvc7a7dvYZHQ8BUHQIHB9XEfT +CDxarSZVndFoODiehxAKxLEWVPZ4OckAJrlglEyZlAnCTSn27vLg8gMgMn65 +k3E0GSGEwHdc8jwlv3ETW9cURYFX53z03MPHAMY0OIonVFVFWaQcjQe4/RPE +cY5XALWAqj5uQARCCEa725RKEKdT8rQgyyz3Ngc88sAKg3zAeDKkKCxlnjKx +MZIaJSGKInrtNgtNh0/8xq8fWzLpN8jTnChsUWeSpVOLbMcZkzhnPxkRj0ck +0xhVg5ISaSFsNSllzmg0pc4KDkdjJmmB8hoor4lrJuTxFC2h12rRCAMagc/8 +bJ+5uRM0Rf7LCx89/7v6+//4evD+rbVTUhk2RkfMz3Uxk4xu00dKiavaSLGA +rGqMkAhq8jwnLSR5meAryEYj9pIxkbaQjKmmY3oNj6V+i6gR0AoCHlhe4snV +j+FouXHzxrXnz58591dPX1yt9cvf/s5r9/dH1MohTWOWTy6AKFk+0aPZiJid +7TPb69KMGrSjJr53PI7ZUQUiI5sOEEnMaH+fhZkurTBkaX6ObDxmaXGB06dO +sjTfxzdmL5scPN/otL/xh3/w+Q/a8r9744p85/LPW/c27p+9fuPKb4a++XSe +qkfBdrUS1FVBWeY0fI9mFCGl4FR7jmbToRsqep7mxntX2Bom9B5dZX2aMGcs +jzz8EJv31w+n48ELv/Pbn3np0iefnnyo2/CffvS2+7PLlxeuXrv1+MFg+Fxe +sVpZVsqydDzPI03TY2/gOARB8J97o65rgqP10fnz51985pln/vzSpUuj/7Xj +FOD1n15t/PS9n58+ODj4teFweCnP85U8z1eSJEEplYRh+NIXP/fs15566qnD +/9NT++VXXpUfNuY/AN2DyvmFX+9DAAAAAElFTkSuQmCC +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwUYkGhT +VwAACFpJREFUWMOtl0mMnVeZhp8z/PMd69at0RU7cdmJHRwldhoMLJgUETCI +VjdNN0IsWIAEEkJCAsECBGKBRLOjV91qNYEgEIhByIJuIYQUhZBBmIDJ4MR2 +OXZVuQbXcO9/7/3Hcw6LRqyCKMDf+nyvHr36zvudIzhg/T69KAeNQStJk9SK +6uG0GC1vDG+du7a++tCVyyvMT8//8PSpB758V2fuxdl4IZ/xZquD6IqDAnzi +qU+8+yn12w+v1NffoazUU1GHkwvHOdJY4OmfPsnVi5cxmeN0dCb/6Hs/fvc7 +T73j+kF09YEdMM/9+En7GESWJIppxxoRl4SBwJqCShjK0HFp7+XQBrZxUF15 +0IPGVBBaVArxQNDci5gZz3JMnmDaLOKbDrVNqOOaXOTmtgMkpkGiu5gF2I4K +brqMAocnfChLRJ0T+RbjWXJT3n6AurND4GrEEKhrcrXFnthB08ZzfZSLUdrh +lT4zVbs+qO6BZ8CXEW6ocbHADxWTfMLm7gb5TE6326WXzDDxRsTLmuvt9frr +N34QD9Jhcbw9S7+1RDuYdsf8OXsggH//1ddcJXbYU1vE4hBCOH40eoTS1JA7 +rG8xypLqlJqK1507y4NvexACy0r6G9aClZVBuapmkkV25Ygv/c8nmY1muPDi +L06fvuctz/5FgP+69B+M/A2qZEKUHCIsfNZaL5GHGl/4lEVJrUte3H+eb6z9 +N71ihsXeIcgdvSnBOqu6jhKO1wsc8ae4tHqRVd1i895z0YEcWBEvUwUWAhDR +dQKjqT1ASlzhECGICDI/50L2NJFJWLKHUEKxMO5TJZamhDLdpdM7wXR7jkpH +bFaVOxCAlh5WFjACIwzCBoSFpDKaWhd4yqM0FQjYD1L2q5SN0QaNRsy1okdu +BEveHZyI72BCxTBVFGGE7XXkgQCcM0RO4FUBe7VFaw9TTDBU+E0PIQR1ZbDS +ggUUOAvjesJYTLBlRFUqVjsbrLNNJ1mkIIKiOtgQmrjGCgikBjGmUA4jQTUN +NY5qUuNHAdrXZPkEFSqEL7GlBVnjhYbaZOyKHVaHN4hFTNu2aL9KPLwqwIn0 +FDfNKqPuPr1Ri67sc7l7GSMs0dhiOh5l6GCY8Yb4QY5693PTbHJVvkDQrlit +hmgk49pyRdXshBkLdZ+Rtyj+5mV03xNn3O/qizRCyYgKQsnhYJb3HXsv8U6f +377yHOtqhSBXhNMN0nFGkk9xZ3jmSvWK97M3z7/u1w/fc/aR+VZY/U1BJIyG +oKJCgdIgPALn03AJN369zqVfXWXi7RLKO/j8+z7wrx+4/4Pf/f/OHwLwyN+b +hM08I7aOiVeD7xASBukuWztbbNwcItKYVqOBsdPMVkd/cNujWIYhToKnocLg +hGGiarbYZhAIZKeLcQKnayxG3vZldEumZAnoGpgAFdjQsFFtsSNT8khRighf +G8bU0W13oJn5ZUvja9UAT5ExxljD5s4WZTVLpCN8r02rgJ9fXXv0i088U4U2 +2u62Y6a74cWuUuWC374URMHIVNX1o21/+0+34Oq1FVkURVDXtbtyU+oX/A2X +pv3wxZu3VLFTBM1m2v3O6NPn6a0sEQG9CMICEVmW7GHUS4fRK4cotyUuG9O7 +5yxHDv0DnZFHIismwQR0zbSfQDnBVzDfbn/v6MLcR8Q/feWRzwyj7mKhdGcy +GfWSIpiSykxVpu4JnXQslZTJOhde+k8y8SxCgpdFqMRjEg+hhuTWEmZtCmxI +JWLuO/12mr0TVDpBBgItSgKhEKWgU62zNYLcauZU/oy+q99++OXd0ZtaQYhO +FNuNEqksGIMShrq2WGUQQoCRWGkpPYerC8j/aGIZIEwTQQNPVPhYQuXAFti8 +AmnQ2kdZQX/pLg5PL1GVMLn+wnH91Q/945u/8Oj581NTnXPtRkBsHE7DyDjS +WrOWptzM9rgetdkcN8kZoEKPujYgJRQx2b5B5R5+Mo3WA6rKkGcpRSWRytHt +tjh6+BDzvT5b44yd4YRrl68QDzYiDXBnolnsBrRDxWzpkJFH7YWUcZeJ0qTB +Ud50qkVqXuHx8gmqQc211TU2x7fItwpMV+B3A8rApydOMiw11WBCrz/Pwtwc +zdgnG2U8v/k8q2nBYD9luLXBfTMNXwD832NPnT+8MHOuGylsSyGlxDmBFjFK +hiShJqs2QaZQLeFMzdjmTDBkgzGTtYzfX8k5/8wVbswLxuMxWvo0ojYaQZWN +cOWIQDu294b02i1mW5E9Ndf5rAYYW499owlUDOMcTwqEA0GBcCUm8/CtQriI +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.es.fb2 b/reader/data/help/MiniHelp.desktop.es.fb2 new file mode 100644 index 0000000..b1f5046 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.es.fb2 @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Acerca de Reader</book-title> <lang>es</lang></title-info></description> +<body> +<title><p>Acerca de Reader &ReaderVersion;</p></title> +<p>Reader es un lector de libros electrónicos para Linux/Windows PDA/UMPC/PC. Reader soporta varios formatos: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. También puede leer directamente archivos comprimidos en formato <code>zip</code>, <code>tar</code>, <code>gzip</code> y <code>bzip2</code> .</p> +<p>Reader es distribuido bajo los términos de la <a l:href="http://www.gnu.org/licenses/gpl.html">Licencia Pública General de GNU</a>.</p> +<p>Si le gusta el programa y desea apoyar su desarrollo, por favor visite nuestra <a l:href="http://www.fbreader.org/donation/make.php">página de donaciones</a>.</p> +<empty-line/> +<subtitle><p>Cómo empezar</p></subtitle> +<p>Reader reconoce automáticamente los archivos <code> ePub</code>, <code>fb2</code> y <code>OpenReader </code> que estén en los <code>Directorios de Libros.</code> La ubicación de estos <code>Directorios</code> se puede modificar en el diálogo de Preferencias. (Haciendo click en <image l:href="#settings.png" voffset="-6"/>, en la barra de herramientas). Allà hay que dirigirse a la solapa <code>Biblioteca</code> e indicar la ubicación de los <code>Directorios</code>. Esta opción debe tener la lista de <code>Directorios</code> (separados por punto y coma) que contienen los archivos <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> etc.</p> +<p>Luego puede abrir la <code>Biblioteca</code> (haciendo click en <image l:href="#books.png" voffset="-6"/>) y seleccionar el Libro de su preferencia.</p> +<p>Para leer un archivo de otro formato, primero es necesario agregarlo a la Biblioteca. Hay que entrar en la opción <code>Añadir Libro a la Biblioteca</code> (<image l:href="#addbook.png"/>), seleccionar el archivo e ingresar la información del Libro. La próxima vez que inicie el programa puede leerlo directamente desde la <code>Biblioteca</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Sitios relacionados</p></subtitle> +<p>Para mayor información sobre este programa puede dirigirse a la <a l:href="http://www.fbreader.org">Página principal de Reader</a>.</p> +<p>Si desea ser notificado sobre los nuevos lanzamientos, puede suscribirse al <a l:href="http://freshmeat.net/projects/fbreader">Proyecto de Reader en freshmeat</a>.</p> +<p>Si quiere realizar cualquier pregunta o sugerencia, por favor use el <a l:href="http://groups.google.com/group/fbreader">Grupo de Reader en Googlegroups</a>.</p> +<empty-line/> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.fi.fb2 b/reader/data/help/MiniHelp.desktop.fi.fb2 new file mode 100644 index 0000000..706f91f --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.fi.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Tietoja Readerista</book-title> <lang>fi</lang></title-info></description> +<body> +<title><p>Tietoja Readerista &ReaderVersion;</p></title> +<p>Reader on sähköisten kirjojen (e-kirja) lukemiseen tarkoitettu ohjelmisto Linux, Windows XP, PDA ja UMPC -tietokoneille. Reader tukee mm. seuraavia e-kirjojen tiedostomuotoja: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>. Kirjojen lukeminen onnistuu suoraan myös <code>zip</code>, <code>tar</code>, <code>gzip</code> ja <code>bzip2</code>-muotoihin pakatuista tiedostoista.</p> +<p>Reader ohjelmistoa levitetään <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>-lisenssin mukaisilla ehdoilla.</p> +<empty-line/> +<subtitle><p>Aloitusohje</p></subtitle> +<p>Reader etsii <code>ePub</code>, <code>fb2</code> ja <code>OpenReader</code>-muodossa olevia kirjoja asetusten <code>Kirjaston hakemisto</code>-kohdassa olevista kansioista. Avaa asetukset valintaikkuna (työkalupalkin <image l:href="#settings.png" voffset="-6"/>-kuvakkeesta) ja muuta <code>Kirjasto</code>-välilehdellä olevaa <code>Kirjaston hakemisto</code>-asetusta. Tämä asetus sisältää listauksen niistä kansioista, jotka sisältävät <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> tai kyseisiä tiedostomuotoja sisältäviä pakattuja tiedostoja. Määritettäessä useita kansioita, tulee ne erottaa toisistaan puolipilkulla.</p> +<p>Avaa <code>kirjasto</code> (työkalupalkin <image l:href="#books.png" voffset="-6"/>-kuvakkeesta), valitse kirja listasta ja voit aloittaa sen lukemisen.</p> +<p>Lukeaksesi jossakin muussa tiedostomuodossa olevan kirjan, sinuun täytyy ensin lisätä kyseinen kirja kirjastoosi. Avaa <code>lisää kirja kirjastoon</code>-valintaikkuna (työkalupalkin <image l:href="#addbook.png"/>-kuvakkeesta). Valitse kirjan tiedosto ja muuta kirjan tiedot haluamiksesi. Tämän jälkeen voit avata lisätyn kirjan työkalupalkin <code>kirjasto-kuvakkeen</code> (<image l:href="#books.png" voffset="-6"/>) listauksesta.</p> +<empty-line/> +<subtitle><p>Liittyvät sivustot</p></subtitle> +<p>Tästä ohjelmasta löytyy englanniksi lisätietoja <a l:href="http://www.fbreader.org">Readerin kotisivulta</a>.</p> +<p>Jos haluat tiedon uusien versioiden julkaisuista, tilaa <a l:href="http://freshmeat.net/projects/fbreader">Reader-projekti freshmeat palvelussa</a>.</p> +<p>Jos sinulla on kysymyksiä tai ehdotuksia, käytä <a l:href="http://groups.google.com/group/fbreader">Reader-ryhmää googlegroups palvelussa</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.fr.fb2 b/reader/data/help/MiniHelp.desktop.fr.fb2 new file mode 100644 index 0000000..92d6395 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.fr.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>À propos de Reader</book-title> <lang>fr</lang></title-info></description> +<body> +<title><p>À propos de Reader &ReaderVersion;</p></title> +<p>Reader est un lecteur de livres électroniques (e-books) pour PDA, ordinateur de bureau et UMPC sous Linux ou Windows XP. Reader supporte plusieurs formats de livres électroniques : <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. La lecture directe à partir d'archives <code>zip</code>, <code>tar</code>, <code>gzip</code> et <code>bzip2</code> est également supportée.</p> +<p>Reader est distribué selon les termes de la licence <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<empty-line/> +<subtitle><p>Débuts avec Reader</p></subtitle> +<p>Reader cherche des livres aux formats <code>ePub</code>, <code>fb2</code> et <code>OpenReader</code> dans les répertoires indiqués dans l'option <code>Chemin des livres</code>. La première chose à faire est de remplir ce chemin. Ouvrez la boîte de dialogue d'options (il suffit de cliquer sur <image l:href="#settings.png" voffset="-6"/> dans la barre d'outils) et changez la valeur de l'option <code>Chemin des livres</code> dans l'onglet <code>Bibliothèque</code>. Cette option contient la liste des répertoires contenant des fichiers <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> ou des fichiers archives. Les répertoires de cette liste sont séparés par des caractères deux-points.</p> +<p>Ouvrez la <code>bibliothèque</code> (cliques sur <image l:href="#books.png" voffset="-6"/>) et sélectionnez un livre de la liste afin de le lire.</p> +<p>Pour lire un fichier dans un autre format, vous devez l'ajouter à la bibliothèque. Ouvrez le dialogue <code>Ajouter un livre</code> (<image l:href="#addbook.png"/>), sélectionnez un fichier et éditez les informations correspondantes. Dans l'avenir, vous pourrez ouvrir ce livre directement depuis la <code>bibliothèque</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Informations complémentaires</p></subtitle> +<p>Davantage d'informations sur ce programme se trouvent sur la <a l:href="http://www.fbreader.org">page Web de Reader</a>.</p> +<p>Si vous souhaitez être prévenu des nouvelles versions, veuillez vous inscrire au <a l:href="http://freshmeat.net/projects/fbreader">projet Reader de freshmeat</a>.</p> +<p>Si vous avez des questions ou des suggestions, veuillez utiliser le <a l:href="http://groups.google.com/group/fbreader">groupe Reader de googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.he.fb2 b/reader/data/help/MiniHelp.desktop.he.fb2 new file mode 100644 index 0000000..130bfc3 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.he.fb2 @@ -0,0 +1,201 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Hebrew Reader resources, by David Kachan --> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"> +<description><title-info><author><last-name>Reader</last-name></author><book-title>×ודות Reader</book-title><lang>he</lang></title-info></description> + <body> + <title><p>×ודות Reader &ReaderVersion;</p></title> + <p>Reader ×”×™× ×• ×ª×•×›× ×” המ×פשרת קרי×ת ×¡×¤×¨×™× ××œ×§×˜×¨×•× ×™×™×, ועובדת תחת מערכות הפעלה Linux, FreeBSD, Windows XP. </p> + <p>Reader מ×שפר קרי×ת ×¡×¤×¨×™× ×‘×¤×•×¨×ž×˜×™× ×¨×‘×™×: <code>ePub</code> , <code>fb2</code> , <code>chm</code> , <code>rtf</code> , <code>plucker</code> וכו' . × ×™×ª×Ÿ לפתוח ×¡×¤×¨×™× ×ž×ª×•×š קבצי ×רכיון כגון <code>zip</code> , <code>tar</code> , <code>gzip</code> <code> ו-bzip2 </code>.</p> + <p>×× ×הבת ×ת ×”×ª×•×›× ×” ×•×‘× ×œ×š לתמוך בפיתוח שלה, בקר בדף <a l:href="http://www.fbreader.org/donation/make.php"> תרומה </a> ×¢" מ לתרו×.</p> + <empty-line/> + <subtitle><p>כיצד מתחילי×</p></subtitle> + <p>Reader ×וטומטית מצרף לספריה ×¡×¤×¨×™× ×‘×¤×•×¨×ž×˜×™× <code>ePub</code> , <code>fb2</code> <code>ו-OpenReader</code> ×שר × ×ž×¦××™× ×‘×ª×™×§×™×” מוגדרת בתוך שדה <code>«× תיב הספריה»</code> בתוך הגדרות.</p> + <p> לכן ×œ×¤× ×™ ×©×ž×ª×—×™×œ×™× ×¦×¨×™×š להגדיר שדה ×–×”. פתח הגדרות ( ×¢"×™ לחיצת כפתור <image l:href="#settings.png" voffset="-6"/>) וערוך שדה <code>«× תיב הספריה»</code> תחת <code>«×¡×¤×¨×™×”»</code>.</p> + <p> תיקיות בשדה ×”× "ל צריכות להיות מופרדות ×¢"×™ × ×§×•×“×” ופסיק ולכלול ×§×‘×¦×™× ×¢× ×¡×™×•×ž×•×ª <code>epub</code> ,<code>fb2</code> ,<code>orb</code> ×ו קבצי ×רכיון ×¢× ×§×‘×¦×™× ×לה.</p> + <p>כעת × ×™×ª×Ÿ לפתוח ×ת <code>הספריה</code> (×¢"×™ לחיצה על <image l:href="#books.png" voffset="-6"/>), לבחור ספר ולהתחיל לקרו×.</p> + <p>על ×ž× ×ª ×œ×§×¨×•× ×¡×¤×¨ בפורמט ×חר צריך ×œ×”×›× ×™×¡×• לספריה בצורה ×™×“× ×™×ª. הפעל <code>חלון הוספת ספר</code> (<image l:href="#addbook.png"/>), בחר קובץ וערוך מידע ×ודות הספר.</p> + <p>×‘×¤×¢× ×”×‘××” × ×™×ª×Ÿ לפתוח ×ת הספר ×¢"×™ <code> ספריה </code> (<image l:href="#books.png" voffset="-6"/>).</p> + <empty-line/> + <subtitle><p>קישורי×</p></subtitle> + <p>×¤×¨×˜×™× × ×•×¡×¤×™× ×¢×œ ×ª×•×›× ×™×ª זו × ×™×ª×Ÿ ×œ×ž×¦×•× ×‘×“×£ הבית של<a l:href="http://www.fbreader.org"> Reader </a>.</p> + <p>לקבלת ×¢×“×›×•× ×™× ×¢×œ גרס×ות חדשות ×”×™×¨×©× ×œ×¤×¨×•×™×™×§×˜<a l:href="http://freshmeat.net/projects/fbreader"> Reader on-freshmeat </a>.</p> + <p>ליצירת קשר ×¢× ×™×•×¦×¨×™ ×”×ª×•×›× ×” ×× × ×”×©×ª×ž×© בקבוצת<a l:href="http://groups.google.com/group/fbreader"> Reader on-googlegroups </a>.</p> + </body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.hu.fb2 b/reader/data/help/MiniHelp.desktop.hu.fb2 new file mode 100644 index 0000000..d1517c2 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.hu.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>About Reader</book-title> <lang>hu</lang></title-info></description> +<body> +<title><p>Az Reader &ReaderVersion;</p></title> +<p>Az Reader egy elektronikus könyv (e-book) olvasó program, Linux/Windows XP operációsrendszerekre, PDA/UMPC/PC számÃtógépekre. Az Reader többféle e-book formátumot képes kezelni: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, stb. Közvetlenül olvas a <code>zip</code>, <code>tar</code>, <code>gzip</code> and <code>bzip2</code> formátumú tömörÃtett fájlokból.</p> +<p>Az Reader a <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a> hatálya alatt terjesztett program.</p> +<p>Ha tetszik a program és támogatnád a fejlesztést, látogass el az <a l:href="http://www.fbreader.org/donation/make.php">adományozó</a> oldalra.</p> +<empty-line/> +<subtitle><p>KezdÅ‘ lépések</p></subtitle> +<p>Az Reader azokat az <code>ePub</code>, <code>fb2</code> és <code>OpenReader</code> köteteket kezeli, amelyek <code>„A könyvek helyeâ€</code> beállÃtásban felsorolt könyvtárakban találhatók. ElÅ‘ször ezt az opciót kell beállÃtani. Nyisd meg a <code>„BeállÃtások módosÃtásaâ€</code> menüt (egy kattintás a <image l:href="#settings.png" voffset="-6"/> ikonon, az eszkösávon) és töltsd ki az <code>„A könyvek helyeâ€</code> sort a <code>„Könyvtárâ€</code> fülön. Ez tartalmazza azon könyvtárak listáját, amelyekben megtalálhatók a <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> fájlok, vagy az ezeket tartalmazó tömörÃtett állományok. A könyvtárakat kettÅ‘sponttal (:) kell elválasztani egymástól.</p> +<p>Nyisd meg a <code>„Könyvtárâ€</code>-at (egy kattintás a <image l:href="#books.png" voffset="-6"/> ikonon), válaszd ki a kötetet és azonnal olvashatod.</p> +<p>A felsoroltaktól eltérÅ‘ formátumú köteteket elÅ‘ször hozzá kell adni a könyvtárhoz. IndÃtsd el a <code>„Fájl hozzáadása a könyvtárhozâ€</code> (<image l:href="#addbook.png"/>) menüt, válaszd ki a fájlt és add meg a szükséges információkat. A továbbiakban a könyv elérhetÅ‘ a <code>„Könyvtárâ€</code> (<image l:href="#books.png" voffset="-6"/>) megnyitásával.</p> +<empty-line/> +<subtitle><p>Fontos Internetoldalak</p></subtitle> +<p>A programról további információk olvashatók az <a l:href="http://www.fbreader.org">Reader oldalon</a>.</p> +<p>Ha értesÃtést szeretnél a változásokról, iratkozz fel a <a l:href="http://freshmeat.net/projects/fbreader">Reader projectre a freshmeat-en</a>.</p> +<p>Ha kérdéseid vagy ötleteid vannak, használd az <a l:href="http://groups.google.com/group/fbreader">Reader csoportot a googlegroups-on</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFiIVNd73 +uAAACXNJREFUWMO1l2mMndV5x3/nPe9617l37szYM+OVMXbGGHATO6ZesA04 +JjQqNBtKgWwKigNlcZUUukREDUIKJU1oVUSkqIkVURwsI4PsELCJwQFDvWMb +jBnPeGYym5eZuXOX977bOf3QUiEZV5i2z5dzpOf/6Pw+PHrO/xFcQuzsf+H1 +3f42e/jM2e7yVOC1F+awsHmRv2b2qj+d785/iY8R4qMKh2u9LZt6fnVm0+hj +JNqkUJhBTk5n4LVBVk1bFn5j5W23Lmtf/eylAhgfVVixJrr2T75BNQUqaxOL +iM5ZreRnOmw59G/23/3mwWeeGP7R7f9vAHU5NafP78PzpiGTLNK3KEqPfMaE +tpjDyWH593se2fTEKz/dcCkA5kcVvn56/xzHFgSNEGkLIGKiNsXSq1dwdN9J +lBFCOuLRsUf+5Z97Hi+ubL3ulcHg1Iod1WfmrOSGvuuyNz7RWmop/48A23uf +W/HbY9sXlUqlw9//44f3fjB3Ohy6pmpHGK7Gsi1Qmpqq4BZnM7t7Fsf6DxNW +oRhY7Ozf8cNTzjscyb7OdaWbeGPwFcaHxm8frg6tbs90nP3QJnxt8tVr/vHA +w7sPnH3bTlREWqRo1dOH5pUWjBpZ6b3VONQ9lh3BkwJhakxh0uK0cuXsxYwN +j3DovQM0nDptC1qZZnbQn36P9spM8m6Otan1nJw8wblna/9+9/X3r148c7H/ +/rvy/UvLuvw9z1V/varuxERpH9+tMWVM5qaMyfaRZLjlrDGG2WxgSUEiI6Rr +oEVCpTaFcAVWUZLtTFMrljnnjtI20YllmzRMnxE1xGJvGft79ncMnjvd/ebT ++zdf0ISRDpNYRGS0R0Z4ZFwXO6OomGeom2exUzGmjhAaHMdB2wrtKSaCcSaC +c+i0xvCg0CjRHs6g4BYpZ8eZtCeYzkw+Zaxg7vQutv3h6Vv+6rV777wAYGX3 +6p9Pq3eGZsNETwlETSC1gWFoLFdgW5KkGmApB9v0ULEGCdliFukaCFOjpMI0 +TWZMdDEkTyNDiyv0Er5ib2Bf401e6n2RKWeSPW/t/toFALdM/1LPZ0t/9uPQ +Usi0jeOlsR0PLQWNKEQaDvlUCUd50FDY0gItkFIixH+dWoCpGMj00BJPJ21n ++KL8Kk9sf5x/+Nmj9GX7aJYtfGrup3/xoZPwrfKRzLqD6/qJkyKxIuWaSFuC +AZZlY0kbNRFTpkxbVwnLMZGxRGKQbU1T11VkzcRoUph4zE+uov9cP3u3HkRr +TZjzuYqFm3fd/satFx3FXz/85RcP9Ry6wU818GUN05Y0Z5tRkxEnDvYgT3no +aTEVFdH+ifwLS25Y7JZT46sTmZAVeXy7gq/r5MIC1lCK/VsOkbGyVGUZUVJD +v12xb+FVs64oX3QS9lV68xU5RWD4mJ5FNp1jfHCCngN9NIZAKEGlHpGaFM9/ +t/TQnRu8BzZ0BrN+j4yRiaBarjNbdJFrFCjXJ6m2VRiUw8jI4pt/tOG+Dz5+ +AcCBscOLBmt9S3U+IbYjGmEdERsE5wPC0YQWmcMpGngmLClds+X+dfcPrs+s +P9HFgq1u7BIZDTrznVQnaxRSzSy6fBH5VAYjgoLTRG3MH7/oX/Do0Ue6v7/j +wd/U/DqKBGkKhBAEQUClUiMIQMeas7qKFzgsvWzpy+/Xzst3vdwUNdFwKlRU +lTDn8we/n4Jd5Luf+1tuvuxmRvvPsqf/d5tePLnt2gsAPr/jxh/908EfH99n +/74jK3PEUxrVAMdywNBYKYN8m4VKKbABQyHlf88wkki9o9R/NpQvKsRGjMwJ +huvDSBe+dfO3uGvD3YwOjHY8+PRDuzZuv++He8qvSgB5x5YvfeXV8y8/5rfW +SYox2WoGhMZ0LEIVYQhBc66Z6aVpBI2ArGdRs+sUdMuRd3a8ewRgyX2Lr3jH +OvJtqSwSCyzl4OAwGY3TG77LGXuY+YUF3LrqNp4f3G4c7Du46kTPiaX3bLxn +q5EpZD9peS4oA1WRVBoVMAWGZaB1Agl4TorpLR3M6ZxDLluEvOBY460vbN77 +zAyAIWtgbWCFqEBiBQ7ChyiKSFIBQabG8dphdk/t5PWp3dxy22dw5mn29O5c +v/vYznvNjJdLXOVRn4pocrPIpgahCEgCH8uxsYRFWA1pnd3GmvVreP7AdsLz +IcOj/Z/73tt3NW48eu3vTsYnvqi0AEvjxinqokJsh8jYICcKRCJmPDdML2/T +FrQSOJM0zUyRbU0hH/ibBwdS5OckAZUoikZSDTcXJrGt0prE0YSRwrQdGkaI +KgraO9pwcg5WkyQ/L71QFcObIoIZtmkRqxihYlKGgFgRS5c4NPASG60VdVMT +mYqju4fonOjkG1d/+4EP9YT3Hrxz6fb3nttWz1enua5L2sxCoPA8D09mUWZE +YARYWYmyEkIdkE6nMU2TQAtM0SBxEpTnoquKVulRiyYIcgp1PM3I3jOszK19 ++Zdffuq6i5rS5b+68oHR/NAjsRuTdly01pgWEKewUybKBtMFLAMhNK7tIYRB +wc5Rq56hInwC00ZNGSzrvPqlyclyX9VOmH2iM5xbnLd3+Yxrn12WX+5f1JIV +0qWeMXsMP64jhIFjmSjDwEwLYqmIVUgUC1zTRQoTFWmkEAzGISePn6JyPoIG +XB7M2fvk3ZvXXbInPBdPtpRVDdO2sUWWuBEThBGm5yMtiekIhBaoWBEmIUJK +crk0ncPNjPVILCNCiDzGZKbvY7nikejM1XUdIHCgITGVi2enkZGJTAxEbKIi +iANFEoJKNI7t0VLoRqkcwktBVlLV5/MfC0Da8TWuKdHVkKgSIqKEeq1MUtXQ +sDBCSVxNSBoKoQVJmOD7AfOdEs3KxEpCIrNKVExaLhngod3fywgVdsskwYw1 +OctFEjEwOMHI6dEBf6LeJxITlETHmjhW+L5PpVKmng1opENqZkxkJLSVWocu +GaDUMiNfkO2yUouoFMuM6CGCfuGv4/o7an+RzOr7/Ojcxy/7+XfmxZdzPhom +cCZQ0qcancfNVFGWoins4Kb0HQMPL3/yLz/Wbrip9xcbtx3Z8oMz5ZHM3OL8 +d9d2rfvzr3Z/7cAHNT849tc/2Tr61L1TqSlcK40KFNfOvp53dx1nbeeap/5k +4We/88lpa8r8b2L/8JszL5Y7VNtv37fvrl1dWzv0ghfm6lW7VuiNRzf2/uvx +J9f/n2/HF13ZB17K//rUU4/JlLnoypYlm5fnrvrZlaVPVz9q/X8A8yhCVXd4 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwIdr0Mx +HwAACg1JREFUWMPFl1uopedZx3/v6Tuubx33mn2c2ZNMMulkstudZBwDNqUp +o21i8bYXVa/sRa+KdxW8KAFrJSAEggWxII221KYXNWolxdBIQxqa1Exm2jl1 +9sweZ58P67DX+s7f93qxixAEISL63j8vP57D//k/8P/8xIcNeOv+3UcH46OV +v1nrr1xf31zZTYvVw2l8qsxzIkqCbDw51Wu9+MefffCFZx/7yOh/DPDmlu3e +3RqsvntnfeX9zb2Vtbhc3bVmdaKMAoXwLHYyxTgOMi/ouiHZaAJJjs1KVmY2 +RhcfOvvCp86de/G51eXJfwvwt7+IV9++u7ny3r31lXs7GytW2JX16NQiFqiA +yoKQeI5PM2zRCAKeUNeYb4cst0NaRlMUku+99iZDIm5tD1ChoeNpzva7hxfP +LH7tqTNLX3/u3Nx/ARGf+Mpfv3P5SD856SxQuT4idPF8zTPEdALDYtNhOVLM +uxkndE5LFniipBAPMRNI/GqI7zusxzlf+vq3iJcf5/1Bxv4AMJZWJFlsKs6E +au/xdvgnn3zw9F9+6uJHkg9k4LVXvmvboUecJFjXR/kejg4JXI8g8PB9F+NI +HKNQSiClRFU+A1vSDSNG2ZDad/mzL3yVNz/9NOMbBbfjlEIbgvkFrDH0mj4n +fYdGerR9tt97/rOz5hvPPnkq1wCPXrhAWlbMCAclDJHXJOz6v2K0IAXWVhRF +QZJOSbIMlU2I64xk+9/JiXHDFnWSICYVrm1Q7N4EP6Qwls7SAu2wifIlqbBz +P9u6+RdV3Pjyq7e2/kgDbCdj0vEEv9aYtET6DXZ2M4QQSO3gBT6O56Mdg5QK +P3AJpKKlXVwXVNBmOE5onWjjC8u0jqGjQQqKvfvsxmNGOy3Onl7m6QsfI3Q1 +3/zBP5yqAueLGoDNAZ3AIRdTymZF0oF5r4+UGuU4oDSFhbICIQSOY7Clzyge +YiufYVyzdnuD7Xab2rO4nZwLYhHpBWxPYkZVxWhnnys721zduIMVFRQ+P3rn +OhrgzuYhnWaH6eQIpQoCb8qbFEipkcpgpSLLS6ZJSmVBKsORcRlMpxRoto2g +3szY1gtsbIxgOGYhipCi4mSkOOO1cNx54jRhOJ6QFTkbzRmm9+6gn/nT79rf +/7cJVatBQYQjQOQZSt4mz3Oq0h53ghXYogAEwhj8IsZWUFaaImhwupphUmv2 +r9yF8T57t69ifI+o3yOY6dGaX0A2QjQ13V4Xt6yZbTXRprxNtb9LftBACY1M +E+x4hBe0kVlGVZRoCbKy1FWJlgrfcdmpBwR1hgek3Q7BpMOBZ4iUoG5FOOfO +oR1N7TrspAl3r11DVOBLh07Uwl9e5uITj5Ti6lqy8Oq/vL1Ra42QKdIOUSRk +lcA1mmYjpBOGGAF1keFpRej5nOguEuZDXBVzRxW8+713een6TY5w2djZBnUG +HIUODTp0EEIQaAenVqTjmLbe56tf+sJv6cce9DdvXLuOEgITupSuIrUFzbim +LEustZRlSVEUGGMwxlAUBY4RZJXAD7uckYLJx5+gcfkK/YdX2BhrSCuUdKlq +g6RFe24R2WgySnLidspge40XvvXDz2iASlsqKpxS0MHgWqDbpa5rjDEopajr ++li5hKAsS0odUMcNqnSCFJq5pdNEjR4WF1f7WJOQT/chUVhVY9KQfr/DI4uL +SMfljX++w+Bw/6IGGMWKJE1R2Zi5oEHLNdTFLnVdH6verwCEOFZBay2pCWm4 +mrKyKCnASsbDMVG/ot/pcri7Rh4PwVqKcsrG3iYbV94B7UFVQhCyO7h3PIYn +vIig3aO2OUFoQBQUpovvOzjmg8sjzSCOE5zRFlUO2XSCEzQo8gKpLM3Io1tW +2LqHNJosKxBCQH2cPS0tQmkKVdPy9DHAKDtklEuydEo4lShZk03uEEURjuNg +rcVxHMIwPP4kz+i1+2RpjK8dcD2GW3cJGi7tnk+bksOJS292HmHBVZrA83Gk +QlowxmB9ycW5J9FffvmV3/vKD98iqyU9z+ex2XlORi1McUA3s4RhiNaaAIdY +1VRVRZpm3N07JEtifFdTq5z3bt8jE4o4S6nqnJl2m2YjwnUcXCUJjKEsCvJ4 +ipSS7YNNHvv4CvqN99e/eWtak0qXsE7517fuUezvkTZ9jDHUdf2BZrTWIqXk +3EJIlaVERtNtRkziDKe9xGBYMhpmLHYisumAwfaI6WjIaHDI0WBAXeY4WqGi +JpcXmujZoy2ODgt2pzVITZYn5OmE0REgBFgLjoNxHKqqwlqL7/u8njXRSuIW +BZHcR5cWKQ37v9gijhPWsvtURUan1WSm16YfSGa9JlEjIAwDYhOxsX7n2A98 +/zvfXi/z6hRC0ej1GY2PmKSCCsvhZMJgOiUpSwZpwv5wRJwmTA9rtg72KKgw +tcRYgeP5JFpS+S4zyQG+71PXx2XzfZ9ut8v8/DwLCws0WzO8/oO//7EGiMIG +jX6I74ekRcnCiT6t0EMbQ1Fb0roEbaiEpKhragEcJYyzBCsFRVKwc3+XH//k +J2xOjljb2yZonqAsS5SjcLTGdV2cICJOCq5cvc7a7dvYZHQ8BUHQIHB9XEfT +CDxarSZVndFoODiehxAKxLEWVPZ4OckAJrlglEyZlAnCTSn27vLg8gMgMn65 +k3E0GSGEwHdc8jwlv3ETW9cURYFX53z03MPHAMY0OIonVFVFWaQcjQe4/RPE +cY5XALWAqj5uQARCCEa725RKEKdT8rQgyyz3Ngc88sAKg3zAeDKkKCxlnjKx +MZIaJSGKInrtNgtNh0/8xq8fWzLpN8jTnChsUWeSpVOLbMcZkzhnPxkRj0ck +0xhVg5ISaSFsNSllzmg0pc4KDkdjJmmB8hoor4lrJuTxFC2h12rRCAMagc/8 +bJ+5uRM0Rf7LCx89/7v6+//4evD+rbVTUhk2RkfMz3Uxk4xu00dKiavaSLGA +rGqMkAhq8jwnLSR5meAryEYj9pIxkbaQjKmmY3oNj6V+i6gR0AoCHlhe4snV +j+FouXHzxrXnz58591dPX1yt9cvf/s5r9/dH1MohTWOWTy6AKFk+0aPZiJid +7TPb69KMGrSjJr53PI7ZUQUiI5sOEEnMaH+fhZkurTBkaX6ObDxmaXGB06dO +sjTfxzdmL5scPN/otL/xh3/w+Q/a8r9744p85/LPW/c27p+9fuPKb4a++XSe +qkfBdrUS1FVBWeY0fI9mFCGl4FR7jmbToRsqep7mxntX2Bom9B5dZX2aMGcs +jzz8EJv31w+n48ELv/Pbn3np0iefnnyo2/CffvS2+7PLlxeuXrv1+MFg+Fxe +sVpZVsqydDzPI03TY2/gOARB8J97o65rgqP10fnz51985pln/vzSpUuj/7Xj +FOD1n15t/PS9n58+ODj4teFweCnP85U8z1eSJEEplYRh+NIXP/fs15566qnD +/9NT++VXXpUfNuY/AN2DyvmFX+9DAAAAAElFTkSuQmCC +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.id.fb2 b/reader/data/help/MiniHelp.desktop.id.fb2 new file mode 100644 index 0000000..527406d --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.id.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Mengenai Reader</book-title> <lang>id</lang></title-info></description> +<body> +<title><p>Mengenai Reader &ReaderVersion;</p></title> +<p>Reader adalah aplikasi pembaca buku elektronik (e-book) untuk komputer PDA/UMPC/desktop dengan sistem operasi Linux/Windows XP. Reader mendukung beberapa format buku elektronik: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, dan lain-lain. Juga mendukung pembacaan langsung dari berkas terkompresi dalam format <code>zip</code>, <code>tar</code>, <code>gzip</code> dan <code>bzip2</code>.</p> +<p>Reader didistribusikan di bawah lisensi <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<p>Jika Anda menyukai program ini dan ingin mendukung pengembangannya, silakan ke halaman <a l:href="http://www.fbreader.org/donation/make.php">pemberian donasi</a>.</p> +<empty-line/> +<subtitle><p>Bagaimana Memulainya</p></subtitle> +<p>Reader mencari buku format <code>ePub</code>, <code>fb2</code> dan <code>OpenReader</code> dalam direktori yang tercantum dalam pengaturan <code>Lokasi Buku</code>. Anda perlu mengatur lokasi ini terlebih dahulu. Buka dialog pengaturan (klik pada ikon <image l:href="#settings.png" voffset="-6"/> di toolbar) dan ubah pengaturan <code>Lokasi Buku</code> pada halaman <code>Pustaka</code>. Pengaturan ini berisi daftar direktori yang terdapat berkas <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> atau berkas terkompresi. Daftar direktori ini dipisahkan oleh titik dua.</p> +<p>Buka <code>pustaka</code> (klik pada ikon <image l:href="#books.png" voffset="-6"/>), pilih sebuah buku dari daftar dan Anda bisa mulai membaca.</p> +<p>Untuk membaca berkas dalam format lain, Anda perlu menambahkannya ke pustaka. Mulailah <code>dialog tambah ke pustaka</code> (<image l:href="#addbook.png"/>), pilih sebuah berkas dan ubah informasi berkasnya jika perlu. Di lain waktu Anda dapat membuka berkas ini menggunakan <code>pustaka</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Alamat yang berkaitan</p></subtitle> +<p>Informasi tambahan mengenai aplikasi ini dapat ditemukan di <a l:href="http://www.fbreader.org">situs Reader</a>.</p> +<p>Jika ingin menerima informasi mengenai rilis baru aplikasi ini, silakan daftarkan diri ke <a l:href="http://freshmeat.net/projects/fbreader">proyek Reader di freshmeat</a>.</p> +<p>Jika Anda memiliki pertanyaan atau masukan, silakan gunakan <a l:href="http://groups.google.com/group/fbreader">grup Reader di googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.it.fb2 b/reader/data/help/MiniHelp.desktop.it.fb2 new file mode 100644 index 0000000..f80a992 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.it.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Informazioni su Reader</book-title> <lang>it</lang></title-info></description> +<body> +<title><p>Informazioni su Reader &ReaderVersion;</p></title> +<p>Reader è un lettore di e-book per PDA/UMPC/computer Linux/Windows. Reader supporta diversi formati di e-book: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. E' anche supportata la lettura diretta da archivi <code>zip</code>, <code>tar</code>, <code>gzip</code> e <code>bzip2</code>.</p> +<p>Reader è distribuito nei termini is della licenza <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<empty-line/> +<subtitle><p>Come Iniziare</p></subtitle> +<p>Reader cerca i libri <code>ePub</code>, <code>fb2</code> e <code>OpenReader</code> nelle cartelle elencate nell'opzione <code>Percorso Libri</code>. Prima di tutto occorre impostare questo percorso. Apri la finestra Opzioni (basta fare clic su <image l:href="#settings.png" voffset="-6"/> nella barra degli strumenti) and cambiare il valore dell'opzione <code>Percorso Libri</code> nella scheda <code>Biblioteca</code>. Questa opzione contiene l'elenco delle cartelle contenenti file <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> o archivi. Le cartelle dell'elenco sono separate da due punti.</p> +<p>Apri <code>biblioteca</code> (fare clic su <image l:href="#books.png" voffset="-6"/>), seleziona un libro dall'elenco e leggi.</p> +<p>Per leggere un file in un altro formato, devi aggiungerlo alla biblioteca. Apri la <code>finestra aggiungi alla biblioteca</code> (<image l:href="#addbook.png"/>), seleziona un file e modifica le informazioni sul file. La prossima volta puoi aprire questo file usando la <code>biblioteca</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Siti correlati</p></subtitle> +<p>Ulteriori informazioni su questo programma possono essere trovate alla <a l:href="http://www.fbreader.org">homepage di Reader</a>.</p> +<p>Se vuoi essere informato sull'uscita di nuove versioni, per favore iscriviti al <a l:href="http://freshmeat.net/projects/fbreader">progetto Reader su freshmeat</a>.</p> +<p>Se hai domande o suggerimenti, per favore usa il <a l:href="http://groups.google.com/group/fbreader">gruppo di Reader su google gruppi</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.lt.fb2 b/reader/data/help/MiniHelp.desktop.lt.fb2 new file mode 100644 index 0000000..77ec399 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.lt.fb2 @@ -0,0 +1,218 @@ +<?xml version="1.0" encoding="utf-8" ?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"> +<description> +<title-info> +<author> +<first-name>Reader</first-name> +<middle-name></middle-name> +<last-name></last-name> +</author> +<book-title>Apie Reader 0.12.0</book-title> +<lang>lt</lang> +<src-lang>en</src-lang> +<translator> +<first-name>Stanislovas</first-name> +<middle-name></middle-name> +<last-name>Zacharovas</last-name> +<nickname>Stas</nickname> +<home-page>www.knygute.lt</home-page> +<email>stanislovasz@gmail.com</email> +</translator> +</title-info> +</description> +<body> +<title><p>Apie programÄ… Reader &ReaderVersion;</p></title> +<p>Programa Reader skirta elektroninių knygų skaitymui kompiuteriuose, kuriuose yra įdiegtos Linux arba Windows operacinÄ—s sistemos. Reader palaiko daugumÄ… elektroninių knygų formatų: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, ir t.t. Programa taip pat sugeba atidaryti elektronines knygas tiesiogiai iÅ¡ archyvų <code>zip</code>, <code>tar</code>, <code>gzip</code> ir <code>bzip2</code>.</p> +<p>Programa Reader yra platinama pagal GNU Bendros VieÅ¡osios Licenzijos (<a l:href="http://www.gnu.org/licenses/gpl.html">GNU BVL</a>) sÄ…lygas.</p> +<p>Jeigu jums patinka programa ir jÅ«s norite paremti jos vystymÄ…si – aplankykite <a l:href="http://www.fbreader.org/donation/make.php">paramos puslapį</a>.</p> +<empty-line/> +<subtitle><p>Kaip pradÄ—ti naudotis programa</p></subtitle> +<p>Programa Reader ieÅ¡ko <code>ePub</code>, <code>fb2</code> ir <code>OpenReader</code> knygų kataloguose (directory) iÅ¡vardintuose kortelÄ—s Biblioteka nustatymuose. Jeigu norite, kad Reader žinotų kur jÅ«sų kompiuteryje yra laikomos knygos, turite nurodyti programai keliÄ… iki knygų katalogo. Tam tikslui atidarykite nustatymų langÄ… paspausdami <image l:href="#settings.png"/> programos įrankių juostoje ir kortelÄ—s Biblioteka laukuose “Kelias prie knygos (knygų)†ir “Atsisiųstų knygų saugojimo vieta†įraÅ¡ykite keliÄ… prie knygų saugojimo vietos, pavyzdžiui:</p> +<p><code>~/Books:/media/disk1/Books</code></p> +<p>Skirtingos knygų laikymo vietos atskiriamos dvitaÅ¡kiu: “:â€</p> +<p>Tam, kad atidaryti Reader bibliotekÄ… – paspauskite ženkliukÄ… <image l:href="#books.png"/> – Äia galÄ—site iÅ¡sirinkti knygÄ… skaitymui.</p> +<p>Norint pridÄ—ti knygÄ… prie Reader bibliotekos, paspauskite <image l:href="#addbook.png"/> – atsidarys knygos paieÅ¡kos langas. Langas rodo paskutinÄ—s į Reader bibliotekÄ… įkeltos knygos buvimo vietÄ…. Nurodykite knygos, kuriÄ… norite skaityti Reader programoje, saugojimo vietÄ… jÅ«sų kompiuteryje, pažymÄ—kite knygÄ… ir paspauskite mygtukÄ… "Patvirtinti". Knyga bus prijungta prie Reader bibliotekos ir sekantį kartÄ… galÄ—site jÄ… pasiekti spausdami Reader bibliotekos ženkliukÄ… <image l:href="#books.png"/>.</p> +<empty-line/> +<subtitle><p>Susieti tinklalapiai</p></subtitle> +<p>AtnaujintÄ… informacijÄ… apie programÄ… rasite <a l:href="http://www.fbreader.org/">Reader svetainÄ—je</a>.</p> +<p>Jeigu jÅ«s norite gauti informacijÄ… apie Reader atnaujinimus elektroniniu paÅ¡tu – užsiprenumeruokite programos naujienas svetainÄ—je <a l:href="http://freshmeat.net/projects/fbreader">Freshmeat.</a></p> +<p>Jeigu turite klausimų ar pasiÅ«lymų – susisiekite su Reader bendruomene <a l:href="http://groups.google.com/group/fbreader">googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.nl.fb2 b/reader/data/help/MiniHelp.desktop.nl.fb2 new file mode 100755 index 0000000..b505843 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.nl.fb2 @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Over Reader</book-title> <lang>nl</lang></title-info></description> +<body> +<title><p>Over Reader &ReaderVersion;</p></title> +<p>Reader is een e-book reader voor Linux/Windows/FreeBSD en verschillende mobiele platformen. Reader ondersteunt verschillende e-book bestanden: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. Het direct lezen van <code>zip</code>, <code>tar</code>, <code>gzip</code> en <code>bzip2</code> gecomprimeerde bestanden wordt ook ondersteund.</p> +<p>Reader wordt distribueerd onder de voorwaarden van de <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<p>Indien U dit programma op prijs stelt en U aan de ontwikkeling ervan wilt bijdragen, bezoek dan de <a l:href="http://www.fbreader.org/donation/make.php">donatie</a> pagina.</p> +<empty-line/> +<subtitle><p>Configuratie</p></subtitle> +<p>Reader zoekt naar <code>ePub</code>, <code>fb2</code> en <code>OpenReader</code> boeken in de mappen die als <code>Boek Locaties </code> zijn gespecificeerd. Om te beginnen kiest u deze mappen. Open het configuratiescherm (Selecteer <image l:href="#settings.png" voffset="-6"/> in de menubalk) en kies Uw <code>Boek Locaties</code> op de pagina met het <code>Bibliotheek</code> label. Deze pagina bevat een lijst van mappen met <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> of gecomprimeerde bestanden. Mappen in deze lijst worden van elkaar gescheiden door een dubbele punt (:).</p> +<p>Open de <code>bibliotheek</code> (<image l:href="#books.png" voffset="-6"/>) en selecteer een boek uit de lijst om het te lezen.</p> +<p>Om andere e-book bestanden te lezen dient U deze aan de bibliotheek toe te voegen. Open het <code>aan bibliotheek toevoegen</code> (<image l:href="#addbook.png"/>) keuzescherm, selecteer een bestand en bewerk eventueel de informatie. U kunt dit bestand in het vervolg vanuit de <code>bibliotheek</code> (<image l:href="#books.png" voffset="-6"/>) openen.</p> +<empty-line/> +<subtitle><p>Gerelateerde sites</p></subtitle> +<p>Meer informatie over dit programma kunt U op de <a l:href="http://www.fbreader.org">Reader homepage</a> vinden.</p> +<p>Om op de hoogte gehouden te worden van nieuwe versies kunt U zich abonneren op het <a l:href="http://freshmeat.net/projects/fbreader">Reader project op Freshmeat</a>.</p> +<p>Voor vragen of suggesties kunt U de <a l:href="http://groups.google.com/group/fbreader">Reader group van googlegroups</a> bezoeken.</p> +</body> +<binary content-type="image/png" id="settings.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFiIVNd73 +uAAACXNJREFUWMO1l2mMndV5x3/nPe9617l37szYM+OVMXbGGHATO6ZesA04 +JjQqNBtKgWwKigNlcZUUukREDUIKJU1oVUSkqIkVURwsI4PsELCJwQFDvWMb +jBnPeGYym5eZuXOX977bOf3QUiEZV5i2z5dzpOf/6Pw+PHrO/xFcQuzsf+H1 +3f42e/jM2e7yVOC1F+awsHmRv2b2qj+d785/iY8R4qMKh2u9LZt6fnVm0+hj +JNqkUJhBTk5n4LVBVk1bFn5j5W23Lmtf/eylAhgfVVixJrr2T75BNQUqaxOL +iM5ZreRnOmw59G/23/3mwWeeGP7R7f9vAHU5NafP78PzpiGTLNK3KEqPfMaE +tpjDyWH593se2fTEKz/dcCkA5kcVvn56/xzHFgSNEGkLIGKiNsXSq1dwdN9J +lBFCOuLRsUf+5Z97Hi+ubL3ulcHg1Iod1WfmrOSGvuuyNz7RWmop/48A23uf +W/HbY9sXlUqlw9//44f3fjB3Ohy6pmpHGK7Gsi1Qmpqq4BZnM7t7Fsf6DxNW +oRhY7Ozf8cNTzjscyb7OdaWbeGPwFcaHxm8frg6tbs90nP3QJnxt8tVr/vHA +w7sPnH3bTlREWqRo1dOH5pUWjBpZ6b3VONQ9lh3BkwJhakxh0uK0cuXsxYwN +j3DovQM0nDptC1qZZnbQn36P9spM8m6Otan1nJw8wblna/9+9/X3r148c7H/ +/rvy/UvLuvw9z1V/varuxERpH9+tMWVM5qaMyfaRZLjlrDGG2WxgSUEiI6Rr +oEVCpTaFcAVWUZLtTFMrljnnjtI20YllmzRMnxE1xGJvGft79ncMnjvd/ebT ++zdf0ISRDpNYRGS0R0Z4ZFwXO6OomGeom2exUzGmjhAaHMdB2wrtKSaCcSaC +c+i0xvCg0CjRHs6g4BYpZ8eZtCeYzkw+Zaxg7vQutv3h6Vv+6rV777wAYGX3 +6p9Pq3eGZsNETwlETSC1gWFoLFdgW5KkGmApB9v0ULEGCdliFukaCFOjpMI0 +TWZMdDEkTyNDiyv0Er5ib2Bf401e6n2RKWeSPW/t/toFALdM/1LPZ0t/9uPQ +Usi0jeOlsR0PLQWNKEQaDvlUCUd50FDY0gItkFIixH+dWoCpGMj00BJPJ21n ++KL8Kk9sf5x/+Nmj9GX7aJYtfGrup3/xoZPwrfKRzLqD6/qJkyKxIuWaSFuC +AZZlY0kbNRFTpkxbVwnLMZGxRGKQbU1T11VkzcRoUph4zE+uov9cP3u3HkRr +TZjzuYqFm3fd/satFx3FXz/85RcP9Ry6wU818GUN05Y0Z5tRkxEnDvYgT3no +aTEVFdH+ifwLS25Y7JZT46sTmZAVeXy7gq/r5MIC1lCK/VsOkbGyVGUZUVJD +v12xb+FVs64oX3QS9lV68xU5RWD4mJ5FNp1jfHCCngN9NIZAKEGlHpGaFM9/ +t/TQnRu8BzZ0BrN+j4yRiaBarjNbdJFrFCjXJ6m2VRiUw8jI4pt/tOG+Dz5+ +AcCBscOLBmt9S3U+IbYjGmEdERsE5wPC0YQWmcMpGngmLClds+X+dfcPrs+s +P9HFgq1u7BIZDTrznVQnaxRSzSy6fBH5VAYjgoLTRG3MH7/oX/Do0Ue6v7/j +wd/U/DqKBGkKhBAEQUClUiMIQMeas7qKFzgsvWzpy+/Xzst3vdwUNdFwKlRU +lTDn8we/n4Jd5Luf+1tuvuxmRvvPsqf/d5tePLnt2gsAPr/jxh/908EfH99n +/74jK3PEUxrVAMdywNBYKYN8m4VKKbABQyHlf88wkki9o9R/NpQvKsRGjMwJ +huvDSBe+dfO3uGvD3YwOjHY8+PRDuzZuv++He8qvSgB5x5YvfeXV8y8/5rfW +SYox2WoGhMZ0LEIVYQhBc66Z6aVpBI2ArGdRs+sUdMuRd3a8ewRgyX2Lr3jH +OvJtqSwSCyzl4OAwGY3TG77LGXuY+YUF3LrqNp4f3G4c7Du46kTPiaX3bLxn +q5EpZD9peS4oA1WRVBoVMAWGZaB1Agl4TorpLR3M6ZxDLluEvOBY460vbN77 +zAyAIWtgbWCFqEBiBQ7ChyiKSFIBQabG8dphdk/t5PWp3dxy22dw5mn29O5c +v/vYznvNjJdLXOVRn4pocrPIpgahCEgCH8uxsYRFWA1pnd3GmvVreP7AdsLz +IcOj/Z/73tt3NW48eu3vTsYnvqi0AEvjxinqokJsh8jYICcKRCJmPDdML2/T +FrQSOJM0zUyRbU0hH/ibBwdS5OckAZUoikZSDTcXJrGt0prE0YSRwrQdGkaI +KgraO9pwcg5WkyQ/L71QFcObIoIZtmkRqxihYlKGgFgRS5c4NPASG60VdVMT +mYqju4fonOjkG1d/+4EP9YT3Hrxz6fb3nttWz1enua5L2sxCoPA8D09mUWZE +YARYWYmyEkIdkE6nMU2TQAtM0SBxEpTnoquKVulRiyYIcgp1PM3I3jOszK19 ++Zdffuq6i5rS5b+68oHR/NAjsRuTdly01pgWEKewUybKBtMFLAMhNK7tIYRB +wc5Rq56hInwC00ZNGSzrvPqlyclyX9VOmH2iM5xbnLd3+Yxrn12WX+5f1JIV +0qWeMXsMP64jhIFjmSjDwEwLYqmIVUgUC1zTRQoTFWmkEAzGISePn6JyPoIG +XB7M2fvk3ZvXXbInPBdPtpRVDdO2sUWWuBEThBGm5yMtiekIhBaoWBEmIUJK +crk0ncPNjPVILCNCiDzGZKbvY7nikejM1XUdIHCgITGVi2enkZGJTAxEbKIi +iANFEoJKNI7t0VLoRqkcwktBVlLV5/MfC0Da8TWuKdHVkKgSIqKEeq1MUtXQ +sDBCSVxNSBoKoQVJmOD7AfOdEs3KxEpCIrNKVExaLhngod3fywgVdsskwYw1 +OctFEjEwOMHI6dEBf6LeJxITlETHmjhW+L5PpVKmng1opENqZkxkJLSVWocu +GaDUMiNfkO2yUouoFMuM6CGCfuGv4/o7an+RzOr7/Ojcxy/7+XfmxZdzPhom +cCZQ0qcancfNVFGWoins4Kb0HQMPL3/yLz/Wbrip9xcbtx3Z8oMz5ZHM3OL8 +d9d2rfvzr3Z/7cAHNT849tc/2Tr61L1TqSlcK40KFNfOvp53dx1nbeeap/5k +4We/88lpa8r8b2L/8JszL5Y7VNtv37fvrl1dWzv0ghfm6lW7VuiNRzf2/uvx +J9f/n2/HF13ZB17K//rUU4/JlLnoypYlm5fnrvrZlaVPVz9q/X8A8yhCVXd4 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.ru.fb2 b/reader/data/help/MiniHelp.desktop.ru.fb2 new file mode 100644 index 0000000..dec9df7 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.ru.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>О программе Reader</book-title> <lang>ru</lang></title-info></description> +<body> +<title><p>О программе Reader &ReaderVersion;</p></title> +<p>Reader – программа Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñлектронных книг, Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´ операционными ÑиÑтемами Linux, FreeBSD, Windows XP. Reader позволÑет читать книги во многих форматах: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, и Ñ‚. Ð´. Файлы можно читать напрÑмую из архивов <code>zip</code>, <code>tar</code>, <code>gzip</code> и <code>bzip2</code>.</p> +<p>Reader раÑпроÑтранÑетÑÑ Ñвободно, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¸Ñходные текÑты, под лицензией <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<empty-line/> +<subtitle><p>С чего начать</p></subtitle> +<p>Reader автоматичеÑки Ñобирает в библиотеку файлы форматов <code>ePub</code>, <code>fb2</code> и <code>OpenReader</code>, лежащие в каталогах, заданных параметром <code>«ÐšÐ°Ñ‚алоги Ñ ÐºÐ½Ð¸Ð³Ð°Ð¼Ð¸»</code>. ПоÑтому прежде вÑего нужно определить Ñтот параметр. Откройте диалог наÑтроек (нажмите на кнопку <image l:href="#settings.png" voffset="-6"/>) и отредактруйте <code>«ÐºÐ°Ñ‚алоги Ñ ÐºÐ½Ð¸Ð³Ð°Ð¼Ð¸»</code> в разделе <code>«Ð‘иблиотека»</code>. Каталоги перечиÑлÑÑŽÑ‚ÑÑ Ñ‡ÐµÑ€ÐµÐ· двоеточие, в Ñтих каталогах должны лежать файлы Ñ Ñ€Ð°ÑширениÑми <code>epub</code>, <code>fb2</code> или <code>orb</code>, или Ñодержащие их архивы.</p> +<p>Теперь откройте <code>библиотеку</code> (нажмите на <image l:href="#books.png" voffset="-6"/>), выберите книгу, и приÑтупайте к чтению.</p> +<p>Чтобы читать книгу в другом формате, ее нужно вручную добавить в библиотеку. ЗапуÑтите <code>диалог Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ½Ð¸Ð³Ð¸</code> (<image l:href="#addbook.png"/>), выберите файл и отредактируйте информацию о книге. Ð’ Ñледующий раз вы Ñможете открыть Ñту книгу уже Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ <code>библиотеки</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>СÑылки</p></subtitle> +<p>Информацию об Reader'е и Ñвежую верÑию программы можно найти на <a l:href="http://www.fbreader.org">Ñайте Reader'а</a>.</p> +<p>ЕÑли вы хотите получать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ новых верÑиÑÑ…, подпишитеÑÑŒ на <a l:href="http://freshmeat.net/projects/fbreader">проект Reader на freshmeat</a>.</p> +<p>Чтобы ÑвÑзатьÑÑ Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð°Ð¼Ð¸ программы, воÑпользуйтеÑÑŒ <a l:href="http://groups.google.com/group/fbreader">группой Reader на googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.sv.fb2 b/reader/data/help/MiniHelp.desktop.sv.fb2 new file mode 100644 index 0000000..730a27a --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.sv.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Om Reader</book-title> <lang>sv</lang></title-info></description> +<body> +<title><p>Om Reader &ReaderVersion;</p></title> +<p>Reader är en e-boksläsare för Linux/Windows XP PDA/UMPC/skrivbordsdator. Reader har stöd för flera e-boksformat: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, etc. Direktläsning frÃ¥n arkivformaten <code>zip</code>, <code>tar</code>, <code>gzip</code> och <code>bzip2</code> stöds ocksÃ¥.</p> +<p>Reader distribueras under villkoren för <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<empty-line/> +<subtitle><p>Hur man kommer igÃ¥ng</p></subtitle> +<p>Reader letar efter böcker i formaten <code>ePub</code>, <code>fb2</code> och <code>OpenReader</code> i kataloger som listas i alternativet <code>Boksökväg</code>. Först mÃ¥ste du ange denna sökväg. Öppna alternativdialogrutan (klicka helt enkelt pÃ¥ <image l:href="#settings.png" voffset="-6"/> i verktygsraden) och ändra värdet för alternativet <code>Boksökväg</code> under fliken <code>Bibliotek</code>. Detta alternativ innehÃ¥ller listan över kataloger som innehÃ¥ller <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> eller arkivfiler. Kataloger i listan separeras med kolon.</p> +<p>Öppna <code>biblioteket</code> (klicka pÃ¥ <image l:href="#books.png" voffset="-6"/>), välj en bok frÃ¥n listan och läs den.</p> +<p>För att läsa en fil i ett annat format mÃ¥ste du lägga till den till biblioteket. Starta <code>Lägg till i biblioteket</code> (<image l:href="#addbook.png"/>), välj en fil och redigera filinformationen. Nästa gÃ¥ng sÃ¥ kan du öppna denna fil med <code>biblioteket</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>Relaterade webbplatser</p></subtitle> +<p>Mer information om det här programmet kan hittas pÃ¥ <a l:href="http://www.fbreader.org">Readers webbplats</a>.</p> +<p>Om du vill bli informerad om nya utgÃ¥vor kan du prenumerera pÃ¥ <a l:href="http://freshmeat.net/projects/fbreader">Readers projektsida pÃ¥ Freshmeat</a>.</p> +<p>Om du har nÃ¥gra frÃ¥gor eller förslag kan du använda <a l:href="http://groups.google.com/group/fbreader">Readers grupp hos Google Groups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.uk.fb2 b/reader/data/help/MiniHelp.desktop.uk.fb2 new file mode 100644 index 0000000..754a000 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.uk.fb2 @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>Про програму Reader</book-title> <lang>uk</lang></title-info></description> +<body> +<title><p>Про програму Reader &ReaderVersion;</p></title> +<p>Reader – програма Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¸Ñ… книг, Ñка працює під операційними ÑиÑтемами Linux, FreeBSD, Windows XP. Reader дозволÑÑ” читати книги у багатьох форматах: <code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>, <code>plucker</code>, Ñ– Ñ‚. Ð´. Файли можна читати напрÑму з архівів <code>zip</code>, <code>tar</code>, <code>gzip</code> та <code>bzip2</code>.</p> +<p>Reader поширюєтьÑÑ Ð²Ñ–Ð»ÑŒÐ½Ð¾, разом з джерельними текÑтами, під лицензією <a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>.</p> +<empty-line/> +<subtitle><p>З чого почати</p></subtitle> +<p>Reader автоматично збирає у бібліотеку файли форматів <code>ePub</code>, <code>fb2</code> та <code>OpenReader</code>, що лежать у каталогах, Ñкі задані параметром <code>“Каталоги з книгами”</code>. Тому передуÑім треба визначити цей параметр. Відкрийте діалог налаштувань (натиÑніть на кнопку <image l:href="#settings.png" voffset="-6"/>) Ñ– відредагуйте <code>“каталоги з книгами”</code> у розділі <code>“Бібліотека”</code>. Каталоги перелічуютьÑÑ Ñ‡ÐµÑ€ÐµÐ· двокрапку i повинні міÑтити файли з розширеннÑми <code>epub</code>, <code>fb2</code> або <code>orb</code>, чи архіви, що Ñ—Ñ… міÑÑ‚Ñть.</p> +<p>Тепер відкрийте <code>бібліотеку</code> (натиÑніть на <image l:href="#books.png" voffset="-6"/>), виберіть книгу Ñ– починайте читати.</p> +<p>Щоб читати книгу у іншому форматі, Ñ—Ñ— потрібно вручну додати у бібліотеку. ЗапуÑтіть <code>діалог Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ½Ð¸Ð³Ð¸</code> (<image l:href="#addbook.png"/>), виберіть файл Ñ– відредагуйте інформацію про книгу. ÐаÑтупного разу ви зможете відкрити цю книгу вже за допомогою <code>бібліотеки</code> (<image l:href="#books.png" voffset="-6"/>).</p> +<empty-line/> +<subtitle><p>ПоÑиланнÑ</p></subtitle> +<p>Інформацію про Reader та нову верÑÑ–ÑŽ програми можна знайти на <a l:href="http://www.fbreader.org">Ñайтi Reader'у</a>.</p> +<p>Якщо ви бажаєте отримувати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ нові верÑÑ–Ñ—, підпишітьÑÑ Ð½Ð° <a l:href="http://freshmeat.net/projects/fbreader">проект Reader на freshmeat</a>.</p> +<p>Ð”Ð»Ñ Ð·Ð²'Ñзку з авторами програми ÑкориÑтуйтеÑÑŒ <a l:href="http://groups.google.com/group/fbreader">групою Reader на googlegroups</a>.</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwUYkGhT +VwAACFpJREFUWMOtl0mMnVeZhp8z/PMd69at0RU7cdmJHRwldhoMLJgUETCI +VjdNN0IsWIAEEkJCAsECBGKBRLOjV91qNYEgEIhByIJuIYQUhZBBmIDJ4MR2 +OXZVuQbXcO9/7/3Hcw6LRqyCKMDf+nyvHr36zvudIzhg/T69KAeNQStJk9SK +6uG0GC1vDG+du7a++tCVyyvMT8//8PSpB758V2fuxdl4IZ/xZquD6IqDAnzi +qU+8+yn12w+v1NffoazUU1GHkwvHOdJY4OmfPsnVi5cxmeN0dCb/6Hs/fvc7 +T73j+kF09YEdMM/9+En7GESWJIppxxoRl4SBwJqCShjK0HFp7+XQBrZxUF15 +0IPGVBBaVArxQNDci5gZz3JMnmDaLOKbDrVNqOOaXOTmtgMkpkGiu5gF2I4K +brqMAocnfChLRJ0T+RbjWXJT3n6AurND4GrEEKhrcrXFnthB08ZzfZSLUdrh +lT4zVbs+qO6BZ8CXEW6ocbHADxWTfMLm7gb5TE6326WXzDDxRsTLmuvt9frr +N34QD9Jhcbw9S7+1RDuYdsf8OXsggH//1ddcJXbYU1vE4hBCOH40eoTS1JA7 +rG8xypLqlJqK1507y4NvexACy0r6G9aClZVBuapmkkV25Ygv/c8nmY1muPDi +L06fvuctz/5FgP+69B+M/A2qZEKUHCIsfNZaL5GHGl/4lEVJrUte3H+eb6z9 +N71ihsXeIcgdvSnBOqu6jhKO1wsc8ae4tHqRVd1i895z0YEcWBEvUwUWAhDR +dQKjqT1ASlzhECGICDI/50L2NJFJWLKHUEKxMO5TJZamhDLdpdM7wXR7jkpH +bFaVOxCAlh5WFjACIwzCBoSFpDKaWhd4yqM0FQjYD1L2q5SN0QaNRsy1okdu +BEveHZyI72BCxTBVFGGE7XXkgQCcM0RO4FUBe7VFaw9TTDBU+E0PIQR1ZbDS +ggUUOAvjesJYTLBlRFUqVjsbrLNNJ1mkIIKiOtgQmrjGCgikBjGmUA4jQTUN +NY5qUuNHAdrXZPkEFSqEL7GlBVnjhYbaZOyKHVaHN4hFTNu2aL9KPLwqwIn0 +FDfNKqPuPr1Ri67sc7l7GSMs0dhiOh5l6GCY8Yb4QY5693PTbHJVvkDQrlit +hmgk49pyRdXshBkLdZ+Rtyj+5mV03xNn3O/qizRCyYgKQsnhYJb3HXsv8U6f +377yHOtqhSBXhNMN0nFGkk9xZ3jmSvWK97M3z7/u1w/fc/aR+VZY/U1BJIyG +oKJCgdIgPALn03AJN369zqVfXWXi7RLKO/j8+z7wrx+4/4Pf/f/OHwLwyN+b +hM08I7aOiVeD7xASBukuWztbbNwcItKYVqOBsdPMVkd/cNujWIYhToKnocLg +hGGiarbYZhAIZKeLcQKnayxG3vZldEumZAnoGpgAFdjQsFFtsSNT8khRighf +G8bU0W13oJn5ZUvja9UAT5ExxljD5s4WZTVLpCN8r02rgJ9fXXv0i088U4U2 +2u62Y6a74cWuUuWC374URMHIVNX1o21/+0+34Oq1FVkURVDXtbtyU+oX/A2X +pv3wxZu3VLFTBM1m2v3O6NPn6a0sEQG9CMICEVmW7GHUS4fRK4cotyUuG9O7 +5yxHDv0DnZFHIismwQR0zbSfQDnBVzDfbn/v6MLcR8Q/feWRzwyj7mKhdGcy +GfWSIpiSykxVpu4JnXQslZTJOhde+k8y8SxCgpdFqMRjEg+hhuTWEmZtCmxI +JWLuO/12mr0TVDpBBgItSgKhEKWgU62zNYLcauZU/oy+q99++OXd0ZtaQYhO +FNuNEqksGIMShrq2WGUQQoCRWGkpPYerC8j/aGIZIEwTQQNPVPhYQuXAFti8 +AmnQ2kdZQX/pLg5PL1GVMLn+wnH91Q/945u/8Oj581NTnXPtRkBsHE7DyDjS +WrOWptzM9rgetdkcN8kZoEKPujYgJRQx2b5B5R5+Mo3WA6rKkGcpRSWRytHt +tjh6+BDzvT5b44yd4YRrl68QDzYiDXBnolnsBrRDxWzpkJFH7YWUcZeJ0qTB +Ud50qkVqXuHx8gmqQc211TU2x7fItwpMV+B3A8rApydOMiw11WBCrz/Pwtwc +zdgnG2U8v/k8q2nBYD9luLXBfTMNXwD832NPnT+8MHOuGylsSyGlxDmBFjFK +hiShJqs2QaZQLeFMzdjmTDBkgzGTtYzfX8k5/8wVbswLxuMxWvo0ojYaQZWN +cOWIQDu294b02i1mW5E9Ndf5rAYYW499owlUDOMcTwqEA0GBcCUm8/CtQriI +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.vi.fb2 b/reader/data/help/MiniHelp.desktop.vi.fb2 new file mode 100644 index 0000000..2d00abe --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.vi.fb2 @@ -0,0 +1,224 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>About Reader</book-title> <lang>vi</lang></title-info></description> +<body> +<title><p>Vá» FBreader &ReaderVersion;</p></title><p><code>(Dịch sang Tiếng Việt bởi Phạm Văn Hùng_Firestork (Có thể không chÃnh xác
+100% do trình độ ngưá»i dịch có hạn. Nếu muốn hiểu kÄ© là m Æ¡n Ä‘á»c bản tiếng Nga
+hoặc tiếng Anh))</code> </p><empty-line/>
+<empty-line/> +<p>Reader là má»™t chương trình Ä‘á»c sách Ä‘iện tá» dà nh cho máy tÃnh để bà n
+Linux/Windows XP PDA/UMPC. Reader há»— trợ nhiá»u định dạng sách Ä‘iện tá»:
+<code>ePub</code>, <code>fb2</code>, <code>chm</code>, <code>rtf</code>,
+<code>plucker</code>, v...v. Việc Ä‘á»c trá»±c tiếp từ các định dạng nén
+<code>zip</code>, <code>tar</code>, <code>gzip</code> và <code>bzip2</code> cũng
+được há»— trợ.</p> +<p>Reader được phân phối dưới Ä‘iá»u khoản cá»§a giấy phép <a
+l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>. </p> +<p>Nếu bạn thÃch chương trình nà y và mong muốn há»— trợ sá»± phát triển cá»§a nó, là m
+ơn ghé thăm trang <a l:href="http://www.fbreader.org/donation/make.php"> hỗ trợ
+tà i chÃnh</a> .</p> +<empty-line/> +<subtitle><p>Bắt đầu như thế nà o?</p></subtitle> +<p>Reader tìm kiếm các sách định dạng <code>ePub</code>, <code>fb2</code> vÃ
+<code>OpenReader</code> trong các thư mục được lên danh sách tại tùy chá»n
+<code>ÄÆ°á»ng dẫn Sách</code>. Äầu tiên bạn cần đặt đưá»ng dẫn nà y. Mở há»™p tùy
+chỉnh (click và o <image l:href="#settings.png" voffset="-6"/> trên thanh công
+cụ) và thay đổi giá trị cá»§a tùy chá»n <code>ÄÆ°á»ng dẫn Sách</code> trong thẻ
+<code>Thư viện</code> . Tùy chá»n nà y chứa danh sách cá»§a các thư mục chứa các táºp
+tin <code>*.epub</code>, <code>*.fb2</code>, <code>*.orb</code> hoặc táºp tin
+nén. Cách thư mục trong danh sách được ngăn cách bằng dấu chấm phẩy.</p>
+<p>Mở <code>thư viện</code> (click và o <image l:href="#books.png" voffset="-
+6"/>), chá»n má»™t quyển trong danh sách và đá»c.</p> +<p>Äể Ä‘á»c má»™t táºp tin có định dạng khác, bạn cần thêm nó và o thư viện. Khởi chạy
+<code>cá»a sổ Thêm và o thư viện</code> (<image l:href="#addbook.png"/>), chá»n má»™t
+táºp tin và chỉnh sá»a thông tin cá»§a nó. Lần sau bạn có thể sá» dụng <code>thư
+viện</code> (<image l:href="#books.png" voffset="-6"/>) để mở táºp tin nà y.</p> +<empty-line/> +<subtitle><p>Những trang Web liên quan</p></subtitle> +<p>Bạn có thể tìm thêm thông tin vá» chương trình nà y tại <a
+l:href="http://www.fbreader.org"> trang chá»§ cá»§a Reader </a>.</p>
+<p>Nếu bạn muốn được thông báo vỠnhững bản phát hà nh mới, vui lòng đăng kà tại
+<a l:href="http://freshmeat.net/projects/fbreader">dự án Reader tại
+freshmeat</a>.</p> +<p>Nếu bạn có bất kỳ câu há»i hay lá»i đỠnghị nà o, vui lòng sá» dụng <a
+l:href="http://groups.google.com/group/fbreader">Reader group tại
+googlegroups</a>.</p> + +</body> +<binary content-type="image/png" id="settings.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFiIVNd73 +uAAACXNJREFUWMO1l2mMndV5x3/nPe9617l37szYM+OVMXbGGHATO6ZesA04 +JjQqNBtKgWwKigNlcZUUukREDUIKJU1oVUSkqIkVURwsI4PsELCJwQFDvWMb +jBnPeGYym5eZuXOX977bOf3QUiEZV5i2z5dzpOf/6Pw+PHrO/xFcQuzsf+H1 +3f42e/jM2e7yVOC1F+awsHmRv2b2qj+d785/iY8R4qMKh2u9LZt6fnVm0+hj +JNqkUJhBTk5n4LVBVk1bFn5j5W23Lmtf/eylAhgfVVixJrr2T75BNQUqaxOL +iM5ZreRnOmw59G/23/3mwWeeGP7R7f9vAHU5NafP78PzpiGTLNK3KEqPfMaE +tpjDyWH593se2fTEKz/dcCkA5kcVvn56/xzHFgSNEGkLIGKiNsXSq1dwdN9J +lBFCOuLRsUf+5Z97Hi+ubL3ulcHg1Iod1WfmrOSGvuuyNz7RWmop/48A23uf +W/HbY9sXlUqlw9//44f3fjB3Ohy6pmpHGK7Gsi1Qmpqq4BZnM7t7Fsf6DxNW +oRhY7Ozf8cNTzjscyb7OdaWbeGPwFcaHxm8frg6tbs90nP3QJnxt8tVr/vHA +w7sPnH3bTlREWqRo1dOH5pUWjBpZ6b3VONQ9lh3BkwJhakxh0uK0cuXsxYwN +j3DovQM0nDptC1qZZnbQn36P9spM8m6Otan1nJw8wblna/9+9/X3r148c7H/ +/rvy/UvLuvw9z1V/varuxERpH9+tMWVM5qaMyfaRZLjlrDGG2WxgSUEiI6Rr +oEVCpTaFcAVWUZLtTFMrljnnjtI20YllmzRMnxE1xGJvGft79ncMnjvd/ebT ++zdf0ISRDpNYRGS0R0Z4ZFwXO6OomGeom2exUzGmjhAaHMdB2wrtKSaCcSaC +c+i0xvCg0CjRHs6g4BYpZ8eZtCeYzkw+Zaxg7vQutv3h6Vv+6rV777wAYGX3 +6p9Pq3eGZsNETwlETSC1gWFoLFdgW5KkGmApB9v0ULEGCdliFukaCFOjpMI0 +TWZMdDEkTyNDiyv0Er5ib2Bf401e6n2RKWeSPW/t/toFALdM/1LPZ0t/9uPQ +Usi0jeOlsR0PLQWNKEQaDvlUCUd50FDY0gItkFIixH+dWoCpGMj00BJPJ21n ++KL8Kk9sf5x/+Nmj9GX7aJYtfGrup3/xoZPwrfKRzLqD6/qJkyKxIuWaSFuC +AZZlY0kbNRFTpkxbVwnLMZGxRGKQbU1T11VkzcRoUph4zE+uov9cP3u3HkRr +TZjzuYqFm3fd/satFx3FXz/85RcP9Ry6wU818GUN05Y0Z5tRkxEnDvYgT3no +aTEVFdH+ifwLS25Y7JZT46sTmZAVeXy7gq/r5MIC1lCK/VsOkbGyVGUZUVJD +v12xb+FVs64oX3QS9lV68xU5RWD4mJ5FNp1jfHCCngN9NIZAKEGlHpGaFM9/ +t/TQnRu8BzZ0BrN+j4yRiaBarjNbdJFrFCjXJ6m2VRiUw8jI4pt/tOG+Dz5+ +AcCBscOLBmt9S3U+IbYjGmEdERsE5wPC0YQWmcMpGngmLClds+X+dfcPrs+s +P9HFgq1u7BIZDTrznVQnaxRSzSy6fBH5VAYjgoLTRG3MH7/oX/Do0Ue6v7/j +wd/U/DqKBGkKhBAEQUClUiMIQMeas7qKFzgsvWzpy+/Xzst3vdwUNdFwKlRU +lTDn8we/n4Jd5Luf+1tuvuxmRvvPsqf/d5tePLnt2gsAPr/jxh/908EfH99n +/74jK3PEUxrVAMdywNBYKYN8m4VKKbABQyHlf88wkki9o9R/NpQvKsRGjMwJ +huvDSBe+dfO3uGvD3YwOjHY8+PRDuzZuv++He8qvSgB5x5YvfeXV8y8/5rfW +SYox2WoGhMZ0LEIVYQhBc66Z6aVpBI2ArGdRs+sUdMuRd3a8ewRgyX2Lr3jH +OvJtqSwSCyzl4OAwGY3TG77LGXuY+YUF3LrqNp4f3G4c7Du46kTPiaX3bLxn +q5EpZD9peS4oA1WRVBoVMAWGZaB1Agl4TorpLR3M6ZxDLluEvOBY460vbN77 +zAyAIWtgbWCFqEBiBQ7ChyiKSFIBQabG8dphdk/t5PWp3dxy22dw5mn29O5c +v/vYznvNjJdLXOVRn4pocrPIpgahCEgCH8uxsYRFWA1pnd3GmvVreP7AdsLz +IcOj/Z/73tt3NW48eu3vTsYnvqi0AEvjxinqokJsh8jYICcKRCJmPDdML2/T +FrQSOJM0zUyRbU0hH/ibBwdS5OckAZUoikZSDTcXJrGt0prE0YSRwrQdGkaI +KgraO9pwcg5WkyQ/L71QFcObIoIZtmkRqxihYlKGgFgRS5c4NPASG60VdVMT +mYqju4fonOjkG1d/+4EP9YT3Hrxz6fb3nttWz1enua5L2sxCoPA8D09mUWZE +YARYWYmyEkIdkE6nMU2TQAtM0SBxEpTnoquKVulRiyYIcgp1PM3I3jOszK19 ++Zdffuq6i5rS5b+68oHR/NAjsRuTdly01pgWEKewUybKBtMFLAMhNK7tIYRB +wc5Rq56hInwC00ZNGSzrvPqlyclyX9VOmH2iM5xbnLd3+Yxrn12WX+5f1JIV +0qWeMXsMP64jhIFjmSjDwEwLYqmIVUgUC1zTRQoTFWmkEAzGISePn6JyPoIG +XB7M2fvk3ZvXXbInPBdPtpRVDdO2sUWWuBEThBGm5yMtiekIhBaoWBEmIUJK +crk0ncPNjPVILCNCiDzGZKbvY7nikejM1XUdIHCgITGVi2enkZGJTAxEbKIi +iANFEoJKNI7t0VLoRqkcwktBVlLV5/MfC0Da8TWuKdHVkKgSIqKEeq1MUtXQ +sDBCSVxNSBoKoQVJmOD7AfOdEs3KxEpCIrNKVExaLhngod3fywgVdsskwYw1 +OctFEjEwOMHI6dEBf6LeJxITlETHmjhW+L5PpVKmng1opENqZkxkJLSVWocu +GaDUMiNfkO2yUouoFMuM6CGCfuGv4/o7an+RzOr7/Ojcxy/7+XfmxZdzPhom +cCZQ0qcancfNVFGWoins4Kb0HQMPL3/yLz/Wbrip9xcbtx3Z8oMz5ZHM3OL8 +d9d2rfvzr3Z/7cAHNT849tc/2Tr61L1TqSlcK40KFNfOvp53dx1nbeeap/5k +4We/88lpa8r8b2L/8JszL5Y7VNtv37fvrl1dWzv0ghfm6lW7VuiNRzf2/uvx +J9f/n2/HF13ZB17K//rUU4/JlLnoypYlm5fnrvrZlaVPVz9q/X8A8yhCVXd4 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +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 +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/help/MiniHelp.desktop.zh.fb2 b/reader/data/help/MiniHelp.desktop.zh.fb2 new file mode 100644 index 0000000..6795b77 --- /dev/null +++ b/reader/data/help/MiniHelp.desktop.zh.fb2 @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><author><last-name>Reader</last-name></author> <book-title>关于 Reader</book-title> <lang>zh</lang></title-info></description> +<body> +<title><p>关于 Reader &ReaderVersion;</p></title> +<p>Reader是一款基于Linux/Windows XP PDA/UMPC/å°å¼ç”µè„‘的电å书阅读软件,它支æŒå¤šç§ç”µåä¹¦æ ¼å¼ï¼Œå¦‚<code>ePub</code>,<code>fb2</code>,<code>chm</code>, <code>rtf</code>,<code>plucker</code>ç‰ï¼Œä¹Ÿæ”¯æŒç›´æŽ¥é˜…读<code>zip</code>, <code>tar</code>, <code>gzip</code>,<code>bzip2</code>å˜æ¡£æ ¼å¼çš„æ–‡ä»¶ã€‚</p> +<p>Reader采用<a l:href="http://www.gnu.org/licenses/gpl.html">GNU GPL</a>æ¡æ¬¾å‘布。</p> +<p>å¦‚æžœä½ å–œæ¬¢Readerå¹¶æ„¿æ„æ”¯æŒå®ƒçš„å‘展,请访问“<a l:href="http://www.fbreader.org/donation/make.php">æèµ 页é¢</a>â€ã€‚</p> +<empty-line/> +<subtitle><p>怎么使用</p></subtitle> +<p>Reader会自动在 图书路径 设置选项ä¸çš„目录里é¢å¯»æ‰¾ <code>ePub</code>ã€<code>fb2</code>å’Œ<code>OpenReader</code>æ ¼å¼çš„书。</p> +<p>å› æ¤ï¼Œä½ è¦åšçš„第一件事情是设置这个 å›¾ä¹¦è·¯å¾„ã€‚æ‰“å¼€è®¾ç½®é€‰é¡¹å¯¹è¯æ¡†ï¼ˆç‚¹å‡»å·¥å…·æ 上<image l:href="#settings.png" voffset="-6"/>按钮),修改书库选项å¡ä¸‹çš„图书路径。它å¯ä»¥åŒ…å«å¤šä¸ªå«æœ‰<code>*.epub</code>, <code>*.fb2</code>,<code>*.orb</code>ç‰æ ¼å¼æ–‡ä»¶çš„目录,列表ä¸çš„目录用分å·éš”开。</p> +<p>打开书库(å•击<image l:href="#books.png" voffset="-6"/>),从书目列表ä¸é€‰æ‹©ä¸€æœ¬ä¹¦é˜…读。</p> +<p>è¦é˜…è¯»å…¶ä»–æ ¼å¼çš„电åä¹¦ï¼Œä½ éœ€è¦å•ç‹¬æŠŠå®ƒæ·»åŠ åˆ°ä¹¦åº“ä¸ã€‚æ‰“å¼€æ·»åŠ åˆ°ä¹¦åº“çš„å¯¹è¯æ¡†ï¼ˆ<image l:href="#addbook.png" voffset="-6"/>),选择一个文件,编辑文件信æ¯ã€‚ä¸‹æ¬¡ä½ å°±å¯ä»¥ä½¿ç”¨ä¹¦åº“æ¥æ‰“å¼€æ¤æ–‡ä»¶äº†ï¼ˆ<image l:href="#books.png" voffset="-6"/>)。</p> +<empty-line/> +<subtitle><p>相关网站</p></subtitle> +<p>更多有关Reader的信æ¯å¯ä»¥åœ¨<a l:href="http://www.fbreader.org">Reader网站</a>查阅到。</p> +<p>如果您想知é“Reader的最新版本信æ¯ï¼Œè¯·è®¢é˜…<a l:href="http://freshmeat.net/projects/fbreader">Reader project at freshmeat</a>。</p> +<p>如果您有任何的问题或建议,请使用googlegroupsä¸çš„“<a l:href="http://groups.google.com/group/fbreader">Reader group</a>â€ã€‚</p> +</body> +<binary content-type="image/png" id="settings.png"> +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 +BFAAAAAASUVORK5CYII= +==== +</binary> +<binary content-type="image/png" id="books.png"> +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 +==== +</binary> +<binary content-type="image/png" id="addbook.png"> +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/ +AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2AsdFwUYkGhT +VwAACFpJREFUWMOtl0mMnVeZhp8z/PMd69at0RU7cdmJHRwldhoMLJgUETCI +VjdNN0IsWIAEEkJCAsECBGKBRLOjV91qNYEgEIhByIJuIYQUhZBBmIDJ4MR2 +OXZVuQbXcO9/7/3Hcw6LRqyCKMDf+nyvHr36zvudIzhg/T69KAeNQStJk9SK +6uG0GC1vDG+du7a++tCVyyvMT8//8PSpB758V2fuxdl4IZ/xZquD6IqDAnzi +qU+8+yn12w+v1NffoazUU1GHkwvHOdJY4OmfPsnVi5cxmeN0dCb/6Hs/fvc7 +T73j+kF09YEdMM/9+En7GESWJIppxxoRl4SBwJqCShjK0HFp7+XQBrZxUF15 +0IPGVBBaVArxQNDci5gZz3JMnmDaLOKbDrVNqOOaXOTmtgMkpkGiu5gF2I4K +brqMAocnfChLRJ0T+RbjWXJT3n6AurND4GrEEKhrcrXFnthB08ZzfZSLUdrh +lT4zVbs+qO6BZ8CXEW6ocbHADxWTfMLm7gb5TE6326WXzDDxRsTLmuvt9frr +N34QD9Jhcbw9S7+1RDuYdsf8OXsggH//1ddcJXbYU1vE4hBCOH40eoTS1JA7 +rG8xypLqlJqK1507y4NvexACy0r6G9aClZVBuapmkkV25Ygv/c8nmY1muPDi +L06fvuctz/5FgP+69B+M/A2qZEKUHCIsfNZaL5GHGl/4lEVJrUte3H+eb6z9 +N71ihsXeIcgdvSnBOqu6jhKO1wsc8ae4tHqRVd1i895z0YEcWBEvUwUWAhDR +dQKjqT1ASlzhECGICDI/50L2NJFJWLKHUEKxMO5TJZamhDLdpdM7wXR7jkpH +bFaVOxCAlh5WFjACIwzCBoSFpDKaWhd4yqM0FQjYD1L2q5SN0QaNRsy1okdu +BEveHZyI72BCxTBVFGGE7XXkgQCcM0RO4FUBe7VFaw9TTDBU+E0PIQR1ZbDS +ggUUOAvjesJYTLBlRFUqVjsbrLNNJ1mkIIKiOtgQmrjGCgikBjGmUA4jQTUN +NY5qUuNHAdrXZPkEFSqEL7GlBVnjhYbaZOyKHVaHN4hFTNu2aL9KPLwqwIn0 +FDfNKqPuPr1Ri67sc7l7GSMs0dhiOh5l6GCY8Yb4QY5693PTbHJVvkDQrlit +hmgk49pyRdXshBkLdZ+Rtyj+5mV03xNn3O/qizRCyYgKQsnhYJb3HXsv8U6f +377yHOtqhSBXhNMN0nFGkk9xZ3jmSvWK97M3z7/u1w/fc/aR+VZY/U1BJIyG +oKJCgdIgPALn03AJN369zqVfXWXi7RLKO/j8+z7wrx+4/4Pf/f/OHwLwyN+b +hM08I7aOiVeD7xASBukuWztbbNwcItKYVqOBsdPMVkd/cNujWIYhToKnocLg +hGGiarbYZhAIZKeLcQKnayxG3vZldEumZAnoGpgAFdjQsFFtsSNT8khRighf +G8bU0W13oJn5ZUvja9UAT5ExxljD5s4WZTVLpCN8r02rgJ9fXXv0i088U4U2 +2u62Y6a74cWuUuWC374URMHIVNX1o21/+0+34Oq1FVkURVDXtbtyU+oX/A2X +pv3wxZu3VLFTBM1m2v3O6NPn6a0sEQG9CMICEVmW7GHUS4fRK4cotyUuG9O7 +5yxHDv0DnZFHIismwQR0zbSfQDnBVzDfbn/v6MLcR8Q/feWRzwyj7mKhdGcy +GfWSIpiSykxVpu4JnXQslZTJOhde+k8y8SxCgpdFqMRjEg+hhuTWEmZtCmxI +JWLuO/12mr0TVDpBBgItSgKhEKWgU62zNYLcauZU/oy+q99++OXd0ZtaQYhO +FNuNEqksGIMShrq2WGUQQoCRWGkpPYerC8j/aGIZIEwTQQNPVPhYQuXAFti8 +AmnQ2kdZQX/pLg5PL1GVMLn+wnH91Q/945u/8Oj581NTnXPtRkBsHE7DyDjS +WrOWptzM9rgetdkcN8kZoEKPujYgJRQx2b5B5R5+Mo3WA6rKkGcpRSWRytHt +tjh6+BDzvT5b44yd4YRrl68QDzYiDXBnolnsBrRDxWzpkJFH7YWUcZeJ0qTB +Ud50qkVqXuHx8gmqQc211TU2x7fItwpMV+B3A8rApydOMiw11WBCrz/Pwtwc +zdgnG2U8v/k8q2nBYD9luLXBfTMNXwD832NPnT+8MHOuGylsSyGlxDmBFjFK +hiShJqs2QaZQLeFMzdjmTDBkgzGTtYzfX8k5/8wVbswLxuMxWvo0ojYaQZWN +cOWIQDu294b02i1mW5E9Ndf5rAYYW499owlUDOMcTwqEA0GBcCUm8/CtQriI +UVWAGJGZMeu7e4z3bxEpRapTLqXP0j32MDe3XqLK9smjjFD6aGvxRY1ScPbY +YXrN5JWjM+2zHzv3+g39/cd/99DKrdG5PTlkfVzymriDDD0CX6I9ifYAT6JU +jHOOduGBVER+E2NihrlF1CPqyQiBZTwYQpXTDqAhS7yyohPHLM7NsLjYYlGF +z/Xb4QP/8tYzFYD+xVMXPnNjUK4IT98pXUXpcqLQpxtpOrFmphky12wz25ki +UAHT0RTD8XWsFpRlgJ/X2HxCOcjphNOMshSRp0SRYDaO6PenWez16bbFhSiu +/+1j73zjy6+6jh/9yeNqc2v7/md29u92Si/XUiyPjTuZlvXJtKqj3FqMkNxn +90mCkE7UIglCnBPsDgesbW+yMxgw0Ufot2MWplvMJpqOV+7Ot/x/PnHX0mPH +jyy6melZ91e/Bz73zf9d3B4Ol/OiuvuWbt1fFMXyZDK5M8+L5cLWlA5KZyit +4YGoQSsO6TejzcV+61P3Hp7/1rtef6/9u3/Hf67e/7Vvnxlm4+W8LJeNccv9 +/cHM8WNHf/na06e++p6zJ8vVQSYOtSP35/r/ABPJ7DnErBKYAAAAAElFTkSu +QmCC +==== +</binary> +</FictionBook> diff --git a/reader/data/icons/application/16x16.png b/reader/data/icons/application/16x16.png Binary files differnew file mode 100644 index 0000000..42baa62 --- /dev/null +++ b/reader/data/icons/application/16x16.png diff --git a/reader/data/icons/application/26x26.png b/reader/data/icons/application/26x26.png Binary files differnew file mode 100644 index 0000000..c0b254b --- /dev/null +++ b/reader/data/icons/application/26x26.png diff --git a/reader/data/icons/application/32x24.png b/reader/data/icons/application/32x24.png Binary files differnew file mode 100644 index 0000000..9b353ee --- /dev/null +++ b/reader/data/icons/application/32x24.png diff --git a/reader/data/icons/application/32x32.png b/reader/data/icons/application/32x32.png Binary files differnew file mode 100644 index 0000000..7c5ad30 --- /dev/null +++ b/reader/data/icons/application/32x32.png diff --git a/reader/data/icons/application/48x48.png b/reader/data/icons/application/48x48.png Binary files differnew file mode 100644 index 0000000..d1b42d0 --- /dev/null +++ b/reader/data/icons/application/48x48.png diff --git a/reader/data/icons/application/64x43.png b/reader/data/icons/application/64x43.png Binary files differnew file mode 100644 index 0000000..1c117e7 --- /dev/null +++ b/reader/data/icons/application/64x43.png diff --git a/reader/data/icons/application/64x64.png b/reader/data/icons/application/64x64.png Binary files differnew file mode 100644 index 0000000..4fa52c4 --- /dev/null +++ b/reader/data/icons/application/64x64.png diff --git a/reader/data/icons/application/Reader.icns b/reader/data/icons/application/Reader.icns Binary files differnew file mode 100644 index 0000000..95de917 --- /dev/null +++ b/reader/data/icons/application/Reader.icns diff --git a/reader/data/icons/application/desktop.png b/reader/data/icons/application/desktop.png new file mode 120000 index 0000000..b463b00 --- /dev/null +++ b/reader/data/icons/application/desktop.png @@ -0,0 +1 @@ +48x48.png
\ No newline at end of file diff --git a/reader/data/icons/back_button.png b/reader/data/icons/back_button.png Binary files differnew file mode 100755 index 0000000..aea6df8 --- /dev/null +++ b/reader/data/icons/back_button.png diff --git a/reader/data/icons/back_button_disabled.png b/reader/data/icons/back_button_disabled.png Binary files differnew file mode 100755 index 0000000..babd3c4 --- /dev/null +++ b/reader/data/icons/back_button_disabled.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-authorinfo.png b/reader/data/icons/booktree/22x22-transparent-png/tree-authorinfo.png Binary files differnew file mode 100644 index 0000000..6dc0485 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-authorinfo.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-bookinfo.png b/reader/data/icons/booktree/22x22-transparent-png/tree-bookinfo.png Binary files differnew file mode 100644 index 0000000..d9949ea --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-bookinfo.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-download-demo.png b/reader/data/icons/booktree/22x22-transparent-png/tree-download-demo.png Binary files differnew file mode 100644 index 0000000..91ed9f2 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-download-demo.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-download-epub.png b/reader/data/icons/booktree/22x22-transparent-png/tree-download-epub.png Binary files differnew file mode 100644 index 0000000..a23e6aa --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-download-epub.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-download-fb2.png b/reader/data/icons/booktree/22x22-transparent-png/tree-download-fb2.png Binary files differnew file mode 100644 index 0000000..7c19f1e --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-download-fb2.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-download-mobi.png b/reader/data/icons/booktree/22x22-transparent-png/tree-download-mobi.png Binary files differnew file mode 100644 index 0000000..9282d6d --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-download-mobi.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-local-demo.png b/reader/data/icons/booktree/22x22-transparent-png/tree-local-demo.png Binary files differnew file mode 100644 index 0000000..3cbdda9 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-local-demo.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-local-epub.png b/reader/data/icons/booktree/22x22-transparent-png/tree-local-epub.png Binary files differnew file mode 100644 index 0000000..d36c7c9 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-local-epub.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-local-fb2.png b/reader/data/icons/booktree/22x22-transparent-png/tree-local-fb2.png Binary files differnew file mode 100644 index 0000000..212c446 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-local-fb2.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-local-mobi.png b/reader/data/icons/booktree/22x22-transparent-png/tree-local-mobi.png Binary files differnew file mode 100644 index 0000000..11bc581 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-local-mobi.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-open-in-browser.png b/reader/data/icons/booktree/22x22-transparent-png/tree-open-in-browser.png Binary files differnew file mode 100644 index 0000000..83fc6a0 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-open-in-browser.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-order-series.png b/reader/data/icons/booktree/22x22-transparent-png/tree-order-series.png Binary files differnew file mode 100644 index 0000000..bf9db9b --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-order-series.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-purchase.png b/reader/data/icons/booktree/22x22-transparent-png/tree-purchase.png Binary files differnew file mode 100644 index 0000000..6d9af32 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-purchase.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-removebook.png b/reader/data/icons/booktree/22x22-transparent-png/tree-removebook.png Binary files differnew file mode 100644 index 0000000..9b73cb6 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-removebook.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-removetag.png b/reader/data/icons/booktree/22x22-transparent-png/tree-removetag.png Binary files differnew file mode 100644 index 0000000..5154445 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-removetag.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-strut.png b/reader/data/icons/booktree/22x22-transparent-png/tree-strut.png Binary files differnew file mode 100644 index 0000000..54ac724 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-strut.png diff --git a/reader/data/icons/booktree/22x22-transparent-png/tree-taginfo.png b/reader/data/icons/booktree/22x22-transparent-png/tree-taginfo.png Binary files differnew file mode 100644 index 0000000..982f154 --- /dev/null +++ b/reader/data/icons/booktree/22x22-transparent-png/tree-taginfo.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-authorinfo.png b/reader/data/icons/booktree/28x28-transparent-png/tree-authorinfo.png Binary files differnew file mode 100644 index 0000000..1c56ba9 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-authorinfo.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-bookinfo.png b/reader/data/icons/booktree/28x28-transparent-png/tree-bookinfo.png Binary files differnew file mode 100644 index 0000000..fa6b0f2 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-bookinfo.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-download-epub.png b/reader/data/icons/booktree/28x28-transparent-png/tree-download-epub.png Binary files differnew file mode 100644 index 0000000..cc83f5a --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-download-epub.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-download-fb2.png b/reader/data/icons/booktree/28x28-transparent-png/tree-download-fb2.png Binary files differnew file mode 100644 index 0000000..0b63cb3 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-download-fb2.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-download-mobi.png b/reader/data/icons/booktree/28x28-transparent-png/tree-download-mobi.png Binary files differnew file mode 100644 index 0000000..7840bc7 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-download-mobi.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-local-epub.png b/reader/data/icons/booktree/28x28-transparent-png/tree-local-epub.png Binary files differnew file mode 100644 index 0000000..e41c1e1 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-local-epub.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-local-fb2.png b/reader/data/icons/booktree/28x28-transparent-png/tree-local-fb2.png Binary files differnew file mode 100644 index 0000000..834f75a --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-local-fb2.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-local-mobi.png b/reader/data/icons/booktree/28x28-transparent-png/tree-local-mobi.png Binary files differnew file mode 100644 index 0000000..aa64a3b --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-local-mobi.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-open-in-browser.png b/reader/data/icons/booktree/28x28-transparent-png/tree-open-in-browser.png Binary files differnew file mode 100644 index 0000000..87d8e7a --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-open-in-browser.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-orderseries.png b/reader/data/icons/booktree/28x28-transparent-png/tree-orderseries.png Binary files differnew file mode 100644 index 0000000..026d07a --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-orderseries.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-removebook.png b/reader/data/icons/booktree/28x28-transparent-png/tree-removebook.png Binary files differnew file mode 100644 index 0000000..f1fcc5c --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-removebook.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-removetag.png b/reader/data/icons/booktree/28x28-transparent-png/tree-removetag.png Binary files differnew file mode 100644 index 0000000..2d0c29f --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-removetag.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-strut.png b/reader/data/icons/booktree/28x28-transparent-png/tree-strut.png Binary files differnew file mode 100644 index 0000000..6e05713 --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-strut.png diff --git a/reader/data/icons/booktree/28x28-transparent-png/tree-taginfo.png b/reader/data/icons/booktree/28x28-transparent-png/tree-taginfo.png Binary files differnew file mode 100644 index 0000000..9dab5ad --- /dev/null +++ b/reader/data/icons/booktree/28x28-transparent-png/tree-taginfo.png diff --git a/reader/data/icons/booktree/desktop b/reader/data/icons/booktree/desktop new file mode 120000 index 0000000..5524476 --- /dev/null +++ b/reader/data/icons/booktree/desktop @@ -0,0 +1 @@ +22x22-transparent-png
\ No newline at end of file diff --git a/reader/data/icons/booktree/new/booktree-author.png b/reader/data/icons/booktree/new/booktree-author.png Binary files differnew file mode 100644 index 0000000..2e403d7 --- /dev/null +++ b/reader/data/icons/booktree/new/booktree-author.png diff --git a/reader/data/icons/booktree/new/booktree-book.png b/reader/data/icons/booktree/new/booktree-book.png Binary files differnew file mode 100644 index 0000000..3082f5a --- /dev/null +++ b/reader/data/icons/booktree/new/booktree-book.png diff --git a/reader/data/icons/booktree/new/booktree-catalog.png b/reader/data/icons/booktree/new/booktree-catalog.png Binary files differnew file mode 100644 index 0000000..0b246be --- /dev/null +++ b/reader/data/icons/booktree/new/booktree-catalog.png diff --git a/reader/data/icons/booktree/new/booktree-tag.png b/reader/data/icons/booktree/new/booktree-tag.png Binary files differnew file mode 100644 index 0000000..289b717 --- /dev/null +++ b/reader/data/icons/booktree/new/booktree-tag.png diff --git a/reader/data/icons/booktree/new/searchresult.png b/reader/data/icons/booktree/new/searchresult.png Binary files differnew file mode 100644 index 0000000..92604a0 --- /dev/null +++ b/reader/data/icons/booktree/new/searchresult.png diff --git a/reader/data/icons/filetree/12x12-png/fb2.png b/reader/data/icons/filetree/12x12-png/fb2.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/fb2.png diff --git a/reader/data/icons/filetree/12x12-png/folder.png b/reader/data/icons/filetree/12x12-png/folder.png Binary files differnew file mode 100644 index 0000000..f0c1cf8 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/folder.png diff --git a/reader/data/icons/filetree/12x12-png/html.png b/reader/data/icons/filetree/12x12-png/html.png Binary files differnew file mode 100644 index 0000000..686ac26 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/html.png diff --git a/reader/data/icons/filetree/12x12-png/mobipocket.png b/reader/data/icons/filetree/12x12-png/mobipocket.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/mobipocket.png diff --git a/reader/data/icons/filetree/12x12-png/oeb.png b/reader/data/icons/filetree/12x12-png/oeb.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/oeb.png diff --git a/reader/data/icons/filetree/12x12-png/openreader.png b/reader/data/icons/filetree/12x12-png/openreader.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/openreader.png diff --git a/reader/data/icons/filetree/12x12-png/palm.png b/reader/data/icons/filetree/12x12-png/palm.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/palm.png diff --git a/reader/data/icons/filetree/12x12-png/plucker.png b/reader/data/icons/filetree/12x12-png/plucker.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/plucker.png diff --git a/reader/data/icons/filetree/12x12-png/rtf.png b/reader/data/icons/filetree/12x12-png/rtf.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/rtf.png diff --git a/reader/data/icons/filetree/12x12-png/tcr.png b/reader/data/icons/filetree/12x12-png/tcr.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/tcr.png diff --git a/reader/data/icons/filetree/12x12-png/unknown.png b/reader/data/icons/filetree/12x12-png/unknown.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/unknown.png diff --git a/reader/data/icons/filetree/12x12-png/upfolder.png b/reader/data/icons/filetree/12x12-png/upfolder.png Binary files differnew file mode 100644 index 0000000..f0c1cf8 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/upfolder.png diff --git a/reader/data/icons/filetree/12x12-png/weasel.png b/reader/data/icons/filetree/12x12-png/weasel.png Binary files differnew file mode 100644 index 0000000..77d70d4 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/weasel.png diff --git a/reader/data/icons/filetree/12x12-png/zipfolder.png b/reader/data/icons/filetree/12x12-png/zipfolder.png Binary files differnew file mode 100644 index 0000000..985e826 --- /dev/null +++ b/reader/data/icons/filetree/12x12-png/zipfolder.png diff --git a/reader/data/icons/filetree/22x22-transparent-ico/fb2.ico b/reader/data/icons/filetree/22x22-transparent-ico/fb2.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/fb2.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/folder.ico b/reader/data/icons/filetree/22x22-transparent-ico/folder.ico Binary files differnew file mode 100644 index 0000000..b7c3313 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/folder.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/html.ico b/reader/data/icons/filetree/22x22-transparent-ico/html.ico Binary files differnew file mode 100644 index 0000000..4bda4b7 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/html.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/mobipocket.ico b/reader/data/icons/filetree/22x22-transparent-ico/mobipocket.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/mobipocket.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/oeb.ico b/reader/data/icons/filetree/22x22-transparent-ico/oeb.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/oeb.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/openreader.ico b/reader/data/icons/filetree/22x22-transparent-ico/openreader.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/openreader.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/palm.ico b/reader/data/icons/filetree/22x22-transparent-ico/palm.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/palm.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/plucker.ico b/reader/data/icons/filetree/22x22-transparent-ico/plucker.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/plucker.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/rtf.ico b/reader/data/icons/filetree/22x22-transparent-ico/rtf.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/rtf.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/tcr.ico b/reader/data/icons/filetree/22x22-transparent-ico/tcr.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/tcr.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/unknown.ico b/reader/data/icons/filetree/22x22-transparent-ico/unknown.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/unknown.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/upfolder.ico b/reader/data/icons/filetree/22x22-transparent-ico/upfolder.ico Binary files differnew file mode 100644 index 0000000..6f2caf7 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/upfolder.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/weasel.ico b/reader/data/icons/filetree/22x22-transparent-ico/weasel.ico Binary files differnew file mode 100644 index 0000000..31d71c6 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/weasel.ico diff --git a/reader/data/icons/filetree/22x22-transparent-ico/zipfolder.ico b/reader/data/icons/filetree/22x22-transparent-ico/zipfolder.ico Binary files differnew file mode 100644 index 0000000..b9cc03b --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-ico/zipfolder.ico diff --git a/reader/data/icons/filetree/22x22-transparent-png/fb2.png b/reader/data/icons/filetree/22x22-transparent-png/fb2.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/fb2.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/folder.png b/reader/data/icons/filetree/22x22-transparent-png/folder.png Binary files differnew file mode 100644 index 0000000..45f71b1 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/folder.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/html.png b/reader/data/icons/filetree/22x22-transparent-png/html.png Binary files differnew file mode 100644 index 0000000..51beaff --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/html.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/mobipocket.png b/reader/data/icons/filetree/22x22-transparent-png/mobipocket.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/mobipocket.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/oeb.png b/reader/data/icons/filetree/22x22-transparent-png/oeb.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/oeb.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/openreader.png b/reader/data/icons/filetree/22x22-transparent-png/openreader.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/openreader.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/palm.png b/reader/data/icons/filetree/22x22-transparent-png/palm.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/palm.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/plucker.png b/reader/data/icons/filetree/22x22-transparent-png/plucker.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/plucker.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/rtf.png b/reader/data/icons/filetree/22x22-transparent-png/rtf.png Binary files differnew file mode 100644 index 0000000..c9baeda --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/rtf.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/tcr.png b/reader/data/icons/filetree/22x22-transparent-png/tcr.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/tcr.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/unknown.png b/reader/data/icons/filetree/22x22-transparent-png/unknown.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/unknown.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/upfolder.png b/reader/data/icons/filetree/22x22-transparent-png/upfolder.png Binary files differnew file mode 100644 index 0000000..27d1214 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/upfolder.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/weasel.png b/reader/data/icons/filetree/22x22-transparent-png/weasel.png Binary files differnew file mode 100644 index 0000000..d68a56c --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/weasel.png diff --git a/reader/data/icons/filetree/22x22-transparent-png/zipfolder.png b/reader/data/icons/filetree/22x22-transparent-png/zipfolder.png Binary files differnew file mode 100644 index 0000000..dc76287 --- /dev/null +++ b/reader/data/icons/filetree/22x22-transparent-png/zipfolder.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/fb2.png b/reader/data/icons/filetree/32x32-transparent-png/fb2.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/fb2.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/folder.png b/reader/data/icons/filetree/32x32-transparent-png/folder.png Binary files differnew file mode 100644 index 0000000..0171b09 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/folder.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/html.png b/reader/data/icons/filetree/32x32-transparent-png/html.png Binary files differnew file mode 100644 index 0000000..a896697 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/html.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/mobipocket.png b/reader/data/icons/filetree/32x32-transparent-png/mobipocket.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/mobipocket.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/oeb.png b/reader/data/icons/filetree/32x32-transparent-png/oeb.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/oeb.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/openreader.png b/reader/data/icons/filetree/32x32-transparent-png/openreader.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/openreader.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/palm.png b/reader/data/icons/filetree/32x32-transparent-png/palm.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/palm.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/plucker.png b/reader/data/icons/filetree/32x32-transparent-png/plucker.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/plucker.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/rtf.png b/reader/data/icons/filetree/32x32-transparent-png/rtf.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/rtf.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/tcr.png b/reader/data/icons/filetree/32x32-transparent-png/tcr.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/tcr.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/unknown.png b/reader/data/icons/filetree/32x32-transparent-png/unknown.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/unknown.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/upfolder.png b/reader/data/icons/filetree/32x32-transparent-png/upfolder.png Binary files differnew file mode 100644 index 0000000..2fa4b0d --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/upfolder.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/weasel.png b/reader/data/icons/filetree/32x32-transparent-png/weasel.png Binary files differnew file mode 100644 index 0000000..928a679 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/weasel.png diff --git a/reader/data/icons/filetree/32x32-transparent-png/zipfolder.png b/reader/data/icons/filetree/32x32-transparent-png/zipfolder.png Binary files differnew file mode 100644 index 0000000..4b55b50 --- /dev/null +++ b/reader/data/icons/filetree/32x32-transparent-png/zipfolder.png diff --git a/reader/data/icons/filetree/desktop b/reader/data/icons/filetree/desktop new file mode 120000 index 0000000..5524476 --- /dev/null +++ b/reader/data/icons/filetree/desktop @@ -0,0 +1 @@ +22x22-transparent-png
\ No newline at end of file diff --git a/reader/data/icons/forward_button.png b/reader/data/icons/forward_button.png Binary files differnew file mode 100644 index 0000000..a92d416 --- /dev/null +++ b/reader/data/icons/forward_button.png diff --git a/reader/data/icons/forward_button_disabled.png b/reader/data/icons/forward_button_disabled.png Binary files differnew file mode 100755 index 0000000..105cc93 --- /dev/null +++ b/reader/data/icons/forward_button_disabled.png diff --git a/reader/data/icons/refresh-icon-1.png b/reader/data/icons/refresh-icon-1.png Binary files differnew file mode 100644 index 0000000..29659b9 --- /dev/null +++ b/reader/data/icons/refresh-icon-1.png diff --git a/reader/data/icons/refresh-icon-2.png b/reader/data/icons/refresh-icon-2.png Binary files differnew file mode 100755 index 0000000..a6bf621 --- /dev/null +++ b/reader/data/icons/refresh-icon-2.png diff --git a/reader/data/icons/refresh-icon.svg b/reader/data/icons/refresh-icon.svg new file mode 100644 index 0000000..74758be --- /dev/null +++ b/reader/data/icons/refresh-icon.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd"> +<svg baseProfile="tiny" height="70px" version="1.1" viewBox="0 0.037 70 70" width="70px" x="0px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"> +<radialGradient cx="35" cy="4.8076" gradientUnits="userSpaceOnUse" id="SVGID_1_" r="55.8809"> +<stop offset="0" style="stop-color:#FFFFFF"/> +<stop offset="1" style="stop-color:#3C3C3C;stop-opacity:0.6"/> +</radialGradient> +<path d="M35,5C18.432,5,5,18.432,5,35s13.432,30,30,30s30-13.432,30-30S51.568,5,35,5z M35,61 C20.641,61,9,49.359,9,35S20.641,9,35,9c14.358,0,26,11.641,26,26S49.358,61,35,61z" fill="url(#SVGID_1_)"/> +<rect fill="none" height="70" width="70"/> +</svg> diff --git a/reader/data/icons/search_icon.png b/reader/data/icons/search_icon.png Binary files differnew file mode 100644 index 0000000..12c8dbd --- /dev/null +++ b/reader/data/icons/search_icon.png diff --git a/reader/data/icons/spinner.gif b/reader/data/icons/spinner.gif Binary files differnew file mode 100644 index 0000000..1ed786f --- /dev/null +++ b/reader/data/icons/spinner.gif diff --git a/reader/data/icons/toolbar/14x15-png/addBook.png b/reader/data/icons/toolbar/14x15-png/addBook.png Binary files differnew file mode 100644 index 0000000..40364ca --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/addBook.png diff --git a/reader/data/icons/toolbar/14x15-png/bookInfo.png b/reader/data/icons/toolbar/14x15-png/bookInfo.png Binary files differnew file mode 100644 index 0000000..3def30e --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/bookInfo.png diff --git a/reader/data/icons/toolbar/14x15-png/findNext.png b/reader/data/icons/toolbar/14x15-png/findNext.png Binary files differnew file mode 100644 index 0000000..022c235 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/findNext.png diff --git a/reader/data/icons/toolbar/14x15-png/findPrevious.png b/reader/data/icons/toolbar/14x15-png/findPrevious.png Binary files differnew file mode 100644 index 0000000..a56aa4b --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/findPrevious.png diff --git a/reader/data/icons/toolbar/14x15-png/gotoHome.png b/reader/data/icons/toolbar/14x15-png/gotoHome.png Binary files differnew file mode 100644 index 0000000..bbca77a --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/gotoHome.png diff --git a/reader/data/icons/toolbar/14x15-png/preferences.png b/reader/data/icons/toolbar/14x15-png/preferences.png Binary files differnew file mode 100644 index 0000000..af981f3 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/preferences.png diff --git a/reader/data/icons/toolbar/14x15-png/redo.png b/reader/data/icons/toolbar/14x15-png/redo.png Binary files differnew file mode 100644 index 0000000..1311212 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/redo.png diff --git a/reader/data/icons/toolbar/14x15-png/rotate.png b/reader/data/icons/toolbar/14x15-png/rotate.png Binary files differnew file mode 100644 index 0000000..0a69733 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/rotate.png diff --git a/reader/data/icons/toolbar/14x15-png/search.png b/reader/data/icons/toolbar/14x15-png/search.png Binary files differnew file mode 100644 index 0000000..b9b735b --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/search.png diff --git a/reader/data/icons/toolbar/14x15-png/showLibrary.png b/reader/data/icons/toolbar/14x15-png/showLibrary.png Binary files differnew file mode 100644 index 0000000..9a30429 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/showLibrary.png diff --git a/reader/data/icons/toolbar/14x15-png/showReading.png b/reader/data/icons/toolbar/14x15-png/showReading.png Binary files differnew file mode 100644 index 0000000..5e0f6c3 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/showReading.png diff --git a/reader/data/icons/toolbar/14x15-png/showRecent.png b/reader/data/icons/toolbar/14x15-png/showRecent.png Binary files differnew file mode 100644 index 0000000..9165f11 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/showRecent.png diff --git a/reader/data/icons/toolbar/14x15-png/toc.png b/reader/data/icons/toolbar/14x15-png/toc.png Binary files differnew file mode 100644 index 0000000..575f378 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/toc.png diff --git a/reader/data/icons/toolbar/14x15-png/undo.png b/reader/data/icons/toolbar/14x15-png/undo.png Binary files differnew file mode 100644 index 0000000..5e0f6c3 --- /dev/null +++ b/reader/data/icons/toolbar/14x15-png/undo.png diff --git a/reader/data/icons/toolbar/22x18-png/addBook.png b/reader/data/icons/toolbar/22x18-png/addBook.png Binary files differnew file mode 100644 index 0000000..7f4f02e --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/addBook.png diff --git a/reader/data/icons/toolbar/22x18-png/bookInfo.png b/reader/data/icons/toolbar/22x18-png/bookInfo.png Binary files differnew file mode 100644 index 0000000..25eb5cb --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/bookInfo.png diff --git a/reader/data/icons/toolbar/22x18-png/findNext.png b/reader/data/icons/toolbar/22x18-png/findNext.png Binary files differnew file mode 100644 index 0000000..45294b1 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/findNext.png diff --git a/reader/data/icons/toolbar/22x18-png/findPrevious.png b/reader/data/icons/toolbar/22x18-png/findPrevious.png Binary files differnew file mode 100644 index 0000000..c336d2b --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/findPrevious.png diff --git a/reader/data/icons/toolbar/22x18-png/gotoHome.png b/reader/data/icons/toolbar/22x18-png/gotoHome.png Binary files differnew file mode 100644 index 0000000..4ff73d7 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/gotoHome.png diff --git a/reader/data/icons/toolbar/22x18-png/preferences.png b/reader/data/icons/toolbar/22x18-png/preferences.png Binary files differnew file mode 100644 index 0000000..143fb28 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/preferences.png diff --git a/reader/data/icons/toolbar/22x18-png/redo.png b/reader/data/icons/toolbar/22x18-png/redo.png Binary files differnew file mode 100644 index 0000000..b2f128b --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/redo.png diff --git a/reader/data/icons/toolbar/22x18-png/rotate.png b/reader/data/icons/toolbar/22x18-png/rotate.png Binary files differnew file mode 100644 index 0000000..9d4f128 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/rotate.png diff --git a/reader/data/icons/toolbar/22x18-png/search.png b/reader/data/icons/toolbar/22x18-png/search.png Binary files differnew file mode 100644 index 0000000..dfd2127 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/search.png diff --git a/reader/data/icons/toolbar/22x18-png/showLibrary.png b/reader/data/icons/toolbar/22x18-png/showLibrary.png Binary files differnew file mode 100644 index 0000000..aa56dcb --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/showLibrary.png diff --git a/reader/data/icons/toolbar/22x18-png/showReading.png b/reader/data/icons/toolbar/22x18-png/showReading.png Binary files differnew file mode 100644 index 0000000..fae13ca --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/showReading.png diff --git a/reader/data/icons/toolbar/22x18-png/showRecent.png b/reader/data/icons/toolbar/22x18-png/showRecent.png Binary files differnew file mode 100644 index 0000000..0ffe21f --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/showRecent.png diff --git a/reader/data/icons/toolbar/22x18-png/toc.png b/reader/data/icons/toolbar/22x18-png/toc.png Binary files differnew file mode 100644 index 0000000..aa9e4c3 --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/toc.png diff --git a/reader/data/icons/toolbar/22x18-png/undo.png b/reader/data/icons/toolbar/22x18-png/undo.png Binary files differnew file mode 100644 index 0000000..fae13ca --- /dev/null +++ b/reader/data/icons/toolbar/22x18-png/undo.png diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/addBook.ico b/reader/data/icons/toolbar/32x32-transparent-ico/addBook.ico Binary files differnew file mode 100644 index 0000000..4d4f007 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/addBook.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/advancedSearchOnNetwork.ico b/reader/data/icons/toolbar/32x32-transparent-ico/advancedSearchOnNetwork.ico Binary files differnew file mode 100644 index 0000000..25e82d3 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/advancedSearchOnNetwork.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/bookInfo.ico b/reader/data/icons/toolbar/32x32-transparent-ico/bookInfo.ico Binary files differnew file mode 100644 index 0000000..dd9f4db --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/bookInfo.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/byAuthor.ico b/reader/data/icons/toolbar/32x32-transparent-ico/byAuthor.ico Binary files differnew file mode 100644 index 0000000..5adf345 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/byAuthor.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/byTag.ico b/reader/data/icons/toolbar/32x32-transparent-ico/byTag.ico Binary files differnew file mode 100644 index 0000000..e2467b4 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/byTag.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/findNext.ico b/reader/data/icons/toolbar/32x32-transparent-ico/findNext.ico Binary files differnew file mode 100644 index 0000000..1556227 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/findNext.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/findPrevious.ico b/reader/data/icons/toolbar/32x32-transparent-ico/findPrevious.ico Binary files differnew file mode 100644 index 0000000..7f933db --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/findPrevious.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/gotoHome.ico b/reader/data/icons/toolbar/32x32-transparent-ico/gotoHome.ico Binary files differnew file mode 100644 index 0000000..41a406a --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/gotoHome.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/preferences.ico b/reader/data/icons/toolbar/32x32-transparent-ico/preferences.ico Binary files differnew file mode 100644 index 0000000..878df5c --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/preferences.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/redo.ico b/reader/data/icons/toolbar/32x32-transparent-ico/redo.ico Binary files differnew file mode 100644 index 0000000..dfd3c93 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/redo.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/rotate.ico b/reader/data/icons/toolbar/32x32-transparent-ico/rotate.ico Binary files differnew file mode 100644 index 0000000..0727596 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/rotate.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/search.ico b/reader/data/icons/toolbar/32x32-transparent-ico/search.ico Binary files differnew file mode 100644 index 0000000..8fa3102 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/search.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/showHelp.ico b/reader/data/icons/toolbar/32x32-transparent-ico/showHelp.ico Binary files differnew file mode 100644 index 0000000..6221e6e --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/showHelp.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/showLibrary.ico b/reader/data/icons/toolbar/32x32-transparent-ico/showLibrary.ico Binary files differnew file mode 100644 index 0000000..ac83cf4 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/showLibrary.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/showNetLibrary.ico b/reader/data/icons/toolbar/32x32-transparent-ico/showNetLibrary.ico Binary files differnew file mode 100644 index 0000000..a0d0614 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/showNetLibrary.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/showReading.ico b/reader/data/icons/toolbar/32x32-transparent-ico/showReading.ico Binary files differnew file mode 100644 index 0000000..f3f58bb --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/showReading.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/showRecent.ico b/reader/data/icons/toolbar/32x32-transparent-ico/showRecent.ico Binary files differnew file mode 100644 index 0000000..273774c --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/showRecent.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/toc.ico b/reader/data/icons/toolbar/32x32-transparent-ico/toc.ico Binary files differnew file mode 100644 index 0000000..cc75cd9 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/toc.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-ico/undo.ico b/reader/data/icons/toolbar/32x32-transparent-ico/undo.ico Binary files differnew file mode 100644 index 0000000..3910a73 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-ico/undo.ico diff --git a/reader/data/icons/toolbar/32x32-transparent-png/addBook.png b/reader/data/icons/toolbar/32x32-transparent-png/addBook.png Binary files differnew file mode 100644 index 0000000..e7046fd --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/addBook.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/advancedSearchOnNetwork.png b/reader/data/icons/toolbar/32x32-transparent-png/advancedSearchOnNetwork.png Binary files differnew file mode 100644 index 0000000..f2e8fd0 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/advancedSearchOnNetwork.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/bookInfo.png b/reader/data/icons/toolbar/32x32-transparent-png/bookInfo.png Binary files differnew file mode 100644 index 0000000..929a71d --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/bookInfo.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/byAuthor.png b/reader/data/icons/toolbar/32x32-transparent-png/byAuthor.png Binary files differnew file mode 100644 index 0000000..4b5ef82 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/byAuthor.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/byTag.png b/reader/data/icons/toolbar/32x32-transparent-png/byTag.png Binary files differnew file mode 100644 index 0000000..9df9113 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/byTag.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/findNext.png b/reader/data/icons/toolbar/32x32-transparent-png/findNext.png Binary files differnew file mode 100644 index 0000000..a784e80 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/findNext.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/findPrevious.png b/reader/data/icons/toolbar/32x32-transparent-png/findPrevious.png Binary files differnew file mode 100644 index 0000000..4734693 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/findPrevious.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/gotoHome.png b/reader/data/icons/toolbar/32x32-transparent-png/gotoHome.png Binary files differnew file mode 100644 index 0000000..e3fb36b --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/gotoHome.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/preferences.png b/reader/data/icons/toolbar/32x32-transparent-png/preferences.png Binary files differnew file mode 100644 index 0000000..5fd04b9 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/preferences.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/redo.png b/reader/data/icons/toolbar/32x32-transparent-png/redo.png Binary files differnew file mode 100644 index 0000000..f822240 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/redo.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/rotate.png b/reader/data/icons/toolbar/32x32-transparent-png/rotate.png Binary files differnew file mode 100644 index 0000000..4492032 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/rotate.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/search.png b/reader/data/icons/toolbar/32x32-transparent-png/search.png Binary files differnew file mode 100644 index 0000000..4fe48ab --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/search.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showHelp.png b/reader/data/icons/toolbar/32x32-transparent-png/showHelp.png Binary files differnew file mode 100644 index 0000000..a65ca1b --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showHelp.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showLibrary.png b/reader/data/icons/toolbar/32x32-transparent-png/showLibrary.png Binary files differnew file mode 100644 index 0000000..e244cd2 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showLibrary.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showNetLibrary.png b/reader/data/icons/toolbar/32x32-transparent-png/showNetLibrary.png Binary files differnew file mode 100644 index 0000000..54e3d0a --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showNetLibrary.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showNetworkLibrary.png b/reader/data/icons/toolbar/32x32-transparent-png/showNetworkLibrary.png new file mode 120000 index 0000000..9e64d17 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showNetworkLibrary.png @@ -0,0 +1 @@ +showNetLibrary.png
\ No newline at end of file diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showReading.png b/reader/data/icons/toolbar/32x32-transparent-png/showReading.png Binary files differnew file mode 100644 index 0000000..cbafa6b --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showReading.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/showRecent.png b/reader/data/icons/toolbar/32x32-transparent-png/showRecent.png Binary files differnew file mode 100644 index 0000000..f4ad292 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/showRecent.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/toc.png b/reader/data/icons/toolbar/32x32-transparent-png/toc.png Binary files differnew file mode 100644 index 0000000..d7c9227 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/toc.png diff --git a/reader/data/icons/toolbar/32x32-transparent-png/undo.png b/reader/data/icons/toolbar/32x32-transparent-png/undo.png Binary files differnew file mode 100644 index 0000000..cbbf8b0 --- /dev/null +++ b/reader/data/icons/toolbar/32x32-transparent-png/undo.png diff --git a/reader/data/icons/toolbar/desktop b/reader/data/icons/toolbar/desktop new file mode 120000 index 0000000..a98d612 --- /dev/null +++ b/reader/data/icons/toolbar/desktop @@ -0,0 +1 @@ +32x32-transparent-png
\ No newline at end of file diff --git a/reader/data/resources/RIGHTS b/reader/data/resources/RIGHTS new file mode 100644 index 0000000..a8ee614 --- /dev/null +++ b/reader/data/resources/RIGHTS @@ -0,0 +1,20 @@ +en.xml English ----- any usage +ru.xml Russian ----- any usage +ar.xml Arabic Khaled Hosny +bg.xml Bulgarian Alexander Ivanov any usage +cs.xml Czech LubomÃr ÄŒevela +de.xml German Rainer Paul +eo.xml Esperanto KatarÃna Nosková +es.xml Spanish Leproso +fi.xml Finnish Marko Vertainen freely distributed by GP (open or closed source) +fr.xml French Pierre Senellart any usage +hu.xml Hungarian Sándor Gábor +id.xml Indonesian Ketut Putu Kumajaya any usage +it.xml Italian Floriano Scioscia any usage +lt.xml Lithuanian Stanislovas Zacharovas +nl.xml Dutch Bosel +pl.xml Polish RafaÅ‚ BakuÅ‚a +sv.xml Swedish Daniel Nylander no answer (localization is orphaned) +uk.xml Ukrainian Valentina Kanevska any usage +vi.xml Vietnamese Phạm Văn Hùng_Firestork freely distributed by GP (open or closed source) +zh.xml Chinese http://shucang.com/ any usage diff --git a/reader/data/resources/ar.xml b/reader/data/resources/ar.xml new file mode 100644 index 0000000..273341a --- /dev/null +++ b/reader/data/resources/ar.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Arabic TDE-Ebook-Reader resources, by Khaled Hosny --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="أظهر الكتب"/> + <node name="collapseTree" value="أخ٠الكتب"/> + <node name="edit" value="ØØ±Ø± المعلومات"/> + <node name="unknownAuthor" value="مؤل٠مجهول"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="أظهر الكتب"/> + <node name="collapseTree" value="أخ٠الكتب"/> + <node name="edit" value="ØØ±Ø± الوسم"/> + <node name="clone" value="انسخ الوسم"/> + <node name="delete" value="Ø§ØØ°Ù الوسم"/> + <node name="noTags" value="كتب بلا وسوم"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="أظهر الكتب"/> + <node name="collapseTree" value="أخ٠الكتب"/> + </node> + <node name="bookNode"> + <node name="read" value="اقرأ الكتاب"/> + <node name="edit" value="ØØ±Ø± المعلومات"/> + <node name="delete" value="Ø§ØØ°Ù الكتاب"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="مدّد"/> + <node name="collapseTree" value="قلّص"/> + <node name="reload" value="أعد التØÙ…يل"/> + <node name="openInBrowser" value="Ø§ÙØªØ ÙÙŠ Ø§Ù„Ù…ØªØµÙØ"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Ø§ÙØªØ الÙهرس"/> + <node name="collapseTree" value="أغلق الÙهرس"/> + <node name="login" value="ادخل"/> + <node name="logout" value="اخرج (%s)"/> + <node name="reload" value="أعد التØÙ…يل"/> + <node name="dontShow" value="لا ØªÙØ¸Ù‡Ø± هذا الÙهرس"/> + <node name="topupAccount" value="أعد ملء Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª (ØØ§Ù„يا: %s)"/> + <node name="register" value="سجّل"/> + <node name="passwordRecovery" value="استعد كلمة السر"/> + </node> + <node name="searchResultNode"> + <node name="title" value="نتائج Ø§Ù„Ø¨ØØ«"/> + <node name="expandTree" value="أظهر النتائج"/> + <node name="collapseTree" value="أخ٠النتائج"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="أظهر الكتب"/> + <node name="collapseTree" value="أخ٠الكتب"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="أظهر الكتب"/> + <node name="collapseTree" value="أخ٠الكتب"/> + </node> + <node name="bookNode"> + <node name="read" value="اقرأ النسخة المØÙ„ية"/> + <node name="delete" value="Ø§ØØ°Ù النسخة المØÙ„ية"/> + <node name="download" value="نزّل"/> + <node name="readDemo" value="اقرأ نسخة العرض"/> + <node name="downloadDemo" value="نزّل نسخة العرض"/> + <node name="demo" toBeTranslated="true" value="sample"/> + <node name="buy" value="اشتر٠(%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="معلومات الكتاب..."/> + <node name="toc" value="جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="showLibrary" value="Ø§ÙØªØ المكتبة"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="المكتبة"> + <node name="showLibrary" value="Ø§ÙØªØ"/> + <node name="previousBook" value="الكتاب السابق"/> + <node name="showRecent" value="الأخيرة"/> + <node name="addBook" value="أض٠كتابا..."/> + <node name="showHelp" value="عن Ø¥Ù.بي.ريدر"/> + </node> + <node name="gotoHome" value="اذهب إلى بداية المستند"/> + <node name="gotoPageNumber" value="اذهب إلى ØµÙØØ©..."/> + <node name="gotoSectionStart" value="اذهب إلى بداية الجزء النصي"/> + <node name="gotoSectionEnd" value="اذهب إلى نهاية الجزء النصي"/> + <node name="nextTOCSection" value="اذهب إلى العنصر التالي ÙÙŠ جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="previousTOCSection" value="اذهب إلى العنصر السابق ÙÙŠ جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="navigate" value="تصÙÙ‘Ø"> + <node name="gotoHome" value="اذهب إلى بداية المستند"/> + <node name="gotoPageNumber" value="اذهب إلى ØµÙØØ©..."/> + <node name="gotoSectionStart" value="اذهب إلى بداية الجزء النصي"/> + <node name="gotoSectionEnd" value="اذهب إلى نهاية الجزء النصي"/> + <node name="nextTOCSection" value="اذهب إلى العنصر التالي ÙÙŠ جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="previousTOCSection" value="اذهب إلى العنصر السابق ÙÙŠ جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="undo" value="عد للخلÙ"/> + <node name="redo" value="تقدّم للأمام"/> + </node> + <node name="selection" value="Ø§Ù„ØªØØ¯ÙŠØ¯"> + <node name="copyToClipboard" value="انسخ Ù„Ù„ØØ§Ùظة"/> + <node name="openInDictionary" value="Ø§ÙØªØ ÙÙŠ القاموس"/> + <node name="clearSelection" value="امسØ"/> + </node> + <node name="search" value="Ø¨ØØ«"> + <node name="search" value="Ø§Ø¨ØØ« عن نص..."/> + <node name="findNext" value="Ø§Ø¨ØØ« عن التالي"/> + <node name="findPrevious" value="Ø§Ø¨ØØ« عن السابق"/> + </node> + <node name="view" value="عرض"> + <node name="rotate" value="ل٠الشاشة"/> + <node name="toggleFullscreen" value="املأ الشاشة"/> + <node name="toggleIndicator" value="بدّل الموضّØ"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="أغلق"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="اقرأ الكتاب"/> + <node name="tooltip" value="أظهر وضع القراءة"/> + </node> + <node name="showLibrary"> + <node name="label" value="مكتبة"/> + <node name="tooltip" value="أظهر شجرة المكتبة"/> + <node name="popup" value="أظهر قائمة الكتب Ø§Ù„ØØ¯ÙŠØ«Ø©"/> + </node> + <node name="showRecent"> + <node name="label" value="الكتب Ø§Ù„ØØ¯ÙŠØ«Ø©"/> + <node name="tooltip" value="أظهر قائمة آخر الكتب"/> + </node> + <node name="byAuthor"> + <node name="label" value="ØØ³Ø¨ المؤلÙ"/> + <node name="tooltip" value="رتّب الكتب ØØ³Ø¨ المؤلÙ"/> + </node> + <node name="byTag"> + <node name="label" value="ØØ³Ø¨ الوسم"/> + <node name="tooltip" value="رتّب الكتب ØØ³Ø¨ الوسم"/> + </node> + <node name="addBook"> + <node name="label" value="Ø£Ø¶Ù Ù…Ù„ÙØ§"/> + <node name="tooltip" value="Ø£Ø¶Ù Ù…Ù„ÙØ§ إلى المكتبة"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="الشبكة"/> + <node name="tooltip" value="Ø§Ø¨ØØ« ÙÙŠ مكتبات الشبكة"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Ø¨ØØ« بسيط"/> + <node name="tooltip" value="Ø¨ØØ« الشبكة"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Ø§Ø¨ØØ«"/> + <node name="tooltip" value="Ø¨ØØ« متقدم ÙÙŠ الشبكة"/> + </node> + <node name="gotoHome"> + <node name="label" value="اذهب إلى البداية"/> + <node name="tooltip" value="اذهب إلى بداية النص"/> + </node> + <node name="undo"> + <node name="label" value="عد إلى الخلÙ"/> + <node name="tooltip" value="عد إلى الخلÙ"/> + </node> + <node name="redo"> + <node name="label" value="تقدّم إلى الأمام"/> + <node name="tooltip" value="تقدّم إلى الأمام"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="اذهب إلى ØµÙØØ©"/> + <node name="tooltip" value="اذهب إلى ØµÙØØ©"/> + </node> + <node name="toc"> + <node name="label" value="الÙهرس"/> + <node name="tooltip" value="جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + </node> + <node name="search"> + <node name="label" value="Ø§Ø¨ØØ«"/> + <node name="tooltip" value="Ø§Ø¨ØØ« ÙÙŠ النص"/> + </node> + <node name="findNext"> + <node name="label" value="التالي"/> + <node name="tooltip" value="Ø§Ø¨ØØ« عن التالي"/> + </node> + <node name="findPrevious"> + <node name="label" value="السابق"/> + <node name="tooltip" value="Ø§Ø¨ØØ« عن السابق"/> + </node> + <node name="rotate"> + <node name="label" value="دوّر"/> + <node name="tooltip" value="ل٠النص"/> + </node> + <node name="showHelp"> + <node name="label" value="عن"/> + <node name="tooltip" value="عن Ø¥Ù.بي.ريدر"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="معلومات الكتاب"/> + <node name="tooltip" value="أظهر ØÙˆØ§Ø± معلومات الكتاب"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="ا&ذهب"/> + <node name="thisOnly" value="هذا Ùقط"/> + <node name="withSubtags" value="مع الوسوم الثانوية"/> + <node name="removeLink" value="Ø§ØØ°Ù من المكتبة"/> + <node name="removeFile" value="Ø§ØØ°Ù من القرص"/> + <node name="yesToAll" value="نعم لل&Ù„"/> + <node name="buy" value="ا&شتر"/> + <node name="buyAndDownload" value="اصشتر Ùˆ &نزّل"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="المكتبة"> + <node name="bookPath" value="مسار الكتب"/> + <node name="lookInSubdirectories" value="Ø§Ø¨ØØ« عن الكتب ÙÙŠ المجلدات Ø§Ù„ÙØ±Ø¹ÙŠØ©"/> + <node name="collectBooksWithoutMetaInfo" value="اجمع الكتب بلا معلومات Ùوقية"/> + <node name="downloadDirectory" value="مجلّد الكتب المنزّلة"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Ø¨ØØ« الشبكة"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="استخدم وسيطا"/> + <node name="proxyHost" value="مستضي٠الوسيط"/> + <node name="proxyPort" value="Ù…Ù†ÙØ° الوسيط"/> + <node name="timeout" value="مهلة عمليات الشبكة، بالثواني"/> + </node> + <node name="Web" value="الوب"> + <node name="enableIntegration" value="Ø§ÙØªØ الوصلات الخارجية ÙÙŠ %s"/> + <node name="defaultText" value="Ø§ÙØªØ الوصلات الخارجية ÙÙŠ Ø§Ù„Ù…ØªØµÙØ"/> + <node name="choice" value="استخدم Ø§Ù„Ù…ØªØµÙØ"/> + <node name="command" value="الأمر"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="اللغة"> + <node name="autoDetect" value="تعرّ٠على اللغة والترميز آليا"/> + <node name="defaultLanguage" value="اللغة المبدئية"/> + <node name="defaultEncodingSet" value="طقم الترميز المبدئي"/> + <node name="defaultEncoding" value="الترميز المبدئي"/> + <node name="useWindows1252Hack" value="استخدم windows-1252 بدلا من iso-8859-1"/> + </node> + <node name="Config" value="الإعداد"> + <node name="autoSave" value="اØÙظ Ø§Ù„ØØ§Ù„Ø© تلقائيا"/> + <node name="timeout" value="Ø§Ù„ÙØªØ±Ø© بين الØÙظ، بالثواني"/> + </node> + <node name="Dictionary" value="القاموس"> + <node name="enableIntegration" value="ÙØ¹Ù‘Ù„ التكامل %s"/> + <node name="defaultText" value="ÙØ¹Ù‘Ù„ التكامل مع القاموس"/> + <node name="choice" value="تكامل مع"/> + <node name="singleClickOpen" value="Ø§ÙØªØ بنقرة ÙˆØ§ØØ¯Ø©"/> + </node> + <node name="Maemo" value="ميٰمو"> + <node name="keyActionOnRelease" value="الإجراءات عند ترك Ø§Ù„Ù…ÙØªØ§ØØŒ لا عند ضغطه"/> + <node name="minStylusPressure" value="أدنى ضغط من الريشة"/> + <node name="maxStylusPressure" value="أقصى ضغط من الريشة"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="التقليب"> + <node name="keyScrollDelay" value="التأخير بين التقليب Ø¨Ø§Ù„ÙØ§ØªÙŠØØŒ بالملي ثانية"/> + <node name="keyLinesToScroll" value="السطور التي تقلب عند التقليب بالسطر"/> + <node name="keyLinesToKeep" value="السطور التي تقلب عند التقليب Ø¨Ø§Ù„ØµÙØØ©"/> + <node name="enableTapScrolling" value="ÙØ¹Ù‘Ù„ التقليب بعلامة الجدولة"/> + <node name="fingerOnly" value="اقلب عند الطرق بالأصبع Ùقط"/> + </node> + <node name="Selection" value="Ø§Ù„ØªØØ¯ÙŠØ¯"> + <node name="enableSelection" value="ÙØ¹Ù‘Ù„ ØªØØ¯ÙŠØ¯ النص"/> + </node> + <node name="Indicator" value="الموضØ"> + <node name="type" value="اعرض Ùƒâ€"> + <node name="osScrollbar" value="شريط تمرير النظام"/> + <node name="fbIndicator" value="Ø§Ù„Ù…ÙˆØ¶Ù‘Ø Ø§Ù„Ù‚Ø¯ÙŠÙ…"/> + <node name="none" value="لا ØªÙØ¸Ù‡Ø±"/> + </node> + <node name="height" value="Ø§Ø±ØªÙØ§Ø¹ الموضØ"/> + <node name="offset" value="بعده من النص"/> + <node name="pageNumber" value="اعرض الموضع كرقم"/> + <node name="time" value="أظهر الوقت"/> + <node name="fontSize" value="ØØ¬Ù…"/> + <node name="tocMarks" value="أظهر علامات جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="navigation" value="ÙØ¹Ù‘Ù„ التصÙÙ‘Ø"/> + </node> + <node name="Rotation" value="التدوير"> + <node name="direction" value="نوع التدوير"> + <node name="disabled" value="معطّل"/> + <node name="clockwise" value="90 درجة مع عقارب الساعة"/> + <node name="counterclockwise" value="90 درجة عكس عقارب الساعة"/> + <node name="180" value="180 درجة"/> + <node name="cycle" value="بدل بين الاتجاهات الأربع"/> + </node> + </node> + <node name="Keys" value="Ø§Ù„Ù…ÙØ§ØªÙŠØ"> + <node name="grabSystemKeys" value="التقط Ù…ÙØ§ØªÙŠØ النظام"/> + <node name="separate" value="ارتباطات Ø§Ù„Ù…ÙØ§ØªÙŠØ تعتمد على الوضع"/> + <node name="orientation" value="الوضع"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="لا شيء"/> + <node name="showLibrary" value="أظهر المكتبة"/> + <node name="showNetLibrary" value="أظهر مكتبة الشبكة"/> + <node name="showRecent" value="أظهر الكتب الأخيرة"/> + <node name="previousBook" value="Ø§ÙØªØ الكتاب السابق"/> + <node name="toc" value="أظهر جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="gotoHome" value="اذهب إلى المنزل"/> + <node name="gotoSectionStart" value="اذهب إلى بداية القسم"/> + <node name="gotoSectionEnd" value="اذهب إلى نهاية القسم"/> + <node name="nextTOCSection" value="اذهب إلى القسم التالي ÙÙŠ جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="previousTOCSection" value="اذهب إلى قسم جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª السابق"/> + <node name="pageForward" value="اقلب ØµÙØØ© للأمام"/> + <node name="pageBackward" value="اقلب ØµÙØØ© للخلÙ"/> + <node name="lineForward" value="اقلب سطرا للأمام"/> + <node name="lineBackward" value="اقلب سطرا للخلÙ"/> + <node name="undo" value="تراجع"/> + <node name="redo" value="أعد"/> + <node name="copyToClipboard" value="Copy Selected Text to Clipboard"/> + <node name="openInDictionary" value="Open Selected Text in Dictionary"/> + <node name="clearSelection" value="Clear Selection"/> + <node name="search" value="Ø§Ø¨ØØ«"/> + <node name="findPrevious" value="Find Previous"/> + <node name="findNext" value="Find Next"/> + <node name="increaseFont" value="Increase Font Size"/> + <node name="decreaseFont" value="Decrease Font Size"/> + <node name="toggleIndicator" value="Toggle Position Indicator"/> + <node name="toggleFullscreen" value="Toggle Fullscreen Mode"/> + <node name="rotate" value="Rotate Screen"/> + <node name="addBook" value="أض٠كتابا"/> + <node name="cancel" value="ألغ"/> + <node name="quit" value="اخرج"/> + <node name="bookInfo" value="Show Book Info Dialog"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Quit Application on Cancel"/> + <node name="keyDelay" value="Delay Between Accepted Key Pressings"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="الطرز المتراصة"> + <node name="overrideSpecifiedFonts" value="استخدم دائما خطوطي الخاصة"/> + </node> + <node name="Margins" value="الØÙˆØ§Ø´ÙŠ"> + <node name="left" value="Ø§Ù„ØØ§Ø´ÙŠØ© اليسرى"/> + <node name="right" value="Ø§Ù„ØØ§Ø´ÙŠØ© اليمنى"/> + <node name="top" value="Ø§Ù„ØØ§Ø´ÙŠØ© العليا"/> + <node name="bottom" value="Ø§Ù„ØØ§Ø´ÙŠØ© السÙلى"/> + </node> + <node name="Format" value="النسق"> + <node name="optionsFor" value="خيارات"/> + <node name="lineSpacing" value="تباعد السطور"> + <node name="unchanged" value="<بلا تغيير>"/> + </node> + <node name="firstLineIndent" value="Ø¥Ø²Ø§ØØ© السطر الأول"/> + <node name="alignment" value="Ø§Ù„Ù…ØØ§Ø°Ø§Ø©"> + <node name="left" value="يسار"/> + <node name="right" value="يمين"/> + <node name="center" value="وسط"/> + <node name="justify" value="مساوى"/> + <node name="unchanged" value="<بلا تغيير>"/> + </node> + <node name="spaceBefore" value="Ø§Ù„Ù…Ø³Ø§ÙØ© قبل"/> + <node name="spaceAfter" value="Ø§Ù„Ù…Ø³Ø§ÙØ© بعد"/> + <node name="startIndent" value="Ø¥Ø²Ø§ØØ© بداية السطر"/> + <node name="endIndent" value="Ø¥Ø²Ø§ØØ© نهاية السطر"/> + </node> + <node name="Styles" value="الطرز"> + <node name="optionsFor" value="خيارات"/> + <node name="fontFamily" value="العائلة"> + <node name="unchanged" value="<بلا تغيير>"/> + </node> + <node name="fontSize" value="Ø§Ù„ØØ¬Ù…"/> + <node name="fontSizeDifference" value="Ø§Ø®ØªÙ„Ø§ÙØ§Øª Ø§Ù„ØØ¬Ù…"/> + <node name="bold" value="عريض"/> + <node name="italic" value="مائل"/> + <node name="allowHyphenations" value="Ø§Ø³Ù…Ø Ø¨Ù‚Ø·Ø¹ الكلمات ÙÙŠ آخر السطر"/> + <node name="autoHyphenations" value="قطع تلقائي للكلمات"/> + </node> + <node name="Colors" value="الألوان"> + <node name="colorFor" value="لون"> + <node name="background" value="الخلÙية"/> + <node name="selectionBackground" value="خلÙية Ø§Ù„ØªØØ¯ÙŠØ¯"/> + <node name="text" value="النص العادي"/> + <node name="internalLink" value="النص التشعبي الداخلي"/> + <node name="externalLink" value="النص التشعبي الخارجي"/> + <node name="bookLink" value="وصلة إلى كتاب آخر"/> + <node name="highlighted" value="النص Ø§Ù„Ù…ÙØ¨Ø±Ø²"/> + <node name="treeLines" value="خطوط الشجرة"/> + <node name="indicator" value="Ù…ÙÙˆØ¶Ù‘Ø Ø§Ù„Ù…ÙˆØ¶Ø¹"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="Ø¥Ù.بي.ريدر - معلومات الكتاب"/> + <node name="tab"> + <node name="Common" value="عام"> + <node name="file" value="الملÙ"/> + <node name="title" value="العنوان"/> + <node name="language" value="اللغة"/> + <node name="encodingSet" value="طقم الترميز"/> + <node name="encoding" value="الترميز"/> + </node> + <node name="Authors" value="المؤلÙين"> + <node name="authorDisplayName" value="اسم المؤلÙ"/> + </node> + <node name="Series" value="السلسلة"> + <node name="seriesTitle" value="عنوان السلسلة"/> + <node name="bookIndex" value="رقم الكتاب"/> + </node> + <node name="Tags" value="الوسوم"> + <node name="tags" value="اسم الوسم"/> + </node> + <node name="Text" value="النص"> + <node name="breakType" value="اقطع الÙقرات عند"/> + <node name="ignoreIndent" value="تجاهل Ø§Ù„Ø¥Ø²Ø§ØØ© الأقل من"/> + <node name="buildTOC" value="جهز جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="emptyLines" value="الأسطر Ø§Ù„ÙØ§Ø±ØºØ© قبل الأقسام الجديدة"/> + </node> + <node name="<PRE>" value="<قبل>"> + <node name="breakType" value="اقطع الÙقرات عند"/> + <node name="ignoreIndent" value="تجاهل Ø§Ù„Ø¥Ø²Ø§ØØ© الأقل من"/> + <node name="buildTOC" value="جهز جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="emptyLines" value="الأسطر Ø§Ù„ÙØ§Ø±ØºØ© قبل الأقسام الجديدة"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="Ø¥Ù.بي.ريدر - معلومات ا المؤلÙ"/> + <node name="name" value="اسم المؤلÙ"/> + <node name="sortKey" value="Ù…ÙØªØ§Ø ترتيب المؤلÙ"/> + </node> + <node name="addFileDialog"> + <node name="title" value="Ø¥Ù.بي.ريدر - أض٠كتابا للمكتبة"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Ø§Ù„Ø¨ØØ« عن النص"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&تجاهل ØØ§Ù„Ø© Ø§Ù„ØØ±Ù"/> + <node name="wholeText" value="ÙÙŠ &كل النص"/> + <node name="backward" value="&للخلÙ"/> + <node name="currentSection" value="&هذا القسم Ùقط"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Ø¨ØØ« الشبكة"/> + <node name="titleAndSeries" value="العنوان\السلسلة"/> + <node name="author" value="المؤلÙ"/> + <node name="category" value="التصنيÙ"/> + <node name="description" value="الوصÙ"/> + <node name="annotation" value="نتائج Ø§Ù„Ø¨ØØ« عن: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="اذهب إلى ØµÙØØ©"/> + <node name="pageNumber" value="اذهب إلى Ø§Ù„ØµÙØØ© رقم"/> + </node> + <node name="editTagDialog"> + <node name="title" value="ØØ±Ø± الوسم"/> + <node name="name" value="اسم الوسم"/> + <node name="includeSubtags" value="اشمل الوسوم Ø§Ù„ÙØ±Ø¹ÙŠÙ‰"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="انسخ الوسم"/> + <node name="name" value="اسم الوسم"/> + <node name="includeSubtags" value="اشمل الوسوم Ø§Ù„ÙØ±Ø¹ÙŠÙ‰"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Ø§ØØ°Ù الكتاب"/> + <node name="message" value="Ø£Ø£ØØ°Ù الكتاب %s†من المكتبة؟"/> + <node name="deleteFile" value="أمتأكد أنك تريد ØØ°Ù المل٠“%s†من القرص؟"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Ø§ØØ°Ù الوسم"/> + <node name="message" value="Ø£Ø£ØØ°Ù الوسم “%sâ€ØŸ"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="خطأ"/> + <node name="message" value="تعذّر ÙØªØ: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="خطأ"/> + <node name="message" value="تعذّر ØØ°Ù المل٠%s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="خطأ"/> + <node name="message" value="Ø¢Ø³ÙØŒ مل٠المساعدة غير موجود"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="قائمة مكتبات خالية"/> + <node name="authenticationFailed" value="ÙØ´Ù„ الاستيثاق"/> + <node name="internalError" value="خطأ داخلي ÙÙŠ الخادوم"/> + <node name="purchaseNotEnoughMoney" value="لا ذاكرة كاÙية"/> + <node name="purchaseMissingBook" value="كتاب Ù…Ùقود"/> + <node name="purchaseAlreadyPurchased" value="اشتريته Ø¨Ø§Ù„ÙØ¹Ù„"/> + <node name="bookNotPurchased" value="لم ÙŠÙØ´ØªØ± الكتاب"/> + <node name="downloadLimitExceeded" value="تجاوزت ØØ¯ التنزيل"/> + <node name="unsupportedOperation" value="عملية غير مدعومة"/> + <node name="loginAlreadyTaken" value="اسم المستخدم مستخدم من قبل"/> + <node name="loginNotSpecified" value="من ÙØ¶Ù„Ùƒ أدخل اسم مستخدم"/> + <node name="passwordNotSpecified" value="من ÙØ¶Ù„Ùƒ أدخل كلمة سر غير ÙØ§Ø±ØºØ©"/> + <node name="emailNotSpecified" value="من ÙØ¶Ù„Ùƒ أدخل بريدا إلكترونيا"/> + <node name="invalidEMail" value="عنوان بريد إلكتروني خطأ"/> + <node name="tooManyRegistrations" value="الكثير جدا من التسجيلات من رقمك على الإنترنت (IP); أعد Ø§Ù„Ù…ØØ§ÙˆÙ„Ø© بعد عدة دقائق"/> + <node name="noUserEmail" value="لم ÙŠÙØ³Ø¬Ù„ أي مستخدم بالبريد الإلكترني Ø§Ù„Ù…ØØ¯Ø¯"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="خطأ أثناء التنزيل"/> + <node name="message" value="لا يمكن ØØ§Ù„يا تنزيل هذا الكتاب"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="ÙŠÙØÙ…Ù„ الكتاب، انتظر رجاء..."/> + <node name="loadingBookList" value="ÙŠÙØÙ…Ù„ قائمة الكتب، انتظر رجاء..."/> + <node name="migrate" value="ÙŠÙØ±Ù‚ÙŠ لإصدارة جديدة، انتظر رجاء..."/> + <node name="downloadBookList" value="ÙŠÙنزّل قائمة الكتب، انتظر رجاء..."/> + <node name="downloadBook" value="ÙŠÙنزّل الكتاب، انتظر رجاء..."/> + <node name="downloadImages" value="ÙŠÙنزّل الصور، انتظر رجاء..."/> + <node name="authentication" value="يستوثق، انتظر رجاء..."/> + <node name="purchaseBook" value="يشتر الكتاب، انتظر رجاء..."/> + <node name="initializeAuthenticationManager" value="ÙŠÙنزّل معلومات Ø§Ù„ØØ³Ø§Ø¨ØŒ انتظر رجاء..."/> + <node name="loadSubCatalog" value="ÙŠÙØÙ…Ù‘Ù„ الÙهرس، انتظر رجاء..."/> + <node name="registerUser" value="يسجل ØØ³Ø§Ø¨Ø§ جديدا، انتظر رجاء..."/> + <node name="passwordRecovery" value="يسترجع كلمة السر، انتظر رجاء..."/> + <node name="authenticationCheck" value="يتØÙ‚Ù‚ من Ø§Ù„ØØ³Ø§Ø¨ØŒ انتظر رجاء..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="شراء الكتاب"/> + <node name="message" value="أمتأكد أنك تريد شراء كتاب “%s†؟"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="الاستيثاق"/> + <node name="login" value="اسم المستخدم"/> + <node name="password" value="كلمة السر"/> + <node name="skipIP" value="لا تربط مع رقم الإنترنت (IP)"/> + <node name="loginIsEmpty" value="يجب ألا يكون اسم المستخدم خاليا"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="معلومات"/> + <node name="message" value="الÙهرس خال."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="عطّل الÙهرس"/> + <node name="message" value="أمتأكد أنك تريد تعطيل الÙهرس “%sâ€ØŸ يمكنك ØªÙØ¹ÙŠÙ„Ù‡ لاØÙ‚ا من لسان â€œØ¨ØØ« الشبكة†ÙÙŠ ØÙˆØ§Ø± الخيارات."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Ø§ØØ°Ù الكتاب"/> + <node name="message" value="أمتأكد أنك تريد ØØ°Ù الكتاب “%s†من القرص؟"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="سجّل مستخدما"/> + <node name="login" value="اسم المستخدم"/> + <node name="password" value="كلمة السر"/> + <node name="confirmPassword" value="تأكيد كلمة السر"/> + <node name="email" value="البريد الإلكتروني"/> + <node name="differentPasswords" value="يجب أن تتطابق كلمة السر مع تأكديها."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="استعادة كلمة السر"/> + <node name="email" value="البريد الإلكتروني"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="استعادة كلمة السر"/> + <node name="message" value="أرسلت رسالة مع مزيد من Ø§Ù„ØªÙˆØ¶ÙŠØØ§Øª إلى %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="خطأ ÙÙŠ التنزيل"/> + <node name="message" value="تعذّر تنزيل المل٠%s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="القاعدة"/> + <node name="Regular Paragraph" value="الÙقرات العادية"/> + <node name="Title" value="العناوين"/> + <node name="Section Title" value="عناوين الأقسام"/> + <node name="Poem Title" value="عناوين الشعر"/> + <node name="Subtitle" value="العناوين Ø§Ù„ÙØ±Ø¹ÙŠØ©"/> + <node name="Annotation" value="Annotation"/> + <node name="Epigraph" value="Epigraph"/> + <node name="Stanza" value="الأبيات"/> + <node name="Verse" value="الآيات"/> + <node name="Preformatted text" value="النص المنسق مسبقا"/> + <node name="Image" value="الصور"/> + <node name="Cite" value="الاقتباس"/> + <node name="Author" value="المؤلÙ"/> + <node name="Date" value="التاريخ"/> + <node name="Internal Hyperlink" value="الوصلات الداخلية"/> + <node name="Footnote" value="التذييل"/> + <node name="Emphasis" value="التركيز"/> + <node name="Strong" value="المهم"/> + <node name="Subscript" value="النص السÙلي"/> + <node name="Superscript" value="النص العلوي"/> + <node name="Code" value="الكود"/> + <node name="StrikeThrough" value="الشطب"/> + <node name="Contents Table" value="جدول Ø§Ù„Ù…ØØªÙˆÙŠØ§Øª"/> + <node name="Library Entry" value="عنصر ÙÙŠ المكتبة"/> + <node name="Recent Book List" value="قائمة الكتب الأخيرة"/> + <node name="Italic" value="مائل"/> + <node name="Bold" value="عريض"/> + <node name="Definition" value="تعريÙ"/> + <node name="Definition Description" value="Ø´Ø±Ø Ø§Ù„ØªØ¹Ø±ÙŠÙ"/> + <node name="Header 1" value="رأس 1"/> + <node name="Header 2" value="رأس 2"/> + <node name="Header 3" value="رأس 3"/> + <node name="Header 4" value="رأس 4"/> + <node name="Header 5" value="رأس 5"/> + <node name="Header 6" value="رأس 6"/> + <node name="External Hyperlink" value="الوصلات الخارجية"/> + <node name="Link to Another Book" value="وصلة إلى كتاب آخر"/> + </node> + <node name="external"> + <node name="browser" value="Ø§Ù„Ù…ØªØµÙØ"/> + <node name="defaultBrowser" value="Ø§Ù„Ù…ØªØµÙØ Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="خطأ غير معروÙ"/> + <node name="unsupportedCompressionMethod" value="طريقة ضغط غير مدعومة"/> + <node name="encryptedFile" value="مل٠مØÙ…ÙŠ الØÙ‚وق رقميا (DRM)"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="مكتبة الشبكة"/> + </node> + <node name="library"> + <node name="caption" value="المكتبة"/> + </node> +</resources> diff --git a/reader/data/resources/bg.xml b/reader/data/resources/bg.xml new file mode 100644 index 0000000..5bed7fb --- /dev/null +++ b/reader/data/resources/bg.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Bulgarian TDE-Ebook-Reader resources, by Alexander Ivanov --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Показване на книгите"/> + <node name="collapseTree" value="Скриване на книгите"/> + <node name="edit" value="Редактиране на информациÑта"/> + <node name="unknownAuthor" value="ÐеизвеÑтен автор"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Показване на книгите"/> + <node name="collapseTree" value="Скриване на книгите"/> + <node name="edit" value="Редактиране на етикета"/> + <node name="clone" value="Клониране на етикета"/> + <node name="delete" value="Изтриване на етикета"/> + <node name="noTags" value="Книги без етикети"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показване на книгите"/> + <node name="collapseTree" value="Скриване на книгите"/> + </node> + <node name="bookNode"> + <node name="read" value="Четене на книгата"/> + <node name="edit" value="Редактиране на информациÑта"/> + <node name="delete" value="Изтриване на книгата"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="РазширÑване"/> + <node name="collapseTree" value="Свиване"/> + <node name="reload" value="Презареждане"/> + <node name="openInBrowser" value="ОтварÑне в браузера"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="ОтварÑне на каталога"/> + <node name="collapseTree" value="ЗатварÑне на каталога"/> + <node name="login" value="Влизане"/> + <node name="logout" value="Излизане (%s)"/> + <node name="reload" value="Презареждане"/> + <node name="dontShow" value="Скриване на този каталог"/> + <node name="topupAccount" value="Зареждане на Ñметка (в момента: %s)"/> + <node name="register" value="РегиÑтрациÑ"/> + <node name="passwordRecovery" value="Забравена парола?"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Резултати от търÑенето"/> + <node name="expandTree" value="Показване на резултатите"/> + <node name="collapseTree" value="Скриване на резултатите"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Показване на книгите"/> + <node name="collapseTree" value="Скриване на книгите"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показване на книгите"/> + <node name="collapseTree" value="Скриване на книгите"/> + </node> + <node name="bookNode"> + <node name="read" value="Четене на локалното копие"/> + <node name="delete" value="Изтриване на локалното копие"/> + <node name="download" value="СвалÑне"/> + <node name="readDemo" value="Четене на демото"/> + <node name="downloadDemo" value="СвалÑне на демото"/> + <node name="demo" value="Демо"/> + <node name="buy" value="Купуване (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° книгата..."/> + <node name="toc" value="Съдържание"/> + <node name="showLibrary" value="ОтварÑне на библиотека"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Библиотека"> + <node name="showLibrary" value="ОтварÑне"/> + <node name="previousBook" value="Предишна книга"/> + <node name="showRecent" value="ПоÑледна"/> + <node name="addBook" value="ДобавÑне на книга..."/> + <node name="showHelp" value="За програмата TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Отиване в началото на документа"/> + <node name="gotoPageNumber" value="Отиване на Ñтраница..."/> + <node name="gotoSectionStart" value="Отиване в началото на текÑÑ‚Ð¾Ð²Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»"/> + <node name="gotoSectionEnd" value="Отиване в ÐºÑ€Ð°Ñ Ð½Ð° раздела"/> + <node name="nextTOCSection" value="Отиване на Ñледващата глава"/> + <node name="previousTOCSection" value="Отиване на предишната глава"/> + <node name="navigate" value="Преход"> + <node name="gotoHome" value="Отиване в началото на документа"/> + <node name="gotoPageNumber" value="Отиване на Ñтраница..."/> + <node name="gotoSectionStart" value="Отиване в началото на текÑÑ‚Ð¾Ð²Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»"/> + <node name="gotoSectionEnd" value="Отиване в ÐºÑ€Ð°Ñ Ð½Ð° раздела"/> + <node name="nextTOCSection" value="Отиване на Ñледващата глава"/> + <node name="previousTOCSection" value="Отиване на предишната глава"/> + <node name="undo" value="Ðазад"/> + <node name="redo" value="Ðапред"/> + </node> + <node name="selection" value="Избор"> + <node name="copyToClipboard" value="Копиране в клипборда"/> + <node name="openInDictionary" value="ОтварÑне в речника"/> + <node name="clearSelection" value="ИзчиÑтване"/> + </node> + <node name="search" value="ТърÑене"> + <node name="search" value="Ðамиране на текÑÑ‚..."/> + <node name="findNext" value="Ðамиране на ÑледващиÑ"/> + <node name="findPrevious" value="Ðамиране на предишниÑ"/> + </node> + <node name="view" value="Изглед"> + <node name="rotate" value="Завъртане на екрана"/> + <node name="toggleFullscreen" value="Ðа цÑл екран"/> + <node name="toggleIndicator" value="Включване на индикатора"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="ЗатварÑне"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Четене на книгата"/> + <node name="tooltip" value="Връщане към четенето"/> + </node> + <node name="showLibrary"> + <node name="label" value="Библиотека"/> + <node name="tooltip" value="Библиотека"/> + <node name="popup" value="Показване на ÑпиÑък Ñ Ð½Ð°Ñкоро прочетените книги"/> + </node> + <node name="showRecent"> + <node name="label" value="ИÑториÑ"/> + <node name="tooltip" value="Показване на ÑпиÑък Ñ Ð½Ð°Ñкоро прочетените книги"/> + </node> + <node name="byAuthor"> + <node name="label" value="По автори"/> + <node name="tooltip" value="Подреждане на книгите по автори"/> + </node> + <node name="byTag"> + <node name="label" value="По етикети"/> + <node name="tooltip" value="Подреждане на книгите по етикети"/> + </node> + <node name="addBook"> + <node name="label" value="ДобавÑне на файл"/> + <node name="tooltip" value="ДобавÑне на файл в библиотеката"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Интернет"/> + <node name="tooltip" value="ТърÑене в интернет библиотеки"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Бързо търÑене"/> + <node name="tooltip" value="ТърÑене в интернет"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="ТърÑене"/> + <node name="tooltip" value="Разширено търÑене в интернет"/> + </node> + <node name="gotoHome"> + <node name="label" value="Отиване в началото"/> + <node name="tooltip" value="Отиване в началото на текÑта"/> + </node> + <node name="undo"> + <node name="label" value="Ðазад"/> + <node name="tooltip" value="Ðазад"/> + </node> + <node name="redo"> + <node name="label" value="Ðапред"/> + <node name="tooltip" value="Ðапред"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Отиване на Ñтраница"/> + <node name="tooltip" value="Отиване на Ñтраница"/> + </node> + <node name="toc"> + <node name="label" value="Съдържание"/> + <node name="tooltip" value="Съдържание"/> + </node> + <node name="search"> + <node name="label" value="ТърÑене"/> + <node name="tooltip" value="ТърÑене на текÑÑ‚"/> + </node> + <node name="findNext"> + <node name="label" value="СледващиÑ"/> + <node name="tooltip" value="Ðамиране на ÑледващиÑ"/> + </node> + <node name="findPrevious"> + <node name="label" value="Предишен"/> + <node name="tooltip" value="Ðамиране на предишниÑ"/> + </node> + <node name="rotate"> + <node name="label" value="Завъртане"/> + <node name="tooltip" value="Завъртане на текÑта"/> + </node> + <node name="showHelp"> + <node name="label" value="За програмата"/> + <node name="tooltip" value="За програмата"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Филтър"/> + <node name="tooltip" value="Филтър"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° книгата"/> + <node name="tooltip" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° книгата"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&ТърÑене"/> + <node name="thisOnly" value="Само това"/> + <node name="withSubtags" value="С подетикети"/> + <node name="removeLink" value="Изтриване от библиотеката"/> + <node name="removeFile" value="Изтриване от диÑка"/> + <node name="yesToAll" value="Да за &вÑички"/> + <node name="buy" value="&Купуване"/> + <node name="buyAndDownload" value="Купуване и &ÑвалÑне"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Библиотека"> + <node name="bookPath" value="Папка за Ñъхранение на книгите"/> + <node name="lookInSubdirectories" value="ТърÑене на книги в поддиректориите"/> + <node name="collectBooksWithoutMetaInfo" value="Събиране на книги без метаинформациÑ"/> + <node name="downloadDirectory" value="Папка за ÑвалÑне на книгите"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" toBeTranslated="true" value="Network Library"> + </node> + <node name="Connection" toBeTranslated="true" value="Connection"> + <node name="useProxy" value="Използване прокÑи-Ñървър"/> + <node name="proxyHost" value="ÐÐ´Ñ€ÐµÑ Ð½Ð° прокÑи-Ñървъра"/> + <node name="proxyPort" value="Порт на прокÑи-Ñървъра"/> + <node name="timeout" value="МакÑимално време за изчакване в Ñекунди"/> + </node> + <node name="Web" value="Интернет"> + <node name="enableIntegration" value="ОтварÑне външните линкове Ñ %s"/> + <node name="defaultText" value="ОтварÑне външните линкове Ñ Ð±Ñ€Ð°ÑƒÐ·ÑŠÑ€Ð°"/> + <node name="choice" value="Използване на браузер"/> + <node name="command" value="Команда за изпълнение"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Език"> + <node name="autoDetect" value="Ðвтоматично определÑне на езика и кодирането"/> + <node name="defaultLanguage" value="Език по подразбиране"/> + <node name="defaultEncodingSet" value="ÐаÑтройване на кодирането по подразбиране"/> + <node name="defaultEncoding" value="Кодиране по подразбиране"/> + <node name="useWindows1252Hack" value="Използване на windows-1252 вмеÑто iso-8859-1"/> + </node> + <node name="Config" value="ÐаÑтройки"> + <node name="autoSave" value="Ðвтоматично запиÑване на ÑÑŠÑтоÑнието"/> + <node name="timeout" value="Време между запиÑваниÑта, Ñекунди"/> + </node> + <node name="Dictionary" value="Речник"> + <node name="enableIntegration" value="Включване на Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Ñ %s"/> + <node name="defaultText" value="Включване на Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Ñ Ñ€ÐµÑ‡Ð½Ð¸ÐºÐ°"/> + <node name="choice" value="Интегриране Ñ"/> + <node name="singleClickOpen" value="ОтварÑне Ñ ÐµÐ´Ð¸Ð½Ð¸Ñ‡ÐµÐ½ клик"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Реагиране на отпуÑкане на клавиш, а не на натиÑкане"/> + <node name="minStylusPressure" value="Минимален натиÑк на ÑтилуÑа"/> + <node name="maxStylusPressure" value="МакÑимален натиÑк на ÑтилуÑа"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="ПрелиÑтване"> + <node name="keyScrollDelay" value="ЗабавÑне между клавишни Ð¿Ñ€ÐµÐ²ÑŠÑ€Ñ‚Ð°Ð½Ð¸Ñ Ð² милиÑекунди"/> + <node name="keyLinesToScroll" value="Редове за прелиÑтване при редово прелиÑтване"/> + <node name="keyLinesToKeep" value="Редове за запазване при прелиÑтване на Ñтраници"/> + <node name="enableTapScrolling" value="Включване на прелиÑтването чрез натиÑкане върху екрана"/> + <node name="fingerOnly" value="Само при натиÑкане Ñ Ð¿Ñ€ÑŠÑÑ‚"/> + </node> + <node name="Selection" value="Маркиране"> + <node name="enableSelection" value="Включване на маркирането на текÑÑ‚"/> + </node> + <node name="Indicator" value="Индикатор"> + <node name="type" value="Показване като"> + <node name="osScrollbar" value="OS плъзгач"/> + <node name="fbIndicator" value="Индикатор в Ñтар Ñтил"/> + <node name="none" value="Да не Ñе показва"/> + </node> + <node name="height" value="ВиÑочина на индикатора"/> + <node name="offset" value="ОтÑтъп от текÑта"/> + <node name="pageNumber" value="Показване на номера на Ñтраницата"/> + <node name="time" value="Показване на текущото време"/> + <node name="fontSize" value="Размер на шрифта"/> + <node name="tocMarks" value="Показване на маркери към Ñъдържанието"/> + <node name="navigation" value="Включване на навигациÑта"/> + </node> + <node name="Rotation" value="Завъртане"> + <node name="direction" value="Ðачин на завъртане"> + <node name="disabled" value="Изключено"/> + <node name="clockwise" value="Ðа 90 градуÑа по чаÑовниковата Ñтрелка"/> + <node name="counterclockwise" value="Ðа 90 градуÑа обратно на чаÑовниковата Ñтрелка"/> + <node name="180" value="Ðа 180 градуÑа"/> + <node name="cycle" value="Завъртане през вÑичките четири ориентации"/> + </node> + </node> + <node name="Keys" value="Клавиши"> + <node name="grabSystemKeys" value="Прихващане на ÑиÑтемните клавиши"/> + <node name="separate" value="Бързи клавиши в завиÑимоÑÑ‚ от ориентациÑта"/> + <node name="orientation" value="ОриентациÑ"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="ÐÑма"/> + <node name="showLibrary" value="Показване на библиотеката"/> + <node name="showNetLibrary" value="Показване на интернет библиотеки"/> + <node name="showRecent" value="Показване на поÑледните книги"/> + <node name="previousBook" value="ОтварÑне на предишната книга"/> + <node name="toc" value="Показване на Ñъдържанието"/> + <node name="gotoHome" value="Отиване на началната Ñтраница"/> + <node name="gotoSectionStart" value="Отиване в началото на раздела"/> + <node name="gotoSectionEnd" value="Отиване в ÐºÑ€Ð°Ñ Ð½Ð° раздела"/> + <node name="nextTOCSection" value="Отиване на ÑÐ»ÐµÐ´Ð²Ð°Ñ‰Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»"/> + <node name="previousTOCSection" value="Отиване на Ð¿Ñ€ÐµÐ´Ð¸ÑˆÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»"/> + <node name="pageForward" value="Превъртане на Ñтраницата напред"/> + <node name="pageBackward" value="Превъртане на Ñтраницата назад"/> + <node name="lineForward" value="Превъртане на реда напред"/> + <node name="lineBackward" value="Превъртане на реда назад"/> + <node name="undo" value="ОтмÑна"/> + <node name="redo" value="ВъзÑтановÑване"/> + <node name="copyToClipboard" value="Копирай Ð¼Ð°Ñ€ÐºÐ¸Ñ€Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑÑ‚ в клипборда"/> + <node name="openInDictionary" value="ОтварÑне на Ð¼Ð°Ñ€ÐºÐ¸Ñ€Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑÑ‚ в речника"/> + <node name="clearSelection" value="ИзчиÑтване на маркираното"/> + <node name="search" value="ТърÑене"/> + <node name="findPrevious" value="Ðамиране на предишниÑ"/> + <node name="findNext" value="Ðамиране на ÑледващиÑ"/> + <node name="increaseFont" value="Увеличаване на размера на шрифта"/> + <node name="decreaseFont" value="ÐамалÑване на размера на шрифта"/> + <node name="toggleIndicator" value="Показване/Ñкриване на индикатора"/> + <node name="toggleFullscreen" value="Включване/изключване на цÑл екран"/> + <node name="rotate" value="Завъртане на екрана"/> + <node name="addBook" value="ДобавÑне на книга"/> + <node name="cancel" value="ОтмÑна"/> + <node name="quit" value="Изход"/> + <node name="bookInfo" value="Показване на диалог за Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° книгата"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Изход от програмата при отмÑна"/> + <node name="keyDelay" value="ЗабавÑне между натиÑкането на клавиш"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Винаги да Ñе използват ÑобÑтвени шрифтове"/> + </node> + <node name="Margins" value="ОтÑтъпи"> + <node name="left" value="ОтÑтъп отлÑво"/> + <node name="right" value="ОтÑтъп отдÑÑно"/> + <node name="top" value="ОтÑтъп отгоре"/> + <node name="bottom" value="ОтÑтъп отдолу"/> + </node> + <node name="Format" value="Форматиране"> + <node name="optionsFor" value="ÐаÑтройки за"/> + <node name="lineSpacing" value="Междуредие"> + <node name="unchanged" value="<Ðепроменено>"/> + </node> + <node name="firstLineIndent" value="ОтÑтъп на първи ред"/> + <node name="alignment" value="ПодравнÑване"> + <node name="left" value="ЛÑво"/> + <node name="right" value="ДÑÑно"/> + <node name="center" value="Център"/> + <node name="justify" value="По краищата"/> + <node name="unchanged" value="<Ðепроменено>"/> + </node> + <node name="spaceBefore" value="Интервал преди"/> + <node name="spaceAfter" value="Интервал Ñлед"/> + <node name="startIndent" value="ОтÑтъп в началото на реда"/> + <node name="endIndent" value="ОтÑтъп в ÐºÑ€Ð°Ñ Ð½Ð° реда"/> + </node> + <node name="Styles" value="Стилове"> + <node name="optionsFor" value="ÐаÑтройки за"/> + <node name="fontFamily" value="Шрифт"> + <node name="unchanged" value="<Ðепроменено>"/> + </node> + <node name="fontSize" value="Размер"/> + <node name="fontSizeDifference" value="Размер"/> + <node name="bold" value="Удебелен"/> + <node name="italic" value="Ðаклонен"/> + <node name="allowHyphenations" value="Разрешаване на пренаÑÑне"/> + <node name="autoHyphenations" value="Ðвтоматично пренаÑÑне"/> + </node> + <node name="Colors" value="Цветове"> + <node name="colorFor" value="ЦвÑÑ‚ за"> + <node name="background" value="Фон"/> + <node name="selectionBackground" value="Фон на маркираното"/> + <node name="text" value="Обикновен текÑÑ‚"/> + <node name="internalLink" value="ТекÑÑ‚ на вътрешен линк"/> + <node name="externalLink" value="ТекÑÑ‚ на външен линк"/> + <node name="bookLink" value="Линк към друга книга"/> + <node name="highlighted" value="Маркиран текÑÑ‚"/> + <node name="treeLines" value="Линии"/> + <node name="indicator" value="ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð½Ð° индикатора"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° книгата"/> + <node name="tab"> + <node name="Common" value="ОÑновна"> + <node name="file" value="Файл"/> + <node name="title" value="Заглавие"/> + <node name="language" value="Език"/> + <node name="encodingSet" value="ÐаÑтройка на кодирането"/> + <node name="encoding" value="Кодиране"/> + </node> + <node name="Authors" value="Ðвтори"> + <node name="authorDisplayName" value="Име на автора"/> + </node> + <node name="Series" value="Поредица"> + <node name="seriesTitle" value="Заглавие на поредицата"/> + <node name="bookIndex" value="Ðомер на книгата в поредицата"/> + </node> + <node name="Tags" value="Етикет"> + <node name="tags" value="Име на етикета"/> + </node> + <node name="Text" value="ТекÑÑ‚"> + <node name="breakType" value="Ðов параграф на"/> + <node name="ignoreIndent" value="Игнориране на отÑтъп по-малък от"/> + <node name="buildTOC" value="Създаване на Ñъдържание"/> + <node name="emptyLines" value="Празни редове преди нова глава"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Ðов параграф на"/> + <node name="ignoreIndent" value="Игнориране на отÑтъп по-малък от"/> + <node name="buildTOC" value="Създаване на Ñъдържание"/> + <node name="emptyLines" value="Празни редове преди нова глава"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° автора"/> + <node name="name" value="Име на автора"/> + <node name="sortKey" value="Сортиране на авторите по"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - ДобавÑне на книга в библиотеката"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="ТърÑене на текÑÑ‚"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Игнориране на региÑтъра на буквите"/> + <node name="wholeText" value="Ð’ Ñ†ÐµÐ»Ð¸Ñ Ñ‚ÐµÐºÑÑ‚"/> + <node name="backward" value="Ðазад"/> + <node name="currentSection" value="&Само в тази глава"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="ТърÑене в интернет"/> + <node name="titleAndSeries" value="Заглавие/Поредица"/> + <node name="author" value="Ðвтор"/> + <node name="category" value="Етикет"/> + <node name="description" value="ОпиÑание"/> + <node name="annotation" value="Резултати от търÑенето за: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Отиване на Ñтраница"/> + <node name="pageNumber" value="Отиване на Ñтраница номер"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Редактиране на етикета"/> + <node name="name" value="Име на етикета"/> + <node name="includeSubtags" value="Включително подетикетите"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Клониране на етикета"/> + <node name="name" value="Име на етикета"/> + <node name="includeSubtags" value="Включително подетикетите"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Изтриване на книга"/> + <node name="message" value="Изтриване на книгата “%s†от библиотеката?"/> + <node name="deleteFile" value="Сигурни ли Ñте, че желаете да изтриете файла “%s†от диÑка?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Изтриване на етикета"/> + <node name="message" value="Изтриване на етикета “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Грешка"/> + <node name="message" value="Ðе може да Ñе отвори: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Грешка"/> + <node name="message" value="Ðе може да Ñе изтрие файла %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Грешка"/> + <node name="message" value="ÐŸÐ¾Ð¼Ð¾Ñ‰Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» не е намерен, за Ñъжаление"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="СпиÑъка Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñ‚ÐµÐºÐ¸ е празен"/> + <node name="authenticationFailed" value="ИдентификациÑта Ñе провали"/> + <node name="internalError" value="Вътршена грешка на Ñървъра"/> + <node name="purchaseNotEnoughMoney" value="ÐедоÑтатъчно ÑредÑтва в Ñметката"/> + <node name="purchaseMissingBook" value="Книгата липÑва"/> + <node name="purchaseAlreadyPurchased" value="Книгата вече е платена"/> + <node name="bookNotPurchased" value="Книгата не е платена"/> + <node name="downloadLimitExceeded" value="Лимитът за ÑвалÑÐ½Ð¸Ñ Ðµ изчерпан"/> + <node name="unsupportedOperation" value="Ðеподдържана операциÑ"/> + <node name="loginAlreadyTaken" value="Това потребителÑко име вече е използвано"/> + <node name="loginNotSpecified" value="МолÑ, въведете потребитрелÑко име"/> + <node name="passwordNotSpecified" value="МолÑ, въведете непразна парола"/> + <node name="emailNotSpecified" value="МолÑ, въведете имейл адреÑ"/> + <node name="invalidEMail" value="Ðевалиден имейл адреÑ"/> + <node name="tooManyRegistrations" value="Твърде много региÑтрации от вашето IP; опитайте отново Ñлед нÑколко минути"/> + <node name="noUserEmail" value="ÐÑма региÑтриран потребител Ñ Ñ‚Ð¾Ð·Ð¸ имейл адреÑ"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Грешка по време на ÑвалÑне"/> + <node name="message" value="Ðе може да Ñе Ñвали тази книга в момента"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Зареждане на книга. МолÑ, изчакайте..."/> + <node name="loadingBookList" value="Зареждане на библиотека. МолÑ, изчакайте..."/> + <node name="migrate" value="ОбновÑване до нова верÑиÑ. МолÑ, изчакайте..."/> + <node name="downloadBookList" value="СвалÑне на ÑпиÑъка Ñ ÐºÐ½Ð¸Ð³Ð¸. МолÑ, изчакайте..."/> + <node name="downloadBook" value="СвалÑне на книга. МолÑ, изчакайте..."/> + <node name="downloadImages" value="СвалÑне на изображениÑ. МолÑ, изчакайте..."/> + <node name="authentication" value="ИдентификациÑ. МолÑ, изчакайте..."/> + <node name="purchaseBook" value="Плащане на книга. МолÑ, изчакайте..."/> + <node name="initializeAuthenticationManager" value="СвалÑне на Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° профила. МолÑ, изчакайте..."/> + <node name="loadSubCatalog" value="Зареждане на каталога. МолÑ, изчакайте..."/> + <node name="registerUser" value="РегиÑтриране на нов профил. МолÑ, изчакайте..."/> + <node name="passwordRecovery" value="ВъзÑтановÑване на парола. МолÑ, изчакайте..."/> + <node name="authenticationCheck" value="Проверка за валидноÑÑ‚ на профила. МолÑ, изчакайте..."/> + <node name="signOut" value="ОтпиÑване. МолÑ, изчакайте..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Плащане на книга"/> + <node name="message" value="Сигурни ли Ñте, че желаете да купите книгата “%s†?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="ИдентификациÑ"/> + <node name="login" value="ПотребителÑко име"/> + <node name="password" value="Парола"/> + <node name="skipIP" value="Да не Ñе Ñвързва Ñ ip-адреÑа"/> + <node name="loginIsEmpty" value="ПотребителÑкото име не може да бъде празно"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="ИнформациÑ"/> + <node name="message" value="Каталогът е празен."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Изключване на каталога"/> + <node name="message" value="Сигурни ли Ñте, че желаете да изключите каталога “%s†? Вие можете да го включите отново на “ТърÑене в интернет†в диалога ÐаÑтройки."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Изтриване на книгата"/> + <node name="message" value="Сигурни ли Ñте, че желаете да изтриете “%s†книгата от диÑка?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="РегиÑтриране на потребител"/> + <node name="login" value="ПотребителÑко име"/> + <node name="password" value="Парола"/> + <node name="confirmPassword" value="Потвърдете паролата"/> + <node name="email" value="Имейл" tooltip="Имейлът Ñе използва за възÑтановÑване на вашата парола в Ñлучай, че Ñ Ð·Ð°Ð³ÑƒÐ±Ð¸Ñ‚Ðµ. Ðко не укажете имейл нÑма да може да възÑтановите вашата парола."/> + <node name="differentPasswords" value="Паролата и потвърдената парола трÑбва да бъдат еднакви."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="ВъзÑтановÑване на парола"/> + <node name="email" value="Имейл"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="ВъзÑтановÑване на парола"/> + <node name="message" value="Съобщение Ñ Ð¿Ð¾Ð½Ð°Ñ‚Ð°Ñ‚ÑŠÑˆÐ½Ð¸ инÑтрукции беше изпратена на Ð°Ð´Ñ€ÐµÑ %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Грешка при ÑвалÑнето"/> + <node name="message" value="Ðе може да Ñе отвори ÑÐ²Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð» %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="ОÑновен текÑÑ‚"/> + <node name="Regular Paragraph" value="Обикновен параграф"/> + <node name="Title" value="Заглавие"/> + <node name="Section Title" value="Заглавие на главата"/> + <node name="Poem Title" value="Заглавие на Ñтихотворението"/> + <node name="Subtitle" value="Субтитри"/> + <node name="Annotation" value="ÐнотациÑ"/> + <node name="Epigraph" value="Епиграф"/> + <node name="Stanza" value="Строфа"/> + <node name="Verse" value="Стих"/> + <node name="Preformatted text" value="Преформатиран текÑÑ‚"/> + <node name="Image" value="Изображение"/> + <node name="Cite" value="Цитат"/> + <node name="Author" value="Ðвтор"/> + <node name="Date" value="Дата"/> + <node name="Internal Hyperlink" value="Вътрешен линк"/> + <node name="Footnote" value="ПоÑÑнение"/> + <node name="Emphasis" value="Ударение (емфаза)"/> + <node name="Strong" value="Ударение (твърдо)"/> + <node name="Subscript" value="Долен индекÑ"/> + <node name="Superscript" value="Горен индекÑа"/> + <node name="Code" value="Код"/> + <node name="StrikeThrough" value="Зачертан текÑÑ‚"/> + <node name="Contents Table" value="Таблици на Ñъдържанието"/> + <node name="Library Entry" value="Вход към библиотека"/> + <node name="Recent Book List" value="Скорошен ÑпиÑък Ñ ÐºÐ½Ð¸Ð³Ð¸"/> + <node name="Italic" value="Ðаклонен"/> + <node name="Bold" value="Удебелен"/> + <node name="Definition" value="ДефинициÑ"/> + <node name="Definition Description" value="ОпиÑание на дефинициÑта"/> + <node name="Header 1" value="текÑÑ‚ в <h1>"/> + <node name="Header 2" value="текÑÑ‚ в <h2>"/> + <node name="Header 3" value="текÑÑ‚ в <h3>"/> + <node name="Header 4" value="текÑÑ‚ в <h4>"/> + <node name="Header 5" value="текÑÑ‚ в <h5>"/> + <node name="Header 6" value="текÑÑ‚ в <h6>"/> + <node name="External Hyperlink" value="Външен линк"/> + <node name="Link to Another Book" value="Линк към друга книга"/> + </node> + <node name="external"> + <node name="browser" value="Браузър"/> + <node name="defaultBrowser" value="Браузъра по подразбиране"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="ÐеизвеÑтна грешка"/> + <node name="unsupportedCompressionMethod" value="Ðеподдържан метод на компреÑиÑ"/> + <node name="encryptedFile" value="файлът е Ñ DRM-защита"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Интернет библиотека"/> + </node> + <node name="library"> + <node name="caption" value="Библиотека"/> + </node> +</resources> diff --git a/reader/data/resources/cs.xml b/reader/data/resources/cs.xml new file mode 100644 index 0000000..807d137 --- /dev/null +++ b/reader/data/resources/cs.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Czech TDE-Ebook-Reader resources, by LubomÃr ÄŒevela --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Zobrazit seznam knih"/> + <node name="collapseTree" value="Skrýt seznam knih"/> + <node name="edit" value="Upravit informace o knize"/> + <node name="unknownAuthor" value="Neznámý autor"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Zobrazit seznam knih"/> + <node name="collapseTree" value="Skrýt seznam knih"/> + <node name="edit" value="Upravit informace o knize"/> + <node name="clone" value="ZkopÃrovat informace o knize"/> + <node name="delete" value="Odstranit informace o knize"/> + <node name="noTags" value="Žádné informace o knize nejsou k dispozici"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Zobrazit seznam knih"/> + <node name="collapseTree" value="Skrýt seznam knih"/> + </node> + <node name="bookNode"> + <node name="read" value="ÄŒÃst knihu"/> + <node name="edit" value="Upravit informace o knize"/> + <node name="delete" value="Odstranit knihu"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Podle autora"> + <node name="summary" value="Knihy seÅ™azeny podle autora"/> + </node> + <node name="byTitle" value="Podle názvu"> + <node name="summary" value="Knihy seÅ™azeny podle názvu"/> + </node> + <node name="byDate" value="Podle data"> + <node name="summary" value="Knihy seÅ™azeny podle data zakoupenÃ"/> + </node> + <node name="bySeries" value="Podle série"> + <node name="summary" value="Knihy seÅ™azeny podle série"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Rozbalit"/> + <node name="collapseTree" value="Skrýt"/> + <node name="reload" value="Obnovi"/> + <node name="openInBrowser" value="OtevÅ™Ãt v internetovém prohlÞeÄi"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="OtevÅ™Ãt katalog"/> + <node name="collapseTree" value="ZavÅ™Ãt katalog"/> + <node name="login" value="PÅ™ihlášenÃ"/> + <node name="logout" value="Odhlášenà (%s)"/> + <node name="reload" value="Obnovit"/> + <node name="dontShow" value="'Nezobrazovat tento katalog"/> + <node name="topupAccount" value="Top up account (currently: %s)"/> + <node name="register" value="PÅ™ihlášenÃ"/> + <node name="passwordRecovery" value="Obnovit heslo"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Hledat"/> + <node name="expandTree" value="Zobrazit výsledky"/> + <node name="collapseTree" value="Skrýt výsledky"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Zobrazit knihy"/> + <node name="collapseTree" value="Skrýt knihy"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Zobrazit knihy"/> + <node name="collapseTree" value="Skrýt knihy"/> + </node> + <node name="bookNode"> + <node name="read" value="ÄŒÃst lokálnà verzi knihy"/> + <node name="delete" value="Smazat lokálnà verzi knihy"/> + <node name="download" value="Stáhnout"/> + <node name="readDemo" value="ÄŒÃst ukázku"/> + <node name="downloadDemo" value="Stáhnout ukázku"/> + <node name="demo" toBeTranslated="true" value="sample"/> + <node name="buy" value="Zaplatit (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informace o knize..."/> + <node name="toc" value="Obsah"/> + <node name="showLibrary" value="OtevÅ™Ãt knihovnu"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Knihovna"> + <node name="showLibrary" value="OtevÅ™Ãt"/> + <node name="previousBook" value="PÅ™edchozà kniha"/> + <node name="showRecent" value="Nedávné"/> + <node name="addBook" value="PÅ™idat knihu..."/> + <node name="showHelp" value="O programu TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Na zaÄátek dokumentu"/> + <node name="gotoPageNumber" value="Na stránku..."/> + <node name="gotoSectionStart" value="Na zaÄátek oddÃlu"/> + <node name="gotoSectionEnd" value="Na konec oddÃlu"/> + <node name="nextTOCSection" value="Na dalšà položku obsahu"/> + <node name="previousTOCSection" value="Na pÅ™edchozà položku obsahu"/> + <node name="navigate" value="Navigovat"> + <node name="gotoHome" value="Na zaÄátek dokumentu"/> + <node name="gotoPageNumber" value="Na stránku..."/> + <node name="gotoSectionStart" value="Na zaÄátek oddÃlu"/> + <node name="gotoSectionEnd" value="Na konec oddÃlu"/> + <node name="nextTOCSection" value="Na dalšà položku obsahu"/> + <node name="previousTOCSection" value="Na pÅ™edchozà položku obsahu"/> + <node name="undo" value="ZpÄ›t"/> + <node name="redo" value="DopÅ™edu"/> + </node> + <node name="selection" value="Vybrat"> + <node name="copyToClipboard" value="KopÃrovat"/> + <node name="openInDictionary" value="OtevÅ™Ãt ve slovnÃku"/> + <node name="clearSelection" value="VyÄistit výbÄ›r"/> + </node> + <node name="search" value="NajÃt"> + <node name="search" value="NajÃt text..."/> + <node name="findNext" value="NajÃt dalÅ¡Ã"/> + <node name="findPrevious" value="NajÃt pÅ™edchozÃ"/> + </node> + <node name="view" value="Zobrazit"> + <node name="rotate" value="OtoÄit obrazovku"/> + <node name="toggleFullscreen" value="Celá obrazovka"/> + <node name="toggleIndicator" value="NatoÄenà obrazovky"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="UkonÄit"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="ÄŒtecà režim"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Knihovna - stromový pohled"/> + <node name="popup" value="Nedávno otevÅ™ené knihy"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Seznam nedávno otevÅ™ených knih"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="SeÅ™adit knihy dle autorů"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="SeÅ™adit knihy dle klÃÄových slov"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Vložit do knihovny"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="Hledat v knihovnÄ› na sÃti"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Hledat na sÃti"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="RozÅ¡ÃÅ™ené hledánà na sÃti"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Návrat na zaÄátek textu"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="ZpÄ›t"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Znovu"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="PÅ™ejÃt na stránku"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Obsah"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Hledat text"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="NajÃt dalÅ¡Ã"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="NajÃt pÅ™edchozÃ"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="ZmÄ›na smÄ›ru textu"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="O programu TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Informace o knize"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Provést"/> + <node name="thisOnly" value="Pouze tento"/> + <node name="withSubtags" value="S rozÅ¡ÃÅ™enými volbami"/> + <node name="removeLink" value="Odstranit z knihovny"/> + <node name="removeFile" value="Odstranit z disku"/> + <node name="yesToAll" value="&Ano pro vÅ¡echny"/> + <node name="buy" value="&Zaplatit"/> + <node name="buyAndDownload" value="Zaplatit a &stáhnout"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Knihovna"> + <node name="bookPath" value="Složka s knihami"/> + <node name="lookInSubdirectories" value="Knihy v podadresáři"/> + <node name="collectBooksWithoutMetaInfo" value="Shromáždit knihy bez informacà o knihách (metadat)"/> + <node name="downloadDirectory" value="Prohledávat podadresáře"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Hledánà knih na sÃti"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="PoužÃt Proxy"/> + <node name="proxyHost" value="Proxy server"/> + <node name="proxyPort" value="Port Proxy serveru"/> + <node name="timeout" value="VyprÅ¡enà Äasového intervalu sÃtÄ› v sekundách"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="OtevÃrat externà odkazy v %s"/> + <node name="defaultText" value="OtevÃrat externà odkazy v prohlÞeÄi"/> + <node name="choice" value="PoužÃt prohlÞeÄ"/> + <node name="command" value="Vložte pÅ™Ãkaz"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Jazyk"> + <node name="autoDetect" value="Automatická detekce jazyka o kódovánà znaků"/> + <node name="defaultLanguage" value="PÅ™edvolený jazyk"/> + <node name="defaultEncodingSet" value="PÅ™edvolená sada kódovánÃ"/> + <node name="defaultEncoding" value="Základnà kódovánÃ"/> + <node name="useWindows1252Hack" value="PoužÃt windows-1252 namÃsto iso-8859-1"/> + </node> + <node name="Config" value="NastavenÃ"> + <node name="autoSave" value="Automatické uloženÃ"/> + <node name="timeout" value="Interval mezi uloženÃmi v sekundách"/> + </node> + <node name="Dictionary" value="SlovnÃk"> + <node name="enableIntegration" value="Zapnout integraci s %s"/> + <node name="defaultText" value="Zapnout integraci se slovnÃkem"/> + <node name="choice" value="Integrace s"/> + <node name="singleClickOpen" value="OtevÅ™Ãt jednÃm kliknutÃm"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Reagovat na puÅ¡tÄ›nà klávesy mÃsto stisku klávesy"/> + <node name="minStylusPressure" value="Minimálnà tlak stylusu"/> + <node name="maxStylusPressure" value="Maximálnà tlak stylusu"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Posuv textu"> + <node name="keyScrollDelay" value="ZpoždÄ›nà mezi stiskem kláves posuvu v msec"/> + <node name="keyLinesToScroll" value="PoÄet řádků posuvu pÅ™i posuvu po řádcÃch"/> + <node name="keyLinesToKeep" value="PoÄet řádků, které nebudou pÅ™ekresleny"/> + <node name="enableTapScrolling" value="Posun dotykem na displeji"/> + <node name="fingerOnly" value="Posuv pouze dotykem na displeji"/> + </node> + <node name="Selection" value="VýbÄ›r"> + <node name="enableSelection" value="Povolit výbÄ›r textu"/> + </node> + <node name="Indicator" value="Indikátor"> + <node name="type" value="Zobraz jako"> + <node name="osScrollbar" value="PosuvnÃk OS"/> + <node name="fbIndicator" value="Indikátor ve starém stylu"/> + <node name="none" value="Nezobrazovat"/> + </node> + <node name="height" value="Výška indikátoru"/> + <node name="offset" value="Vzdálenost od textu"/> + <node name="pageNumber" value="Zobrazit polohu ÄÃselnÄ›"/> + <node name="time" value="Zobrazit Äas"/> + <node name="fontSize" value="Velikost pÃsma"/> + <node name="tocMarks" value="Zobraz znaÄky TOC"/> + <node name="navigation" value="Povolit navigaci"/> + </node> + <node name="Rotation" value="NatoÄenÃ"> + <node name="direction" value="SmÄ›r natoÄenÃ"> + <node name="disabled" value="Vypnuto"/> + <node name="clockwise" value="90 stupňů ve smÄ›ru hodinových ruÄiÄek"/> + <node name="counterclockwise" value="90 stupňů proti smÄ›ru hodinových ruÄiÄek"/> + <node name="180" value="180 stupňů"/> + <node name="cycle" value="StÅ™Ãdat vÅ¡echny ÄtyÅ™i smÄ›ry"/> + </node> + </node> + <node name="Keys" value="Klávesové zkratky"> + <node name="grabSystemKeys" value="PÅ™evzÃt systémové zkratky"/> + <node name="separate" value="Vlastnà zkratky zavislé na orientaci textu"/> + <node name="orientation" value="Orientace"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Žádné"/> + <node name="showLibrary" value="Zobrazit knihovnu"/> + <node name="showNetLibrary" value="Zobrazit knihovnu na sÃti"/> + <node name="showRecent" value="Zobrazit nedávné"/> + <node name="previousBook" value="OtevÅ™Ãt pÅ™edchozà knihu"/> + <node name="toc" value="Zobrazit obsah"/> + <node name="gotoHome" value="PÅ™ejÃt na zaÄátek textu"/> + <node name="gotoSectionStart" value="PÅ™ejÃt na zaÄátek oddÃlu"/> + <node name="gotoSectionEnd" value="PÅ™ejÃt na konec oddÃlu"/> + <node name="nextTOCSection" value="PÅ™ejÃt na následujÃcà záhlavÃ"/> + <node name="previousTOCSection" value="PÅ™ejÃt na pÅ™edchozà záhlavÃ"/> + <node name="pageForward" value="Posuv o stránu vpÅ™ed"/> + <node name="pageBackward" value="Posuv o stránu vzad"/> + <node name="lineForward" value="Posuv o řádek vpÅ™ed"/> + <node name="lineBackward" value="Posuv o řádek vzad"/> + <node name="undo" value="ZpÄ›t"/> + <node name="redo" value="Znovu"/> + <node name="copyToClipboard" value="KopÃrovat text do schránky"/> + <node name="openInDictionary" value="OtevÅ™Ãt vybraný text ve slovnÃku"/> + <node name="clearSelection" value="VyÄistit výbÄ›r"/> + <node name="search" value="Hledat"/> + <node name="findPrevious" value="NajÃt pÅ™edchozÃ"/> + <node name="findNext" value="NajÃt dalÅ¡Ã"/> + <node name="increaseFont" value="ZvÄ›tÅ¡it pÃsmo"/> + <node name="decreaseFont" value="ZmenÅ¡it pÃsmo"/> + <node name="toggleIndicator" value="Zobrazit indikátor"/> + <node name="toggleFullscreen" value="Celoobrazovkový mód"/> + <node name="rotate" value="SmÄ›r textu"/> + <node name="addBook" value="PÅ™idat knihu"/> + <node name="cancel" value="ZruÅ¡it"/> + <node name="quit" value="UkonÄit"/> + <node name="bookInfo" value="Informace o knize"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="UkonÄit program"/> + <node name="keyDelay" value="ZpoždÄ›nà stisku kláves"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Vždy použÃt uživatelské fonty"/> + </node> + <node name="Margins" value="Okraje"> + <node name="left" value="Levý okraj"/> + <node name="right" value="Pravý okraj"/> + <node name="top" value="Hornà okraj"/> + <node name="bottom" value="Dolnà okraj"/> + </node> + <node name="Format" value="Formát"> + <node name="optionsFor" value="Nastavenà formátu"/> + <node name="lineSpacing" value="ŘádkovánÃ"> + <node name="unchanged" value="<beze zmÄ›n>"/> + </node> + <node name="firstLineIndent" value="Odsazenà prvnà linky"/> + <node name="alignment" value="ZarovnánÃ"> + <node name="left" value="Vlevo"/> + <node name="right" value="Vpravo"/> + <node name="center" value="Na stÅ™ed"/> + <node name="justify" value="Do bloku"/> + <node name="unchanged" value="<beze zmÄ›n>"/> + </node> + <node name="spaceBefore" value="Odsazenà pÅ™ed"/> + <node name="spaceAfter" value="Odsazenà za"/> + <node name="startIndent" value="PoÄátek odsazenÃ"/> + <node name="endIndent" value="Konec odsazenÃ"/> + </node> + <node name="Styles" value="Styly"> + <node name="optionsFor" value="Nastavenà stylů"/> + <node name="fontFamily" value="Rodina fontů"> + <node name="unchanged" value="<beze zmÄ›n>"/> + </node> + <node name="fontSize" value="Velikost"/> + <node name="fontSizeDifference" value="RozdÃl velikosti"/> + <node name="bold" value="TuÄnÄ›"/> + <node name="italic" value="KurzÃva"/> + <node name="allowHyphenations" value="Povolit dÄ›lenà slov"/> + <node name="autoHyphenations" value="Automatické dÄ›lenà slov"/> + </node> + <node name="Colors" value="Barvy"> + <node name="colorFor" value="Barva"> + <node name="background" value="PozadÃ"/> + <node name="selectionBackground" value="VýbÄ›r pozadÃ"/> + <node name="text" value="Běžného textu"/> + <node name="internalLink" value="InternÃho hypertextového odkazu"/> + <node name="externalLink" value="ExternÃho hypertextového odkazu"/> + <node name="bookLink" value="Odkazu na jinou knihu"/> + <node name="highlighted" value="ZvýraznÄ›ného textu"/> + <node name="treeLines" value="Stromu"/> + <node name="indicator" value="Indikátoru"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informace o knize"/> + <node name="tab"> + <node name="Common" value="Základnà informace"> + <node name="file" value="Soubor"/> + <node name="title" value="Název"/> + <node name="language" value="Jazyk"/> + <node name="encodingSet" value="Typ znakové sady"/> + <node name="encoding" value="KódovánÃ"/> + </node> + <node name="Authors" value="AutoÅ™i"> + <node name="authorDisplayName" value="Jméno autora"/> + </node> + <node name="Series" value="Série"> + <node name="seriesTitle" value="Název série"/> + <node name="bookIndex" value="ÄŒÃslo knihy"/> + </node> + <node name="Tags" value="Kategorie"> + <node name="tags" value="Jméno znaÄky"/> + </node> + <node name="Text" value="Text"> + <node name="breakType" value="Nový odstavec po"/> + <node name="ignoreIndent" value="Ignorovat rozestup menšà než"/> + <node name="buildTOC" value="VytvoÅ™it hlaviÄku"/> + <node name="emptyLines" value="VyÄistit řádky pÅ™ed novou sekcÃ"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Nový odstavec po"/> + <node name="ignoreIndent" value="Ignorovat rozestup menšà než"/> + <node name="buildTOC" value="Sestavit hlaviÄku"/> + <node name="emptyLines" value="VyÄistit řádky pÅ™ed novou sekcÃ"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informace o autorovi"/> + <node name="name" value="Jméno autora"/> + <node name="sortKey" value="TÅ™Ãdicà klÃÄ autora"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - PÅ™idat knihu do knihovny"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Hledat text"/> + <node name="text" value="Text"/> + <node name="ignoreCase" value="&Ignorovat registr knih"/> + <node name="wholeText" value="&V celém textu"/> + <node name="backward" value="&ZpÄ›t"/> + <node name="currentSection" value="&Pouze tento oddÃl"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="SÃÅ¥ové hledánÃ"/> + <node name="titleAndSeries" value="Název knihy / Série"/> + <node name="author" value="Autor"/> + <node name="category" value="Kategorie"/> + <node name="description" value="Popis"/> + <node name="annotation" value="Výsledky hledánà pro: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="JÃt na stránku"/> + <node name="pageNumber" value="JÃt na stránku ÄÃslo"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Editovat kategorii"/> + <node name="name" value="Jméno"/> + <node name="includeSubtags" value="VÄetnÄ› podkategoriÃ"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="KopÃrovat kategorii"/> + <node name="name" value="Jméno"/> + <node name="includeSubtags" value="VÄetnÄ› podkategoriÃ"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Odstranit knihu"/> + <node name="message" value="Odstranit knihu “%s†u knihovny?"/> + <node name="deleteFile" value="Jste jsi opravdu jisti trvalým odst radÄ›nÃm souboru “%s†z disku?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Odstranit kategorii"/> + <node name="message" value="Odstranit kategorii “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Chyba"/> + <node name="message" value="Nemohu't otevÅ™Ãt: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Error"/> + <node name="message" value="Nemohu ostrani't soubor %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Chyba"/> + <node name="message" value="Omlouváme se, soubor nápovÄ›dy nenalezen"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Vyprázdnit seznam knihovny"/> + <node name="authenticationFailed" value="PÅ™ihlášenà selhalo"/> + <node name="internalError" value="Chyba serveru"/> + <node name="purchaseNotEnoughMoney" value="Nedostatek penÄ›z"/> + <node name="purchaseMissingBook" value="ChybÄ›jÃcà kniha"/> + <node name="purchaseAlreadyPurchased" value="Zaplaceno"/> + <node name="bookNotPurchased" value="NedoÅ¡lo k zaplacenà knihy"/> + <node name="downloadLimitExceeded" value="PÅ™ekroÄen limit pro stahovánÃ"/> + <node name="unsupportedOperation" value="Nepodporovaná operace"/> + <node name="loginAlreadyTaken" value="Jméno uživatele je obsazeno"/> + <node name="loginNotSpecified" value="ProsÃm zadejte jméno uživatele"/> + <node name="passwordNotSpecified" value="Zadejte prosÃm neprázdné heslo"/> + <node name="emailNotSpecified" value="Zadejte prosÃm e-mailovou adresu"/> + <node name="invalidEMail" value="Nesprávná adresa e-mailu"/> + <node name="tooManyRegistrations" value="PÅ™ÃliÅ¡ mnoho registracà pro IP; zkuste to za nÄ›kolik minut znovu"/> + <node name="noUserEmail" value="Uživatel nebyl registrován s udanou e-mailovou adresou"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Chyba pÅ™i stahovánÃ"/> + <node name="message" value="Knihu teÄ nenà možné stáhnout"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="ZavádÃm knihu. ÄŒekejte prosÃm..."/> + <node name="loadingBookList" value="ZavádÃm seznam knih. ÄŒekejte prosÃm..."/> + <node name="migrate" value="Probihá upgrade na novou verzi. ÄŒekejte prosÃm..."/> + <node name="downloadBookList" value="ProbÃhá stahovánà seznamu knih. ÄŒekejte prosÃm..."/> + <node name="downloadBook" value="Stahovánà knihy. ÄŒekejte prosÃm..."/> + <node name="downloadImages" value="Stahuji obrázky. ÄŒekelte prosÃm..."/> + <node name="authentication" value="PÅ™ihlaÅ¡ovánà probÃhá. ÄŒekejte prosÃm..."/> + <node name="purchaseBook" value="Platba knihy probÃhá. ÄŒekejte prosÃm..."/> + <node name="initializeAuthenticationManager" value="Stahovánà informace o úÄtu. ÄŒekejte prosÃm..."/> + <node name="loadSubCatalog" value="Importuji katalog. ÄŒekejte prosÃm..."/> + <node name="registerUser" value="Registrace nového úÄtu. ÄŒekejte prosÃm..."/> + <node name="passwordRecovery" value="Obnovenà hesla. ÄŒekejte prosÃm..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Zaplatit knihu"/> + <node name="message" value="Chcete zaplatit “%s†tuto knihu?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="PÅ™ihlášenÃ"/> + <node name="login" value="Jméno"/> + <node name="password" value="Heslo"/> + <node name="skipIP" value="Nenà možné se pÅ™ipoji't k ip-addrese"/> + <node name="loginIsEmpty" value="Prázdné pÅ™ihlaÅ¡ovacà informace"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informace"/> + <node name="message" value="Prázdný katalog."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Zakázat katalog"/> + <node name="message" value="SouhlasÃte se zákazem “%s†katalogu? Můžete ho povolit v nastavenÃch programu, na záložce “Hledánà v sÃtiâ€."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Odstranit knihu"/> + <node name="message" value="SouhlasÃte s trvalým odstranÄ›nÃm “%s†k knihy z disku?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Registrace uživatele"/> + <node name="login" value="Jméno"/> + <node name="password" value="Heslo"/> + <node name="confirmPassword" value="Potvrzenà hesla"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="Heslo a jeho potvrzenà musà být shodné."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Obnovit heslo"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Heslo obnoveno"/> + <node name="message" value="Zprávy k následujÃcÃm instrukcÃm jsou odeslány na %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Chyba stahovánÃ"/> + <node name="message" value="N'emohu otevÅ™Ãt stažený soubor %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Výchozà text"/> + <node name="Regular Paragraph" value="Běžný odstavec"/> + <node name="Title" value="Název"/> + <node name="Section Title" value="Název sekce"/> + <node name="Poem Title" value="Název básnÄ›"/> + <node name="Subtitle" value="Podtitul"/> + <node name="Annotation" value="Anotace"/> + <node name="Epigraph" value="Motto"/> + <node name="Stanza" value="Sloka"/> + <node name="Verse" value="VerÅ¡"/> + <node name="Preformatted text" value="PÅ™edformátovaný text"/> + <node name="Image" value="Obrázek"/> + <node name="Cite" value="Citát"/> + <node name="Author" value="Autor"/> + <node name="Date" value="Datum"/> + <node name="Internal Hyperlink" value="Internà hypertextový odkaz"/> + <node name="Footnote" value="Poznámka pod Äarou"/> + <node name="Emphasis" value="ZdůraznÄ›nÃ"/> + <node name="Strong" value="TuÄnÄ›"/> + <node name="Subscript" value="Index"/> + <node name="Superscript" value="Hornà index"/> + <node name="Code" value="Programový kód"/> + <node name="StrikeThrough" value="PÅ™eÅ¡krtnuté"/> + <node name="Contents Table" value="Obsah tabulky"/> + <node name="Library Entry" value="Záznam do knihovny"/> + <node name="Recent Book List" value="Seznam nedávných knih"/> + <node name="Italic" value="KurzÃva"/> + <node name="Bold" value="TuÄnÄ›"/> + <node name="Definition" value="Popis"/> + <node name="Definition Description" value="Popis definice"/> + <node name="Header 1" value="HlaviÄka 1"/> + <node name="Header 2" value="HlaviÄka 2"/> + <node name="Header 3" value="HlaviÄka 3"/> + <node name="Header 4" value="HlaviÄka 4"/> + <node name="Header 5" value="HlaviÄka 5"/> + <node name="Header 6" value="HlaviÄka 6"/> + <node name="External Hyperlink" value="Externà hypertextový odkaz"/> + <node name="Link to Another Book" value="Odkaz na jinou knihu"/> + </node> + <node name="external"> + <node name="browser" value="ProhlÞeÄ"/> + <node name="defaultBrowser" value="Základnà prohlÞeÄ"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Neznámá chyba"/> + <node name="unsupportedCompressionMethod" value="Nepodporovaná metoda komprese"/> + <node name="encryptedFile" value="Soubor chránÄ›ný DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="SÃÅ¥ová knihovna"/> + </node> + <node name="library"> + <node name="caption" value="Knihovna"/> + </node> +</resources> diff --git a/reader/data/resources/de.xml b/reader/data/resources/de.xml new file mode 100644 index 0000000..7245ccd --- /dev/null +++ b/reader/data/resources/de.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- German TDE-Ebook-Reader resources, by Rainer Paul --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Bücher anzeigen"/> + <node name="collapseTree" value="Bücher verbergen"/> + <node name="edit" value="Informationen ändern"/> + <node name="unknownAuthor" value="Unbekannter Autor"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Bücher anzeigen"/> + <node name="collapseTree" value="Bücher verbergen"/> + <node name="edit" value="Markierung ändern"/> + <node name="clone" value="Markierung klonen"/> + <node name="delete" value="Markierung entfernen"/> + <node name="noTags" value="Bücher ohne Markierungen"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Bücher anzeigen"/> + <node name="collapseTree" value="Bücher verbergen"/> + </node> + <node name="bookNode"> + <node name="read" value="Buch lesen"/> + <node name="edit" value="Informationen ändern"/> + <node name="delete" value="Buch entfernen"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Nach Autoren gruppiert"> + <node name="summary" value="Bücher nach Autoren auswählen"/> + </node> + <node name="byTitle" value="Nach Titel sortiert"> + <node name="summary" value="Bücher nach Titel sortiert"/> + </node> + <node name="byDate" value="Nach Datum sortiert"> + <node name="summary" value="Bücher nach Kaufdatum sortiert"/> + </node> + <node name="bySeries" value="Nach Serien gruppiert"> + <node name="summary" value="Bücher nach Buchserie auswählen"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="erweitern"/> + <node name="collapseTree" value="reduzieren"/> + <node name="reload" value="neu laden"/> + <node name="openInBrowser" value="im Browser öffnen"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Katalog öffnen"/> + <node name="collapseTree" value="Katalog schließen"/> + <node name="login" value="Anmelden"/> + <node name="logout" value="Abmelden (%s)"/> + <node name="reload" value="Neu laden"/> + <node name="dontShow" value="Diesen Katalog nicht anzeigen"/> + <node name="topupAccount" value="Account aufladen (derzeit: %s)"/> + <node name="register" value="Anmelden"/> + <node name="passwordRecovery" value="Passwort wiederherstellen"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Suchergebnisse"/> + <node name="expandTree" value="Ergebnisse anzeigen"/> + <node name="collapseTree" value="Ergebnisse verbergen"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Bücher anzeigen"/> + <node name="collapseTree" value="Bücher verbergen"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Bücher anzeigen"/> + <node name="collapseTree" value="Bücher verbergen"/> + </node> + <node name="bookNode"> + <node name="read" value="Lokale Kopie lesen"/> + <node name="delete" value="Lokale Kopie löschen"/> + <node name="download" value="Download"/> + <node name="readDemo" value="Demo lesen"/> + <node name="downloadDemo" value="Download Demo"/> + <node name="demo" value="demo"/> + <node name="buy" value="Kaufen (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="E-Book Info..."/> + <node name="toc" value="Inhaltsverzeichnis"/> + <node name="showLibrary" value="Bibliothek öffnen"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Bibliothek"> + <node name="showLibrary" value="Öffnen"/> + <node name="previousBook" value="Vorheriges E-Book"/> + <node name="showRecent" value="Aktuell"/> + <node name="addBook" value="E-Book hinzufügen..."/> + <node name="showHelp" value="Über TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Gehe zur ersten Seite des Dokuments"/> + <node name="gotoPageNumber" value="Gehe zur Seite..."/> + <node name="gotoSectionStart" value="Gehe zum Textanfang"/> + <node name="gotoSectionEnd" value="Gehe zum Textende"/> + <node name="nextTOCSection" value="Gehe zum nächsten Kapitel"/> + <node name="previousTOCSection" value="Gehe zum vorherigen Kapitel"/> + <node name="navigate" value="Navigation"> + <node name="gotoHome" value="Gehe zur ersten Seite des Dokuments"/> + <node name="gotoPageNumber" value="Gehe zur Seite..."/> + <node name="gotoSectionStart" value="Gehe zum Textanfang"/> + <node name="gotoSectionEnd" value="Gehe zum Textende"/> + <node name="nextTOCSection" value="Gehe zum nächsten Kapitel"/> + <node name="previousTOCSection" value="Gehe zum vorherigen Kapitel"/> + <node name="undo" value="Gehe zurück"/> + <node name="redo" value="Gehe vorwärts"/> + </node> + <node name="selection" value="Auswahl"> + <node name="copyToClipboard" value="In die Zwischenablage kopieren"/> + <node name="openInDictionary" value="Im Wörterbuch öffnen"/> + <node name="clearSelection" value="Löschen"/> + </node> + <node name="search" value="Suche"> + <node name="search" value="Text suchen..."/> + <node name="findNext" value="Weitersuchen"/> + <node name="findPrevious" value="Vorherige suchen"/> + </node> + <node name="view" value="Ansicht"> + <node name="rotate" value="Bild drehen"/> + <node name="toggleFullscreen" value="Vollbild"/> + <node name="toggleIndicator" value="Bildlauf umschalten"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Schließen"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="Lese-Modus anzeigen"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Baumansicht der Bibliothek anzeigen"/> + <node name="popup" value="Aktuelle Liste der E-Books anzeigen"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Aktuelle Liste der E-Books anzeigen"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="E-Books nach Autoren ordnen"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="E-Books nach Schlagwörtern ordnen"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Datei zur Bibliothek hinzufügen"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="In Netzwerk-Bibliotheken suchen"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Suche im Netzwerk"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Erweiterte Suche im Netzwerk"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Gehe zum Textanfang"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="Gehe zurück"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Gehe vorwärts"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="Gehe zur Seite"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Inhaltsverzeichnis"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Text-Suche"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Weitersuchen"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Vorherige suchen"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Text drehen"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="Über TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="E-Book Infos anzeigen"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Los!"/> + <node name="thisOnly" value="Nur diese"/> + <node name="withSubtags" value="Mit Unterpunkten"/> + <node name="removeLink" value="Aus Bibliothek entfernen"/> + <node name="removeFile" value="Von Festplatte entfernen"/> + <node name="yesToAll" value="Ja für &alle"/> + <node name="buy" value="&Kaufen"/> + <node name="buyAndDownload" value="Kaufen und &Download"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Bibliothek"> + <node name="bookPath" value="E-Book Verzeichnis"/> + <node name="lookInSubdirectories" value="E-Books in Unterverzeichnissen suchen"/> + <node name="collectBooksWithoutMetaInfo" value="E-Books ohne Meta-Infos sammeln"/> + <node name="downloadDirectory" value="Verzeichnis für heruntergeladene E-Books"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Suche im Netzwerk"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Proxy benutzen"/> + <node name="proxyHost" value="Proxy Host"/> + <node name="proxyPort" value="Proxy Port"/> + <node name="timeout" value="Network Operations Timeout, Sekunden"/> + </node> + <node name="Web" value="Internet"> + <node name="enableIntegration" value="Externe Links in %s öffnen"/> + <node name="defaultText" value="Externe Links in Browser öffnen"/> + <node name="choice" value="Browser benutzen"/> + <node name="command" value="Befehl zum Ausführen"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Sprache"> + <node name="autoDetect" value="Automatisch Sprache und Codierung erkennen"/> + <node name="defaultLanguage" value="Standardsprache"/> + <node name="defaultEncodingSet" value="Standard-Codierungs-Set"/> + <node name="defaultEncoding" value="Standard Codierung"/> + <node name="useWindows1252Hack" value="Windows-1252 statt ISO-8859-1 benutzen"/> + </node> + <node name="Config" value="Konfiguration"> + <node name="autoSave" value="Verlauf automatisch sichern"/> + <node name="timeout" value="Abstand zwischen Sicherungen, in Sekunden"/> + </node> + <node name="Dictionary" value="Wörterbuch"> + <node name="enableIntegration" value="Integration mit %s einschalten"/> + <node name="defaultText" value="Integration mit Wörterbuch einschalten"/> + <node name="choice" value="Integriert mit"/> + <node name="singleClickOpen" value="Mit einfachem Klick öffnen"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Ausführen beim Loslassen nicht beim Tastendrücken"/> + <node name="minStylusPressure" value="Minimaler Druck des Eingabestifts"/> + <node name="maxStylusPressure" value="Maximaler Druck des Eingabestifts"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Bildlauf"> + <node name="keyScrollDelay" value="Verzögerung beim Tasten-Bildlauf, ms"/> + <node name="keyLinesToScroll" value="Anzahl Zeilen beim Zeilen-Bildlauf"/> + <node name="keyLinesToKeep" value="Anzahl bleibender Zeilen beim Seiten-Bildlauf"/> + <node name="enableTapScrolling" value="Tippen-Bildlauf einschalten"/> + <node name="fingerOnly" value="Bildlauf nur mit Fingertippen"/> + </node> + <node name="Selection" value="Auswahl"> + <node name="enableSelection" value="Textauswahl einschalten"/> + </node> + <node name="Indicator" value="Bildlauf"> + <node name="type" value="Zeigen als"> + <node name="osScrollbar" value="OS Scrollbar"/> + <node name="fbIndicator" value="Old Style Indikator"/> + <node name="none" value="Keinen anzeigen"/> + </node> + <node name="height" value="Höhe des Bildlaufs"/> + <node name="offset" value="Abstand zum Text"/> + <node name="pageNumber" value="Position als Zahl anzeigen"/> + <node name="time" value="Zeit anzeigen"/> + <node name="fontSize" value="Schriftgröße"/> + <node name="tocMarks" value="Kapitel-Markierungen anzeigen"/> + <node name="navigation" value="Navigation einschalten"/> + </node> + <node name="Rotation" value="Rotation"> + <node name="direction" value="Rotationstyp"> + <node name="disabled" value="abgeschaltet"/> + <node name="clockwise" value="90 Grad im Uhrzeigersinn"/> + <node name="counterclockwise" value="90 Grad im Gegenuhrzeigersinn"/> + <node name="180" value="180 Grad"/> + <node name="cycle" value="alle 4 Richtungen nacheinander"/> + </node> + </node> + <node name="Keys" value="Tasten"> + <node name="grabSystemKeys" value="Systemtasten übernehmen"/> + <node name="separate" value="Tasten abhängig von der Orientierung"/> + <node name="orientation" value="Orientierung"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Keine"/> + <node name="showLibrary" value="Bibliothek zeigen"/> + <node name="showNetLibrary" value="Netzwerk Bibliothek zeigen"/> + <node name="showRecent" value="Aktuelle E-Books zeigen"/> + <node name="previousBook" value="Vorheriges E-Book zeigen"/> + <node name="toc" value="Inhaltsverzeichnis zeigen"/> + <node name="gotoHome" value="Zum Anfang gehen"/> + <node name="gotoSectionStart" value="Zum Anfang des Abschnitts gehen"/> + <node name="gotoSectionEnd" value="Zum Ende des Abschnitts gehen"/> + <node name="nextTOCSection" value="Zum nächsten Kapitel gehen"/> + <node name="previousTOCSection" value="Zum vorherigen Kapitel gehen"/> + <node name="pageForward" value="Nächste Seite anzeigen"/> + <node name="pageBackward" value="Vorherige Seite anzeigen"/> + <node name="lineForward" value="Nächste Zeile anzeigen"/> + <node name="lineBackward" value="Vorherige Zeile anzeigen"/> + <node name="undo" value="zurückgehen"/> + <node name="redo" value="vorwärts gehen"/> + <node name="copyToClipboard" value="Markierten Text in Zwischenablage kopieren"/> + <node name="openInDictionary" value="Markierten Text im Wörterbuch öffnen"/> + <node name="clearSelection" value="Auswahl löschen"/> + <node name="search" value="Suche"/> + <node name="findPrevious" value="Vorherigen suchen"/> + <node name="findNext" value="Weitersuchen"/> + <node name="increaseFont" value="Schriftgröße erhöhen"/> + <node name="decreaseFont" value="Schriftgröße verringern"/> + <node name="toggleIndicator" value="Position des Bildlaufs umschalten"/> + <node name="toggleFullscreen" value="Vollbildmodus umschalten"/> + <node name="rotate" value="Bild drehen"/> + <node name="addBook" value="E-Book hinzufügen"/> + <node name="cancel" value="Abbruch"/> + <node name="quit" value="Schließen"/> + <node name="bookInfo" value="E-Book Infos anzeigen"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Bei Abbruch Anwendung schließen"/> + <node name="keyDelay" value="Verzögerung zwischen erkannten Tastendrücken"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Immer eigene Schriftarten benützen"/> + </node> + <node name="Margins" value="Ränder"> + <node name="left" value="Linker Rand"/> + <node name="right" value="Rechter Rand"/> + <node name="top" value="Oberer Rand"/> + <node name="bottom" value="Unterer Rand"/> + </node> + <node name="Format" value="Format"> + <node name="optionsFor" value="Optionen für"/> + <node name="lineSpacing" value="Zeilenabstand"> + <node name="unchanged" value="<unverändert>"/> + </node> + <node name="firstLineIndent" value="Einzug erste Zeile"/> + <node name="alignment" value="Ausrichtung"> + <node name="left" value="Links"/> + <node name="right" value="Rechts"/> + <node name="center" value="Zentriert"/> + <node name="justify" value="Blocksatz"/> + <node name="unchanged" value="<unverändert>"/> + </node> + <node name="spaceBefore" value="Abstand vor"/> + <node name="spaceAfter" value="Abstand nach"/> + <node name="startIndent" value="Einzug erste Linie"/> + <node name="endIndent" value="Einzug letzte Linie"/> + </node> + <node name="Styles" value="Stile"> + <node name="optionsFor" value="Optionen für"/> + <node name="fontFamily" value="Familie"> + <node name="unchanged" value="<unverändert>"/> + </node> + <node name="fontSize" value="Größe"/> + <node name="fontSizeDifference" value="Größenunterschied"/> + <node name="bold" value="Fett"/> + <node name="italic" value="Kursiv"/> + <node name="allowHyphenations" value="Trennen erlaubt"/> + <node name="autoHyphenations" value="Automatisch trennen"/> + </node> + <node name="Colors" value="Farben"> + <node name="colorFor" value="Farbe für"> + <node name="background" value="Hintergrund"/> + <node name="selectionBackground" value="Hintergrund (Auswahl)"/> + <node name="text" value="Regulärer Text"/> + <node name="internalLink" value="Interner Hyperlink Text"/> + <node name="externalLink" value="Externer Hyperlink Text"/> + <node name="bookLink" value="Verweis auf ein anderes Buch"/> + <node name="highlighted" value="Hervorgehobener Text"/> + <node name="treeLines" value="Baumlinien"/> + <node name="indicator" value="Position Bildlauf"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - E-Book Info"/> + <node name="tab"> + <node name="Common" value="Allgemein"> + <node name="file" value="Datei"/> + <node name="title" value="Titel"/> + <node name="language" value="Sprache"/> + <node name="encodingSet" value="Codierung-Satz"/> + <node name="encoding" value="Codierung"/> + </node> + <node name="Authors" value="Autoren"> + <node name="authorDisplayName" value="Name des Autors"/> + </node> + <node name="Series" value="Serie"> + <node name="seriesTitle" value="Serientitel"/> + <node name="bookIndex" value="Buchnummer"/> + </node> + <node name="Tags" value="Stichwörter"> + <node name="tags" value="Stichwort"/> + </node> + <node name="Text" value="Text"> + <node name="breakType" value="Absätze umbrechen bei"/> + <node name="ignoreIndent" value="Einzüge ignorieren kleiner"/> + <node name="buildTOC" value="Inhaltsverzeichnis erstellen"/> + <node name="emptyLines" value="Leerzeilen vor neuen Abschnitten"/> + </node> + <node name="<PRE>" value="<Vorwort>"> + <node name="breakType" value="Absätze umbrechen bei"/> + <node name="ignoreIndent" value="Einzüge ignorieren kleiner"/> + <node name="buildTOC" value="Inhaltsverzeichnis erstellen"/> + <node name="emptyLines" value="Leerzeilen vor neuen Abschnitten"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader – Infos über Autor"/> + <node name="name" value="Name des Autors"/> + <node name="sortKey" value="Sortierungsindex des Autors"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - E-Book zur Bibliothek hinzufügen"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Text-Suche"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignoriere Groß-/Kleinschreibung"/> + <node name="wholeText" value="Im g&anzen Text"/> + <node name="backward" value="&Rückwärts"/> + <node name="currentSection" value="&Nur diesen Abschnitt"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Netzwerk-Suche"/> + <node name="titleAndSeries" value="Titel/Serie"/> + <node name="author" value="Autor"/> + <node name="category" value="Kategorie"/> + <node name="description" value="Beschreibung"/> + <node name="annotation" value="Suchergebnisse für: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Gehe zur Seite"/> + <node name="pageNumber" value="Gehe zur Seitennummer"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Eintrag ändern"/> + <node name="name" value="Eintrag Name"/> + <node name="includeSubtags" value="Subtags einbeziehen"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Eintrag Klonen"/> + <node name="name" value="Eintrag Name"/> + <node name="includeSubtags" value="Subtags einbeziehen"/> + </node> + <node name="removeBookBox"> + <node name="title" value="E-Book entfernen"/> + <node name="message" value="E-Book “%s†aus Bibliothek entfernen?"/> + <node name="deleteFile" value="Soll die Datei#10;“%s†wirklich von der Festplatte gelöscht werden?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Eintrag entfernen"/> + <node name="message" value="Eintrag “%s†entfernen?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Fehler"/> + <node name="message" value="Konnte %s nicht öffnen"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Fehler"/> + <node name="message" value="Kann Datei %s nicht löschen"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Fehler"/> + <node name="message" value="Hilfedatei nicht gefunden, sorry"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Leere Bibliotheksliste"/> + <node name="authenticationFailed" value="Authentifizierung nicht möglich"/> + <node name="internalError" value="Interner Server-Fehler"/> + <node name="purchaseNotEnoughMoney" value="Zu wenig Geld"/> + <node name="purchaseMissingBook" value="Fehlendes Buch"/> + <node name="purchaseAlreadyPurchased" value="Bereits gekauft"/> + <node name="bookNotPurchased" value="Buch wurde nicht gekauft"/> + <node name="downloadLimitExceeded" value="Download Limit überschritten"/> + <node name="unsupportedOperation" value="Operation wird nicht unterstützt"/> + <node name="loginAlreadyTaken" value="Benutzername wird bereits verwendet"/> + <node name="loginNotSpecified" value="Bitte Benutzername eingeben"/> + <node name="passwordNotSpecified" value="Bitte ein Passwort eingeben"/> + <node name="emailNotSpecified" value="Bitte eine Email-Adresse eingeben"/> + <node name="invalidEMail" value="Ungültige Email-Adresse"/> + <node name="tooManyRegistrations" value="Zu viele Registrierungen von Ihrer IP; bitte in einigen Minuten noch einmal probieren"/> + <node name="noUserEmail" value="Es gibt keinen registrierten Nutzer mit dieser Email-Adresse"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Fehler beim Herunterladen"/> + <node name="message" value="Kann dieses E-Book im Moment nicht herunterladen"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="E-Book wird geladen. Bitte warten..."/> + <node name="loadingBookList" value="Buchliste wird geladen. Bitte warten..."/> + <node name="migrate" value="Upgrade auf neue Version. Bitte warten..."/> + <node name="downloadBookList" value="Buchliste wird geladen. Bitte warten..."/> + <node name="downloadBook" value="E-Book wird heruntergeladen. Bitte warten..."/> + <node name="downloadImages" value="Bilder werden heruntergeladen. Bitte warten..."/> + <node name="authentication" value="Authentifizierung. Bitte warten..."/> + <node name="purchaseBook" value="Buch wird gekauft. Bitte warten..."/> + <node name="initializeAuthenticationManager" value="Account-Informationen werden geladen. Bitte warten..."/> + <node name="loadSubCatalog" value="Katalog wird geladen. Bitte warten..."/> + <node name="registerUser" value="Neuer Account wird registriert. Bitte warten..."/> + <node name="passwordRecovery" value="Passwort wird wiederhergestellt. Bitte warten..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Buchkauf"/> + <node name="message" value="Soll das Buch “%s†wirklich gekauft werden?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Authentifizierung"/> + <node name="login" value="Benutzername"/> + <node name="password" value="Passwort"/> + <node name="skipIP" value="Nicht an IP-Adresse binden"/> + <node name="loginIsEmpty" value="Benutzername sollte angegeben werden"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informationen"/> + <node name="message" value="Katalog ist leer."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Katalog deaktivieren"/> + <node name="message" value="Soll “%s†Katalog wirklich deaktiviert werden? Kann wieder aktiviert werden im Register “Suche im Netzwerk†im Optionen-Dialog."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Buch löschen"/> + <node name="message" value="Soll das Buch “%s†wirklich von der Festplatte gelöscht werden?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Registrierter Benutzer"/> + <node name="login" value="Benutzername"/> + <node name="password" value="Passwort"/> + <node name="confirmPassword" value="Passwortbestätigung"/> + <node name="email" value="Email"/> + <node name="differentPasswords" value="Passwort und Passwortbestätigung müssen identisch sein."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Passwortwiederherstellung"/> + <node name="email" value="Email"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Passwordwiederherstellung"/> + <node name="message" value="Eine Nachricht mit weiteren Anweisungen wurde an “%s†gesendet"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="DownloadFehler"/> + <node name="message" value="Heruntergeladene Datei %s#10;kann nicht geöffnet werden."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Basis"/> + <node name="Regular Paragraph" value="Regulärer Absatz"/> + <node name="Title" value="Titel"/> + <node name="Section Title" value="Abschnittstitel"/> + <node name="Poem Title" value="Titel des Gedichts"/> + <node name="Subtitle" value="Untertitel"/> + <node name="Annotation" value="Anmerkung"/> + <node name="Epigraph" value="Epigraf"/> + <node name="Stanza" value="Strophe"/> + <node name="Verse" value="Vers"/> + <node name="Preformatted text" value="Vorformatierter Text"/> + <node name="Image" value="Bild"/> + <node name="Cite" value="Zitieren"/> + <node name="Author" value="Autor"/> + <node name="Date" value="Datum"/> + <node name="Internal Hyperlink" value="Interner Hyperlink"/> + <node name="Footnote" value="Fußnote"/> + <node name="Emphasis" value="Betonung"/> + <node name="Strong" value="Stark"/> + <node name="Subscript" value="Index"/> + <node name="Superscript" value="Hochgestellt"/> + <node name="Code" value="Code"/> + <node name="StrikeThrough" value="Durchgestrichen"/> + <node name="Contents Table" value="Inhaltsverzeichnis"/> + <node name="Library Entry" value="Bibliothekseintrag"/> + <node name="Recent Book List" value="Aktuelle Buchliste"/> + <node name="Italic" value="Kursiv"/> + <node name="Bold" value="Fett"/> + <node name="Definition" value="Definition"/> + <node name="Definition Description" value="Beschreibung der Definition"/> + <node name="Header 1" value="Überschrift 1"/> + <node name="Header 2" value="Überschrift 2"/> + <node name="Header 3" value="Überschrift 3"/> + <node name="Header 4" value="Überschrift 4"/> + <node name="Header 5" value="Überschrift 5"/> + <node name="Header 6" value="Überschrift 6"/> + <node name="External Hyperlink" value="Externer Hyperlink"/> + <node name="Link to Another Book" value="Verweis auf ein anderes Buch"/> + </node> + <node name="external"> + <node name="browser" value="Browser"/> + <node name="defaultBrowser" value="Standard-Browser"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Unbekannter Fehler"/> + <node name="unsupportedCompressionMethod" value="Komprimiermethode wird nicht unterstützt"/> + <node name="encryptedFile" value="DRM-geschützte Datei"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Netzwerk-Bibliothek"/> + </node> + <node name="library"> + <node name="caption" value="Bibliothek"/> + </node> +</resources> diff --git a/reader/data/resources/en.xml b/reader/data/resources/en.xml new file mode 100644 index 0000000..4ea1887 --- /dev/null +++ b/reader/data/resources/en.xml @@ -0,0 +1,716 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Hide books"/> + <node name="edit" value="Edit information"/> + <node name="unknownAuthor" value="Unknown Author"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Hide books"/> + <node name="edit" value="Edit tag"/> + <node name="clone" value="Clone tag"/> + <node name="delete" value="Remove tag"/> + <node name="noTags" value="Books with no tags"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Hide books"/> + </node> + <node name="bookNode"> + <node name="read" value="Read book"/> + <node name="edit" value="Edit information"/> + <node name="delete" value="Remove book"/> + </node> + </node> + <node name="networkView" value="Network Library"> + <node name="byAuthor" value="By author"> + <node name="summary" value="Books sorted by author"/> + </node> + <node name="byTitle" value="By title"> + <node name="summary" value="Books sorted by title"/> + </node> + <node name="byDate" value="By date"> + <node name="summary" value="Books sorted by date of purchasing"/> + </node> + <node name="bySeries" value="By series"> + <node name="summary" value="Books sorted by series"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Expand"/> + <node name="collapseTree" value="Collapse"/> + <node name="reload" value="Reload"/> + <node name="openInBrowser" value="Open in browser"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Open catalog"/> + <node name="collapseTree" value="Close catalog"/> + <node name="login" value="Sign in"/> + <node name="logout" value="Sign out (%s)"/> + <node name="reload" value="Reload"/> + <node name="dontShow" value="Don't show this catalog"/> + <node name="topupAccount" value="Top up account (currently: %s)"/> + <node name="topupAccountUndefined" value="Top up account"/> + <node name="register" value="Sign up"/> + <node name="passwordRecovery" value="Recover password"/> + </node> + <node name="searchResultNode"> + <node name="searchfield" value="Type to search..."/> + <node name="title" value="Search results"/> + <node name="expandTree" value="Show results"/> + <node name="collapseTree" value="Hide results"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Hide books"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Hide books"/> + <node name="booksCount" value="%s books"> + <node condition="value 1" value="%s book"/> + </node> + </node> + <node name="bookNode"> + <node name="read" value="Read local copy"/> + <node name="delete" value="Delete local copy"/> + <node name="download" value="Download"/> + <node name="readDemo" value="Read sample"/> + <node name="downloadDemo" value="Download sample"/> + <node name="demo" value="sample"/> + <node name="buy" value="Buy (%s)"/> + <node name="alsoRead" value="Also read with this book"/> + <node name="sameAuthor" value="All books of %s"/> + </node> + </node> + <node name="bookInfo"> + <node name="bookInfo" value="Book Info"/> + <node name="fileInfo" value="File Info"/> + <node name="description" value="Description"/> + <node name="noDescription" value="No description available."/> + <node name="annotation" value="Annotation"/> + <node name="title" value="Title:"/> + <node name="authors" value="Authors:"> + <node condition="value 1" value="Author:"/> + </node> + <node name="series" value="Series:"/> + <node name="indexInSeries" value="Index in series:"/> + <node name="tags" value="Tags:"> + <node condition="value 1" value="Tag:"/> + </node> + <node name="language" value="Language:"/> + <node name="name" value="Name:"/> + <node name="type" value="Type:"/> + <node name="size" value="Size:"/> + <node name="time" value="Last modified:"/> + <node name="sizeInBytes" value="%s bytes"> + <node condition="value 1" value="%s byte"/> + </node> + <node name="sizeInKiloBytes" value="%s kB"/> + <node name="catalog" value="Catalog:"/> + <node name="extraLinks" value="Related links"/> + </node> + <node name="menu"> + <node name="bookInfo" value="Book Info..."/> + <node name="toc" value="Table of Contents"/> + <node name="showLibrary" value="Open library"/> + <node name="showNetLibrary" value="Network library"/> + <node name="addBook" value="Open file..."/> + <node name="showRecent" value="Recent books"/> + <node name="library" value="Library"> + <node name="showLibrary" value="Open"/> + <node name="previousBook" value="Previous Book"/> + <node name="showRecent" value="Recent"/> + <node name="addBook" value="Add Book..."/> + <node name="showHelp" value="About TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Go to Start of Document"/> + <node name="gotoPageNumber" value="Go to Page..."/> + <node name="gotoSectionStart" value="Go to Start of Text Section"/> + <node name="gotoSectionEnd" value="Go to End of Text Section"/> + <node name="nextTOCSection" value="Go to Next TOC Item"/> + <node name="previousTOCSection" value="Go to Previous TOC Item"/> + <node name="navigate" value="Navigate"> + <node name="gotoHome" value="Go to Start of Document"/> + <node name="gotoPageNumber" value="Go to Page..."/> + <node name="gotoSectionStart" value="Go to Start of Text Section"/> + <node name="gotoSectionEnd" value="Go to End of Text Section"/> + <node name="nextTOCSection" value="Go to Next TOC Item"/> + <node name="previousTOCSection" value="Go to Previous TOC Item"/> + <node name="undo" value="Go Back"/> + <node name="redo" value="Go Forward"/> + </node> + <node name="selection" value="Selection"> + <node name="copyToClipboard" value="Copy to Clipboard"/> + <node name="openInDictionary" value="Open in Dictionary"/> + <node name="clearSelection" value="Clear"/> + </node> + <node name="search" value="Find"> + <node name="search" value="Find Text..."/> + <node name="findNext" value="Find Next"/> + <node name="findPrevious" value="Find Previous"/> + </node> + <node name="view" value="View"> + <node name="rotate" value="Rotate Screen"/> + <node name="toggleFullscreen" value="Full Screen"/> + <node name="toggleIndicator" value="Toggle Indicator"/> + </node> + <node name="preferences" value="Last Preferences Dialog..."/> + <node name="quit" value="Close"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Read Book"/> + <node name="tooltip" value="Show Reading Mode"/> + </node> + <node name="showLibrary"> + <node name="label" value="Library"/> + <node name="tooltip" value="Show Library Tree"/> + <node name="popup" value="Show Recent Books List"/> + </node> + <node name="showRecent"> + <node name="label" value="Recent Books"/> + <node name="tooltip" value="Show Recent Books List"/> + </node> + <node name="byAuthor"> + <node name="label" value="By Author"/> + <node name="tooltip" value="Organize Books by Author"/> + </node> + <node name="byTag"> + <node name="label" value="By Tag"/> + <node name="tooltip" value="Organize Books by Tag"/> + </node> + <node name="addBook"> + <node name="label" value="Add File"/> + <node name="tooltip" value="Add File to Library"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Network"/> + <node name="tooltip" value="Search in Network Libraries"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Simple Search"/> + <node name="tooltip" value="Network Search"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Search"/> + <node name="tooltip" value="Advanced Network Search"/> + </node> + <node name="gotoHome"> + <node name="label" value="Go to Start"/> + <node name="tooltip" value="Go to Start of Text"/> + </node> + <node name="undo"> + <node name="label" value="Go Back"/> + <node name="tooltip" value="Go Back"/> + </node> + <node name="redo"> + <node name="label" value="Go Forward"/> + <node name="tooltip" value="Go Forward"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Go to Page"/> + <node name="tooltip" value="Go to Page"/> + </node> + <node name="toc"> + <node name="label" value="TOC"/> + <node name="tooltip" value="Table of Contents"/> + </node> + <node name="search"> + <node name="label" value="Search"/> + <node name="tooltip" value="Text Search"/> + </node> + <node name="findNext"> + <node name="label" value="Next"/> + <node name="tooltip" value="Find Next"/> + </node> + <node name="findPrevious"> + <node name="label" value="Previous"/> + <node name="tooltip" value="Find Previous"/> + </node> + <node name="rotate"> + <node name="label" value="Rotate"/> + <node name="tooltip" value="Rotate Text"/> + </node> + <node name="showHelp"> + <node name="label" value="About"/> + <node name="tooltip" value="About TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Filter"/> + <node name="tooltip" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" value="Last Preferences Dialog"/> + <node name="tooltip" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Book Info"/> + <node name="tooltip" value="Show Book Info Dialog"/> + </node> + <node name="libraryOptions"> + <node name="label" value="Library Preferences"/> + <node name="tooltip" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" value="Network Preferences"/> + <node name="tooltip" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" value="System Preferences"/> + <node name="tooltip" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" value="Reading Preferences"/> + <node name="tooltip" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" value="Look & Feel Preferences"/> + <node name="tooltip" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Go!"/> + <node name="thisOnly" value="This only"/> + <node name="withSubtags" value="With subtags"/> + <node name="removeLink" value="Remove from library"/> + <node name="removeFile" value="Remove from disk"/> + <node name="yesToAll" value="Yes to &all"/> + <node name="buy" value="&Buy"/> + <node name="buyAndDownload" value="Buy and &download"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Library"> + <node name="bookPath" value="Book Path"/> + <node name="lookInSubdirectories" value="Look for Books in Subdirectories"/> + <node name="collectBooksWithoutMetaInfo" value="Collect Books without MetaInfo"/> + <node name="downloadDirectory" value="Directory for Downloaded Books"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Network Library"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Use Proxy"/> + <node name="proxyHost" value="Proxy Host"/> + <node name="proxyPort" value="Proxy Port"/> + <node name="timeout" value="Network Operations Timeout, seconds"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Open External Links in %s"/> + <node name="defaultText" value="Open External Links in Browser"/> + <node name="choice" value="Use Browser"/> + <node name="command" value="Command to Execute"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Language"> + <node name="autoDetect" value="Automatically Detect Language and Encoding"/> + <node name="defaultLanguage" value="Default Language"/> + <node name="defaultEncodingSet" value="Default Encoding Set"/> + <node name="defaultEncoding" value="Default Encoding"/> + <node name="useWindows1252Hack" value="Use windows-1252 instead of iso-8859-1"/> + </node> + <node name="Config" value="Config"> + <node name="autoSave" value="Save State Automatically"/> + <node name="timeout" value="Timeout between Savings, seconds"/> + </node> + <node name="Dictionary" value="Dictionary"> + <node name="enableIntegration" value="Enable Integration with %s"/> + <node name="defaultText" value="Enable Integration with Dictionary"/> + <node name="choice" value="Integrate with"/> + <node name="singleClickOpen" value="Open by Single Click"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Action on Key Release, not on Key Press"/> + <node name="minStylusPressure" value="Minimal Stylus Pressure"/> + <node name="maxStylusPressure" value="Maximal Stylus Pressure"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Scrolling"> + <node name="keyScrollDelay" value="Delay between Key Scrollings, msecs"/> + <node name="keyLinesToScroll" value="Lines to Scroll per Line Scrolling"/> + <node name="keyLinesToKeep" value="Lines to Keep per Page Scrolling"/> + <node name="enableTapScrolling" value="Enable Tap Scrolling"/> + <node name="fingerOnly" value="Scroll on Finger Tap Only"/> + </node> + <node name="Selection" value="Selection"> + <node name="enableSelection" value="Enable Text Selection"/> + </node> + <node name="Indicator" value="Indicator"> + <node name="type" value="Show as"> + <node name="osScrollbar" value="OS Scrollbar"/> + <node name="fbIndicator" value="Old Style Indicator"/> + <node name="none" value="Don't Show"/> + </node> + <node name="height" value="Indicator Height"/> + <node name="offset" value="Offset from Text"/> + <node name="pageNumber" value="Show Position as Numbers"/> + <node name="time" value="Show Time"/> + <node name="fontSize" value="Font Size"/> + <node name="tocMarks" value="Show TOC Marks"/> + <node name="navigation" value="Enable Navigation"/> + </node> + <node name="Rotation" value="Rotation"> + <node name="direction" value="Rotation Type"> + <node name="disabled" value="Disabled"/> + <node name="clockwise" value="90 Degrees Clockwise"/> + <node name="counterclockwise" value="90 Degrees Counterclockwise"/> + <node name="180" value="180 Degrees"/> + <node name="cycle" value="Cycle Through All 4 Directions"/> + </node> + </node> + <node name="Keys" value="Keys"> + <node name="grabSystemKeys" value="Grab System Keys"/> + <node name="separate" value="Keybindings Depend on Orientation"/> + <node name="orientation" value="Orientation"> + <node name="degrees0" value="0 Degrees"/> + <node name="degrees90ccw" value="90 Degrees Counterclockwise"/> + <node name="degrees180" value="180 Degrees"/> + <node name="degrees90cw" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="None"/> + <node name="showLibrary" value="Show library"/> + <node name="showNetLibrary" value="Show network library"/> + <node name="showRecent" value="Show recent books"/> + <node name="previousBook" value="Open previous book"/> + <node name="toc" value="Show table of contents"/> + <node name="gotoHome" value="Go to home"/> + <node name="gotoSectionStart" value="Go to start of section"/> + <node name="gotoSectionEnd" value="Go to end of section"/> + <node name="nextTOCSection" value="Go to next TOC section"/> + <node name="previousTOCSection" value="Go to previous TOC section"/> + <node name="pageForward" value="Scroll page forward"/> + <node name="pageBackward" value="Scroll page backward"/> + <node name="lineForward" value="Scroll line forward"/> + <node name="lineBackward" value="Scroll line backward"/> + <node name="undo" value="Undo"/> + <node name="redo" value="Redo"/> + <node name="copyToClipboard" value="Copy selected text to clipboard"/> + <node name="openInDictionary" value="Open selected text in dictionary"/> + <node name="clearSelection" value="Clear selection"/> + <node name="search" value="Search"/> + <node name="findPrevious" value="Find previous"/> + <node name="findNext" value="Find next"/> + <node name="increaseFont" value="Increase font size"/> + <node name="decreaseFont" value="Decrease font size"/> + <node name="toggleIndicator" value="Toggle position indicator"/> + <node name="toggleFullscreen" value="Toggle fullscreen mode"/> + <node name="rotate" value="Rotate screen"/> + <node name="addBook" value="Add book"/> + <node name="cancel" value="Cancel"/> + <node name="quit" value="Quit"/> + <node name="bookInfo" value="Show book info dialog"/> + <node name="preferences" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Quit Application on Cancel"/> + <node name="keyDelay" value="Delay Between Accepted Key Pressings"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Always Use My Own Fonts"/> + </node> + <node name="Margins" value="Margins"> + <node name="left" value="Left Margin"/> + <node name="right" value="Right Margin"/> + <node name="top" value="Top Margin"/> + <node name="bottom" value="Bottom Margin"/> + </node> + <node name="Format" value="Format"> + <node name="optionsFor" value="Options for"/> + <node name="lineSpacing" value="Line Spacing"> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="firstLineIndent" value="First Line Indent"/> + <node name="alignment" value="Alignment"> + <node name="left" value="Left"/> + <node name="right" value="Right"/> + <node name="center" value="Center"/> + <node name="justify" value="Justify"/> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="spaceBefore" value="Space Before"/> + <node name="spaceAfter" value="Space After"/> + <node name="startIndent" value="Line Start Indent"/> + <node name="endIndent" value="Line End Indent"/> + </node> + <node name="Styles" value="Styles"> + <node name="optionsFor" value="Options for"/> + <node name="fontFamily" value="Family"> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="fontSize" value="Size"/> + <node name="fontSizeDifference" value="Size Difference"/> + <node name="bold" value="Bold"/> + <node name="italic" value="Italic"/> + <node name="allowHyphenations" value="Allow Hyphenations"/> + <node name="autoHyphenations" value="Auto Hyphenations"/> + </node> + <node name="Colors" value="Colors"> + <node name="colorFor" value="Color for"> + <node name="background" value="Background"/> + <node name="selectionBackground" value="Selection Background"/> + <node name="text" value="Regular Text"/> + <node name="internalLink" value="Internal Hyperlink Text"/> + <node name="externalLink" value="External Hyperlink Text"/> + <node name="bookLink" value="Link to Another Book"/> + <node name="highlighted" value="Highlighted Text"/> + <node name="treeLines" value="Tree Lines"/> + <node name="indicator" value="Position Indicator"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Book Info"/> + <node name="tab"> + <node name="Common" value="Common"> + <node name="file" value="File"/> + <node name="title" value="Title"/> + <node name="language" value="Language"/> + <node name="encodingSet" value="Encoding Set"/> + <node name="encoding" value="Encoding"/> + </node> + <node name="Authors" value="Authors"> + <node name="authorDisplayName" value="Author Name"/> + </node> + <node name="Series" value="Series"> + <node name="seriesTitle" value="Series Title"/> + <node name="bookIndex" value="Book Index"/> + </node> + <node name="Tags" value="Tags"> + <node name="tags" value="Tag Name"/> + </node> + <node name="Text" value="Text"> + <node name="breakType" value="Break Paragraph at"/> + <node name="ignoreIndent" value="Ignore Indent Less than"/> + <node name="buildTOC" value="Build Table of Contents"/> + <node name="emptyLines" value="Empty Lines Before New Section"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Break Paragraph at"/> + <node name="ignoreIndent" value="Ignore Indent Less than"/> + <node name="buildTOC" value="Build Table of Contents"/> + <node name="emptyLines" value="Empty Lines Before New Section"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Author Info"/> + <node name="name" value="Author Name"/> + <node name="sortKey" value="Author Sort Key"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Add Book to the Library"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Text Search"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignore case"/> + <node name="wholeText" value="In w&hole text"/> + <node name="backward" value="&Backward"/> + <node name="currentSection" value="&This section only"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Network Search"/> + <node name="titleAndSeries" value="Title/Series"/> + <node name="author" value="Author"/> + <node name="category" value="Category"/> + <node name="description" value="Description"/> + <node name="annotation" value="Search results for: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Go To Page"/> + <node name="pageNumber" value="Go to Page Number"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Edit Tag"/> + <node name="name" value="Tag Name"/> + <node name="includeSubtags" value="Include Subtags"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Clone Tag"/> + <node name="name" value="Tag Name"/> + <node name="includeSubtags" value="Include Subtags"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Remove Book"/> + <node name="message" value="Remove Book “%s†from the Library?"/> + <node name="deleteFile" value="Are you sure you want to remove file “%s†from the disk?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Remove Tag"/> + <node name="message" value="Remove Tag “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Error"/> + <node name="message" value="Couldn't open: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Error"/> + <node name="message" value="Couldn't remove file %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Error"/> + <node name="message" value="Help file not found, sorry"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Empty libraries list"/> + <node name="authenticationFailed" value="Authentication failed"/> + <node name="internalError" value="Internal server error"/> + <node name="purchaseNotEnoughMoney" value="Not enough money"/> + <node name="purchaseMissingBook" value="Missing book"/> + <node name="purchaseAlreadyPurchased" value="Already purchased"/> + <node name="bookNotPurchased" value="Book was not purchased"/> + <node name="downloadLimitExceeded" value="Download limit exceeded"/> + <node name="unsupportedOperation" value="Unsupported operation"/> + <node name="loginAlreadyTaken" value="Username is already in use"/> + <node name="loginNotSpecified" value="Please, enter a username"/> + <node name="passwordNotSpecified" value="Please, enter a non-empty password"/> + <node name="emailNotSpecified" value="Please, enter an e-mail address"/> + <node name="invalidEMail" value="Invalid e-mail address"/> + <node name="tooManyRegistrations" value="Too many registrations from your IP; try again in a few minutes"/> + <node name="noUserEmail" value="No user was registered with specified e-mail address"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed"/> + </node> + <node name="downloadError"> + <node name="title" value="Error while downloading"/> + <node name="message" value="Can't download this book at the moment"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Loading book. Please, wait..."/> + <node name="loadingBookList" value="Loading library. Please, wait..."/> + <node name="migrate" value="Upgrading to the new version. Please, wait..."/> + <node name="downloadBookList" value="Downloading book list. Please, wait..."/> + <node name="downloadBook" value="Downloading book. Please, wait..."/> + <node name="downloadImages" value="Downloading images. Please, wait..."/> + <node name="authentication" value="Authentication. Please, wait..."/> + <node name="purchaseBook" value="Purchase book. Please, wait..."/> + <node name="initializeAuthenticationManager" value="Downloading account information. Please, wait..."/> + <node name="loadSubCatalog" value="Loading catalog. Please, wait..."/> + <node name="registerUser" value="Registering new account. Please, wait..."/> + <node name="passwordRecovery" value="Recovering password. Please, wait..."/> + <node name="authenticationCheck" value="Account validation. Please, wait..."/> + <node name="signOut" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..."/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Purchase book"/> + <node name="message" value="Are you sure you want to buy “%s†book?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Authentication"/> + <node name="login" value="Username"/> + <node name="password" value="Password"/> + <node name="skipIP" value="Don't bound to ip-address"/> + <node name="loginIsEmpty" value="Username should be non-empty"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Information"/> + <node name="message" value="Catalog is empty."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Disable catalog"/> + <node name="message" value="Are you sure you want to disable “%s†catalog? You can enable this catalog again at “Network Search†tab in the Preferences dialog."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Delete Book"/> + <node name="message" value="Are you sure you want to remove “%s†book from the disk?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Register User"/> + <node name="login" value="Username"/> + <node name="password" value="Password"/> + <node name="confirmPassword" value="Password confirmation"/> + <node name="email" value="E-mail" tooltip="E-mail is used to recover your password in case of loss. If you have not specified an e-mail you can't recover your password."/> + <node name="differentPasswords" value="Password and password confirmation must be the same."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Password Recovery"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Password Recovery"/> + <node name="message" value="A message with further instructions has been sent to %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Download Error"/> + <node name="message" value="Can't open downloaded file %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Base"/> + <node name="Regular Paragraph" value="Regular Paragraph"/> + <node name="Title" value="Title"/> + <node name="Section Title" value="Section Title"/> + <node name="Poem Title" value="Poem Title"/> + <node name="Subtitle" value="Subtitle"/> + <node name="Annotation" value="Annotation"/> + <node name="Epigraph" value="Epigraph"/> + <node name="Stanza" value="Stanza"/> + <node name="Verse" value="Verse"/> + <node name="Preformatted text" value="Preformatted text"/> + <node name="Image" value="Image"/> + <node name="Cite" value="Cite"/> + <node name="Author" value="Author"/> + <node name="Date" value="Date"/> + <node name="Internal Hyperlink" value="Internal Hyperlink"/> + <node name="Footnote" value="Footnote"/> + <node name="Emphasis" value="Emphasis"/> + <node name="Strong" value="Strong"/> + <node name="Subscript" value="Subscript"/> + <node name="Superscript" value="Superscript"/> + <node name="Code" value="Code"/> + <node name="StrikeThrough" value="StrikeThrough"/> + <node name="Contents Table" value="Contents Table"/> + <node name="Library Entry" value="Library Entry"/> + <node name="Recent Book List" value="Recent Book List"/> + <node name="Italic" value="Italic"/> + <node name="Bold" value="Bold"/> + <node name="Definition" value="Definition"/> + <node name="Definition Description" value="Definition Description"/> + <node name="Header 1" value="Header 1"/> + <node name="Header 2" value="Header 2"/> + <node name="Header 3" value="Header 3"/> + <node name="Header 4" value="Header 4"/> + <node name="Header 5" value="Header 5"/> + <node name="Header 6" value="Header 6"/> + <node name="External Hyperlink" value="External Hyperlink"/> + <node name="Link to Another Book" value="Link to Another Book"/> + </node> + <node name="external"> + <node name="browser" value="Browser"/> + <node name="defaultBrowser" value="Default Browser"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Unknown Error"/> + <node name="unsupportedCompressionMethod" value="Unsupported Compression Method"/> + <node name="encryptedFile" value="DRM-protected File"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Network Library"/> + </node> + <node name="library"> + <node name="caption" value="Library"/> + </node> +</resources> diff --git a/reader/data/resources/eo.xml b/reader/data/resources/eo.xml new file mode 100644 index 0000000..380826a --- /dev/null +++ b/reader/data/resources/eo.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Esperanto TDE-Ebook-Reader resources, by KatarÃna Nosková --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Aperigi liston de libroj"/> + <node name="collapseTree" value="KaÅi liston de libroj"/> + <node name="edit" value="Redakti informojn pri libro"/> + <node name="unknownAuthor" value="Nekonata aÅtoro"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Elpaki arbon de libroj"/> + <node name="collapseTree" value="Paki arbon de libroj"/> + <node name="edit" value="Redakti informojn pri libro"/> + <node name="clone" value="Kopii informojn pri libro"/> + <node name="delete" value="Forigi informojn pri libro"/> + <node name="noTags" value="Neniuj informoj pri la libro estas je dispono"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Elpaki arbon de libroj"/> + <node name="collapseTree" value="Paki arbon de libroj"/> + </node> + <node name="bookNode"> + <node name="read" value="Legi libron"/> + <node name="edit" value="Redakti informojn pri libro"/> + <node name="delete" value="Forigi libron"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Elpaki"/> + <node name="collapseTree" value="Paki"/> + <node name="reload" value="ReÅargi"/> + <node name="openInBrowser" value="Malfermi en retfoliumilo"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Malfermi katalogon"/> + <node name="collapseTree" value="Fermi katalogon"/> + <node name="login" value="Ensaluto"/> + <node name="logout" value="Elsaluto (%s)"/> + <node name="reload" value="ReÅargi"/> + <node name="dontShow" value="'Ne aperigi ĉi tiun katalogon"/> + <node name="topupAccount" value="Replenigi konton (aktuale: %s)"/> + <node name="register" value="RegistriÄi"/> + <node name="passwordRecovery" value="Renovigi pasvorton"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Serĉi"/> + <node name="expandTree" value="Elpaki serĉrezultojn"/> + <node name="collapseTree" value="Paki serĉrezultojn"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Elpaki librojn"/> + <node name="collapseTree" value="Paki librojn"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Elpaki librojn"/> + <node name="collapseTree" value="Paki librojn"/> + </node> + <node name="bookNode"> + <node name="read" value="Legi lokan version de libro"/> + <node name="delete" value="Forigi lokan version de libro"/> + <node name="download" value="ElÅuti"/> + <node name="readDemo" value="Legi demonstraĵon"/> + <node name="downloadDemo" value="ElÅuti demonstraĵon"/> + <node name="demo" toBeTranslated="true" value="sample"/> + <node name="buy" value="Pagi (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informoj pri la libro..."/> + <node name="toc" value="Enhavo"/> + <node name="showLibrary" value="Malfermi librejon"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Knihovna"> + <node name="showLibrary" value="Malfermi"/> + <node name="previousBook" value="AntaÅa libro"/> + <node name="showRecent" value="Lastatempe malfermitaj"/> + <node name="addBook" value="Aldoni libron..."/> + <node name="showHelp" value="Pri la programo TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Al komenco de dokumento"/> + <node name="gotoPageNumber" value="Al la paÄo..."/> + <node name="gotoSectionStart" value="Al komenco de sekcio"/> + <node name="gotoSectionEnd" value="Al fino de sekcio"/> + <node name="nextTOCSection" value="Al sekva ero de enhavo"/> + <node name="previousTOCSection" value="Al antaÅa ero de enhavo"/> + <node name="navigate" value="Navigi"> + <node name="gotoHome" value="Al komenco de dokumento"/> + <node name="gotoPageNumber" value="Al la paÄo..."/> + <node name="gotoSectionStart" value="Al komenco de sekcio"/> + <node name="gotoSectionEnd" value="Al fino de sekcio"/> + <node name="nextTOCSection" value="Al sekva ero de enhavo"/> + <node name="previousTOCSection" value="Al antaÅa ero de enhavo"/> + <node name="undo" value="Reen"/> + <node name="redo" value="AntaÅen"/> + </node> + <node name="selection" value="Elekti"> + <node name="copyToClipboard" value="Kopii"/> + <node name="openInDictionary" value="Malfermi en vortaro"/> + <node name="clearSelection" value="Malplenigi elekton"/> + </node> + <node name="search" value="Serĉi"> + <node name="search" value="Serĉi la tekston..."/> + <node name="findNext" value="Trovi sekvan"/> + <node name="findPrevious" value="Trovi antaÅan"/> + </node> + <node name="view" value="Aperigi"> + <node name="rotate" value="Turni ekranon"/> + <node name="toggleFullscreen" value="Tutekrana reÄimo"/> + <node name="toggleIndicator" value="Baskuligo de ekrano"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Fermi"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="ReÄimo de legado"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Librejo - la tuta arbo"/> + <node name="popup" value="Lastatempe malfermitaj libroj"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Listo de lastatempe malfermitaj libroj"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="Ordigi librojn laÅ aÅtoroj"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="Ordigi librojn laÅ kategorioj"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Aldoni en librejon"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="Serĉi en reta librejo"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Serĉi en la reto"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Detala serĉado en la reto"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Iru al komenco de teksto"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="Reen"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Denove"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="Iri al la paÄo"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Enhavo"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Serĉi tekston"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Trovi sekvan"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Trovi antaÅan"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Turni tekston"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="Pri la programo TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Informoj pri libro"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Fari"/> + <node name="thisOnly" value="Nur ĉi tiu"/> + <node name="withSubtags" value="Kun subkategorioj"/> + <node name="removeLink" value="Forigi el librejo"/> + <node name="removeFile" value="Forigi el disko"/> + <node name="yesToAll" value="&Jes por ĉiuj"/> + <node name="buy" value="&Pagi"/> + <node name="buyAndDownload" value="Pagi kaj &elÅuti"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Librejo"> + <node name="bookPath" value="Dosierujo kun libroj"/> + <node name="lookInSubdirectories" value="Libroj en subdosierujoj"/> + <node name="collectBooksWithoutMetaInfo" value="Amasigi librojn sen meta-informoj"/> + <node name="downloadDirectory" value="Dosierujo por elÅutitaj libroj"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Reta serĉado"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Uzi prokuran servilon"/> + <node name="proxyHost" value="Prokura servilo"/> + <node name="proxyPort" value="Pordo de prokura servilo"/> + <node name="timeout" value="Tempolimo por ekkonektiÄo en sekundoj"/> + </node> + <node name="Web" value="Reto"> + <node name="enableIntegration" value="Malfermi eksterajn ligilojn en %s"/> + <node name="defaultText" value="Malfermi eksterajn ligilojn en la retfoliumilo"/> + <node name="choice" value="Uzi la retfoliumilon"/> + <node name="command" value="Enmetu komandon"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Lingvo"> + <node name="autoDetect" value="AÅtomata detekto de lingvo kaj kodado"/> + <node name="defaultLanguage" value="DefaÅlta lingvo"/> + <node name="defaultEncodingSet" value="DefaÅlta kodaro"/> + <node name="defaultEncoding" value="Baza kodado"/> + <node name="useWindows1252Hack" value="Uzi windows-1252 anstataÅ iso-8859-1"/> + </node> + <node name="Config" value="Agordoj"> + <node name="autoSave" value="AÅtomata konservado"/> + <node name="timeout" value="Intervalo inter unuopaj konservoj en sekundoj"/> + </node> + <node name="Dictionary" value="Vortaro"> + <node name="enableIntegration" value="Åœalti integradon kun %s"/> + <node name="defaultText" value="Åœalti integradon kun vortaro"/> + <node name="choice" value="Integrado kun"/> + <node name="singleClickOpen" value="Malfermi per unu klako"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Reagi pri malpremo de klavo, ne pri premo de klavo"/> + <node name="minStylusPressure" value="Minimuma grifelpremo"/> + <node name="maxStylusPressure" value="Maksimuma grifelpremo"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Rulumado de teksto"> + <node name="keyScrollDelay" value="MalfruiÄo de rulumado en milisekundoj"/> + <node name="keyLinesToScroll" value="Nombro de rulumotaj linioj ĉe rulumado laÅ linioj"/> + <node name="keyLinesToKeep" value="Nombro de la linioj, kiuj ne estos surkovritaj"/> + <node name="enableTapScrolling" value="Rulumado per tuÅekrano"/> + <node name="fingerOnly" value="Rulumado nur per tuÅekrano"/> + </node> + <node name="Selection" value="Elektado"> + <node name="enableSelection" value="Permesi elektadon de teksto"/> + </node> + <node name="Indicator" value="Indikilo"> + <node name="type" value="Aperigu kiel"> + <node name="osScrollbar" value="Rulumskalo OS"/> + <node name="fbIndicator" value="Indikilo en malnova stilo"/> + <node name="none" value="Ne aperigi"/> + </node> + <node name="height" value="Alto de indikilo"/> + <node name="offset" value="DeÅovo de teksto"/> + <node name="pageNumber" value="Aperigi la pozicion en formo de numeroj"/> + <node name="time" value="Aperigi tempon"/> + <node name="fontSize" value="Tipara grando"/> + <node name="tocMarks" value="Aperigi la markojn TOC"/> + <node name="navigation" value="Permesi navigadon"/> + </node> + <node name="Rotation" value="Rotacio"> + <node name="direction" value="Direkto de rotacio"> + <node name="disabled" value="MalÅaltita"/> + <node name="clockwise" value="Je 90 gradoj laÅhorloÄe"/> + <node name="counterclockwise" value="Je 90 gradoj nelaÅhorloÄe"/> + <node name="180" value="Je 180 gradoj"/> + <node name="cycle" value="Cikle alterni ĉiujn kvar direktojn"/> + </node> + </node> + <node name="Keys" value="Fulmoklavoj"> + <node name="grabSystemKeys" value="Kapti sistemajn fulmoklavojn"/> + <node name="separate" value="Propraj fulmoklavoj, dependantaj de tekst-orientiÄo"/> + <node name="orientation" value="OrientiÄo"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Neniu"/> + <node name="showLibrary" value="Aperigi librejon"/> + <node name="showNetLibrary" toBeTranslated="true" value="Aperigu retan librejon"/> + <node name="showRecent" value="Aperigu lastatempe malfermitajn librojn"/> + <node name="previousBook" value="Malfermi la antaÅan libron"/> + <node name="toc" value="Aperigi enhavon"/> + <node name="gotoHome" value="Iri al komenco de teksto"/> + <node name="gotoSectionStart" value="Iri al komenco de sekcio"/> + <node name="gotoSectionEnd" value="Iri al fino de sekcio"/> + <node name="nextTOCSection" value="Iri al sekva TOC-sekcio"/> + <node name="previousTOCSection" value="Iri al antaÅa TOC-sekcio"/> + <node name="pageForward" value="Rulumo je unu paÄo antaÅen"/> + <node name="pageBackward" value="Rulumo je unu paÄo malantaÅen"/> + <node name="lineForward" value="Rulumo je unu linio antaÅen"/> + <node name="lineBackward" value="Rulumo je unu linio malantaÅen"/> + <node name="undo" value="Reen"/> + <node name="redo" value="Denove"/> + <node name="copyToClipboard" value="Kopii la tekston"/> + <node name="openInDictionary" value="Malfermi la elektitan tekston en vortaro"/> + <node name="clearSelection" value="Malplenigi elekton"/> + <node name="search" value="Serĉi"/> + <node name="findPrevious" value="Trovi antaÅan"/> + <node name="findNext" value="Trovi sekvan"/> + <node name="increaseFont" value="Pligrandigi tiparon"/> + <node name="decreaseFont" value="Malpligrandigi tiparon"/> + <node name="toggleIndicator" value="Aperigi indikilon"/> + <node name="toggleFullscreen" value="Tutekrana reÄimo"/> + <node name="rotate" value="Turni ekranon"/> + <node name="addBook" value="Aldoni libron"/> + <node name="cancel" value="Rezigni"/> + <node name="quit" value="Fermi"/> + <node name="bookInfo" value="Informoj pri libro"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Fermi"/> + <node name="keyDelay" value="MalfruiÄo de klavpremo"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Ĉiam uzi tiparojn de uzanto"/> + </node> + <node name="Margins" value="MarÄenoj"> + <node name="left" value="Maldekstra marÄeno"/> + <node name="right" value="Dekstra marÄeno"/> + <node name="top" value="Supra marÄeno"/> + <node name="bottom" value="Malsupra marÄeno"/> + </node> + <node name="Format" value="Formato"> + <node name="optionsFor" value="Agordoj de formato"/> + <node name="lineSpacing" value="Interlinia distanco"> + <node name="unchanged" value="<sen ÅanÄoj>"/> + </node> + <node name="firstLineIndent" value="KrommarÄeno de la unua linio"/> + <node name="alignment" value="Äœisrandigo"> + <node name="left" value="Maldekstrigi"/> + <node name="right" value="Dekstrigi"/> + <node name="center" value="Centrigi"/> + <node name="justify" value="En blokon"/> + <node name="unchanged" value="<sen ÅanÄoj>"/> + </node> + <node name="spaceBefore" value="Spaco antaÅ"/> + <node name="spaceAfter" value="Spaco post"/> + <node name="startIndent" value="Komenco de krommarÄeno"/> + <node name="endIndent" value="Fino de krommarÄeno"/> + </node> + <node name="Styles" value="Stiloj"> + <node name="optionsFor" value="Agordoj de stiloj"/> + <node name="fontFamily" value="Tipara familio"> + <node name="unchanged" value="<sen ÅanÄoj>"/> + </node> + <node name="fontSize" value="Tipara grando"/> + <node name="fontSizeDifference" value="Diferenco en grando"/> + <node name="bold" value="Dika"/> + <node name="italic" value="Kursiva"/> + <node name="allowHyphenations" value="Permesi vortdividon"/> + <node name="autoHyphenations" value="AÅtomata vortdivido"/> + </node> + <node name="Colors" value="Koloroj"> + <node name="colorFor" value="Koloro de"> + <node name="background" value="Fono"/> + <node name="selectionBackground" value="Elekto de fono"/> + <node name="text" value="Ordinara teksto"/> + <node name="internalLink" value="Interna ligilo"/> + <node name="externalLink" value="Ekstera ligilo"/> + <node name="bookLink" value="Ligilo al alia libro"/> + <node name="highlighted" value="Markita teksto"/> + <node name="treeLines" value="Arbo"/> + <node name="indicator" value="Indikilo"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informoj pri libro"/> + <node name="tab"> + <node name="Common" value="Bazaj informoj"> + <node name="file" value="Dosiero"/> + <node name="title" value="Titolo"/> + <node name="language" value="Lingvo"/> + <node name="encodingSet" value="Tipo de kodaro"/> + <node name="encoding" value="Kodado"/> + </node> + <node name="Authors" value="AÅtoroj"> + <node name="authorDisplayName" value="Nomo de aÅtoro"/> + </node> + <node name="Series" value="Serio"> + <node name="seriesTitle" value="Titolo de serio"/> + <node name="bookIndex" value="Numero de libro"/> + </node> + <node name="Tags" value="Kategorioj"> + <node name="tags" value="Listo de kategorioj"/> + </node> + <node name="Text" value="Teksto"> + <node name="breakType" value="Nova alineo post"/> + <node name="ignoreIndent" value="Ignori la krommarÄenon malpli grandan ol"/> + <node name="buildTOC" value="Krei kapon"/> + <node name="emptyLines" value="Malplenigi alineojn antaÅ nova sekcio"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Nova alineo post"/> + <node name="ignoreIndent" value="Ignori la krommarÄenon malpli grandan ol"/> + <node name="buildTOC" value="Krei kapon"/> + <node name="emptyLines" value="Malplenigi alineojn antaÅ nova sekcio"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informoj pri aÅtoro"/> + <node name="name" value="Nomo de aÅtoro"/> + <node name="sortKey" value="Ordiga Ålosilo de aÅtoro"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Aldoni libron en librejon"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Serĉi tekston"/> + <node name="text" value="Teksto"/> + <node name="ignoreCase" value="&Ignori usklecon"/> + <node name="wholeText" value="&En la tuta teksto"/> + <node name="backward" value="&Reen"/> + <node name="currentSection" value="&Nur ĉi tiu sekcio"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Reta serĉado"/> + <node name="titleAndSeries" value="Titolo de libro / serio"/> + <node name="author" value="AÅtoro"/> + <node name="category" value="Kategorio"/> + <node name="description" value="Priskribo"/> + <node name="annotation" value="Serĉrezultoj por: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Iri al la paÄo"/> + <node name="pageNumber" value="Iri al la paÄo n-ro"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Redakti / kopii kategorion"/> + <node name="name" value="Nomo"/> + <node name="includeSubtags" value="Inkluzive de subkategorioj"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Kopii kategorion"/> + <node name="name" value="Nomo"/> + <node name="includeSubtags" value="Inkluzive de subkategorioj"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Forigi libron"/> + <node name="message" value="Ĉu forigi la libron “%s†el librejo?"/> + <node name="deleteFile" value="Ĉu vi certas, ke vi vere deziras forigi la dosieron “%s†el via disko?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Forigi kategorion"/> + <node name="message" value="Ĉu forigi la kategorion “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Eraro"/> + <node name="message" value="Ne eblas malfermi: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Eraro"/> + <node name="message" value="Ne eblas forigi la dosieron %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Eraro"/> + <node name="message" value="Pardonu, helpdosiero ne estis trovita"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Listo de librejoj estas malplena"/> + <node name="authenticationFailed" value="Ensaluto malsukcesis"/> + <node name="internalError" value="Eraro de ervilo"/> + <node name="purchaseNotEnoughMoney" value="Mono ne sufiĉas"/> + <node name="purchaseMissingBook" value="Mankas libro"/> + <node name="purchaseAlreadyPurchased" value="Pagita"/> + <node name="bookNotPurchased" value="Pago por la libro ne okazis"/> + <node name="downloadLimitExceeded" value="Transpasita elÅut-limigo"/> + <node name="unsupportedOperation" value="Nesubtenata ago"/> + <node name="loginAlreadyTaken" value="Ĉi tiu salutnomo estas jam okupita"/> + <node name="loginNotSpecified" value="Bonvolu enmeti alian salutnomon"/> + <node name="passwordNotSpecified" value="Bonvolu enmeti pasvorton"/> + <node name="emailNotSpecified" value="Bonvolu enmeti retpoÅt-adreson"/> + <node name="invalidEMail" value="MalÄusta retpoÅt-adreso"/> + <node name="tooManyRegistrations" value="Tro multe da registriÄoj por IP; provu denove post kelkaj minutoj"/> + <node name="noUserEmail" value="La uzanto ne estis registrita kun ĉi tiu retpoÅt-adreso"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Eraro ĉe elÅutado"/> + <node name="message" value="Ne eblas nun elÅuti la libron"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Mi Åargas libron. Bonvolu atendi..."/> + <node name="loadingBookList" value="Mi Åargas liston de libroj. Bonvolu atendi..."/> + <node name="migrate" value="Okazas trairo al nova versio. Bonvolu atendi..."/> + <node name="downloadBookList" value="Mi elÅutas liston de libroj. Bonvolu atendi..."/> + <node name="downloadBook" value="Mi elÅutas libron. Bonvolu atendi..."/> + <node name="downloadImages" value="Mi elÅutas bildojn. Bonvolu atendi..."/> + <node name="authentication" value="Okazas ensaluto. Bonvolu atendi..."/> + <node name="purchaseBook" value="Okazas pago por libro. Bonvolu atendi..."/> + <node name="initializeAuthenticationManager" value="Mi elÅutas kontajn informojn. Bonvolu atendi..."/> + <node name="loadSubCatalog" value="Mi importas katalogon. Bonvolu atendi..."/> + <node name="registerUser" value="Okazas registrado de nova konto. Bonvolu atendi..."/> + <node name="passwordRecovery" value="Okazas renovigo de pasvorto. Bonvolu atendi..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Okazas validigo de konto. Bonvolu atendi..."/> + <node name="signOut" toBeTranslated="true" value="Okazas elsaluto. Bonvolu atendi..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Pagi libron"/> + <node name="message" value="Ĉu vi deziras pagi la libron “%s†?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Ensaluto"/> + <node name="login" value="Salutnomo"/> + <node name="password" value="Pasvorto"/> + <node name="skipIP" value="Ne eblas konektiÄi kun la IP-adreso"/> + <node name="loginIsEmpty" value="Mankas ensalutaj datumoj"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informoj"/> + <node name="message" value="Malplena katalogo."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Malpermesi katalogon"/> + <node name="message" value="Ĉu vi vere deziras malpermesi la katalogon “%s†? Vi povas denove permesi Äin en Agordoj, en la folio “Reta serĉadoâ€."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Forigi libron"/> + <node name="message" value="Ĉu vi konsentas kun vera forigo de la libro “%s†k el via disko?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="RegistriÄo de uzanto"/> + <node name="login" value="Salutnomo"/> + <node name="password" value="Pasvorto"/> + <node name="confirmPassword" value="Konfirmu pasvorton"/> + <node name="email" value="RetpoÅto"/> + <node name="differentPasswords" value="Pasvorto kaj Äia konfirmo devas kongrui."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Renovigi pasvorton"/> + <node name="email" value="RetpoÅto"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="La pasvorto estas renovigita."/> + <node name="message" value="MesaÄoj al sekvaj instrukcioj estas senditaj al %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Eraro ĉe elÅutado"/> + <node name="message" value="Ne eblas malfermi la elÅutitan dosieron %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Elira teksto"/> + <node name="Regular Paragraph" value="Ordinara alineo"/> + <node name="Title" value="Titolo"/> + <node name="Section Title" value="Nomo de sekcio"/> + <node name="Poem Title" value="Titolo de poemo"/> + <node name="Subtitle" value="Subtitolo"/> + <node name="Annotation" value="Notacio"/> + <node name="Epigraph" value="Moto"/> + <node name="Stanza" value="Strofo"/> + <node name="Verse" value="Verso"/> + <node name="Preformatted text" value="AntaÅformatita teksto"/> + <node name="Image" value="Bildo"/> + <node name="Cite" value="Citaĵo"/> + <node name="Author" value="AÅtoro"/> + <node name="Date" value="Dato"/> + <node name="Internal Hyperlink" value="Interna ligilo"/> + <node name="Footnote" value="Piednoto"/> + <node name="Emphasis" value="Emfazo"/> + <node name="Strong" value="Forta"/> + <node name="Subscript" value="Suba indico"/> + <node name="Superscript" value="Supra indico"/> + <node name="Code" value="Kodo"/> + <node name="StrikeThrough" value="Trastrekita"/> + <node name="Contents Table" value="Enhavo de tabelo"/> + <node name="Library Entry" value="Ero de librejo"/> + <node name="Recent Book List" value="Listo de lastatempe malfermitaj libroj"/> + <node name="Italic" value="Kursiva"/> + <node name="Bold" value="Dika"/> + <node name="Definition" value="Priskribo"/> + <node name="Definition Description" value="Priskribo de difino"/> + <node name="Header 1" value="Kapo 1"/> + <node name="Header 2" value="Kapo 2"/> + <node name="Header 3" value="Kapo 3"/> + <node name="Header 4" value="Kapo 4"/> + <node name="Header 5" value="Kapo 5"/> + <node name="Header 6" value="Kapo 6"/> + <node name="External Hyperlink" value="Ekstera ligilo"/> + <node name="Link to Another Book" value="Ligilo al alia libro"/> + </node> + <node name="external"> + <node name="browser" value="Retfoliumilo"/> + <node name="defaultBrowser" value="DefaÅlta retfoliumilo"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Nekonata eraro"/> + <node name="unsupportedCompressionMethod" value="Nesubtenata metodo de densigo"/> + <node name="encryptedFile" value="La dosiero estas protektita per DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Reta librejo"/> + </node> + <node name="library"> + <node name="caption" value="Librejo"/> + </node> +</resources> diff --git a/reader/data/resources/es.xml b/reader/data/resources/es.xml new file mode 100644 index 0000000..1d02f77 --- /dev/null +++ b/reader/data/resources/es.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Spanish TDE-Ebook-Reader resources, by Leproso --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Mostrar libros"/> + <node name="collapseTree" value="Mostrar libros"/> + <node name="edit" value="Modificar información"/> + <node name="unknownAuthor" value="Autor desconocido"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Mostrar libros"/> + <node name="collapseTree" value="Ocultar libros"/> + <node name="edit" value="Modificar etiqueta"/> + <node name="clone" value="Duplicar etiqueta"/> + <node name="delete" value="Borrar etiqueta"/> + <node name="noTags" value="Libros sin etiquetas"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Mostrar libros"/> + <node name="collapseTree" value="Ocultar libro"/> + </node> + <node name="bookNode"> + <node name="read" value="Leer libro"/> + <node name="edit" value="Modificar información"/> + <node name="delete" value="Borrar libro"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Por autor"> + <node name="summary" value="Libros ordenados por autor"/> + </node> + <node name="byTitle" value="Por tÃtulo"> + <node name="summary" value="Libros ordenados por tÃtulo"/> + </node> + <node name="byDate" value="Por fecha"> + <node name="summary" value="Libros ordenados or fecha de compra"/> + </node> + <node name="bySeries" value="Por serie"> + <node name="summary" value="Libros ordenados por serie"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Ampliar"/> + <node name="collapseTree" value="Cerrar"/> + <node name="reload" value="Recargar"/> + <node name="openInBrowser" value="Abrir en navegador"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Abrir catálogo"/> + <node name="collapseTree" value="Cerrar catálogo"/> + <node name="login" value="Ingresar"/> + <node name="logout" value="Salir (%s)"/> + <node name="reload" value="Recargar"/> + <node name="dontShow" value="No volver a mostrar este catálogo"/> + <node name="topupAccount" value="Recargar cuenta (actualizar: %s)"/> + <node name="register" value="Ingresar"/> + <node name="passwordRecovery" value="Recuperar contraseña"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Resultados de la búsqueda"/> + <node name="expandTree" value="Mostrar los resultados"/> + <node name="collapseTree" value="Ocultar los resultados"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Mostrar libros"/> + <node name="collapseTree" value="Ocultar libros"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Mostrar libros"/> + <node name="collapseTree" value="Ocultar libros"/> + </node> + <node name="bookNode"> + <node name="read" value="Leer copia guardada"/> + <node name="delete" value="Borrar copia guardada"/> + <node name="download" value="Descargar"/> + <node name="readDemo" value="Leer demostración"/> + <node name="downloadDemo" value="Descargar demostración"/> + <node name="demo" value="demostración"/> + <node name="buy" value="Comprar (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Información sobre el libro..."/> + <node name="toc" value="Ãndice de contenidos"/> + <node name="showLibrary" value="Abrir biblioteca"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Biblioteca"> + <node name="showLibrary" value="Abrir"/> + <node name="previousBook" value="Libro anterior"/> + <node name="showRecent" value="Reciente"/> + <node name="addBook" value="Añadir libro..."/> + <node name="showHelp" value="Ayuda sobre TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Ir al inicio del libro"/> + <node name="gotoPageNumber" value="Ir a la página..."/> + <node name="gotoSectionStart" value="Ir al inicio del capÃtulo"/> + <node name="gotoSectionEnd" value="Ir al final del capÃtulo"/> + <node name="nextTOCSection" value="Ir al siguiente capÃtulo"/> + <node name="previousTOCSection" value="Ir al capÃtulo anterior"/> + <node name="navigate" value="Navegar"> + <node name="gotoHome" value="Ir al inicio del libro"/> + <node name="gotoPageNumber" value="Ir a la página..."/> + <node name="gotoSectionStart" value="Ir al inicio del capÃtulo"/> + <node name="gotoSectionEnd" value="Ir al final del capÃtulo"/> + <node name="nextTOCSection" value="Ir al siguiente capÃtulo"/> + <node name="previousTOCSection" value="Ir al capÃtulo anterior"/> + <node name="undo" value="Anterior"/> + <node name="redo" value="Siguiente"/> + </node> + <node name="selection" value="Selección"> + <node name="copyToClipboard" value="Copiar al portapapeles"/> + <node name="openInDictionary" value="Abrir en el Diccionario"/> + <node name="clearSelection" value="Deshacer selección"/> + </node> + <node name="search" value="Buscar"> + <node name="search" value="Buscar palabra..."/> + <node name="findNext" value="Buscar siguiente"/> + <node name="findPrevious" value="Buscar anterior"/> + </node> + <node name="view" value="Ver"> + <node name="rotate" value="Girar pantalla"/> + <node name="toggleFullscreen" value="Pantalla completa"/> + <node name="toggleIndicator" value="Activar Indicador"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Salir"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Leer Librok"/> + <node name="tooltip" value="Volver al Modo de Lectura"/> + </node> + <node name="showLibrary"> + <node name="label" value="Biblioteca"/> + <node name="tooltip" value="Mostrar contenido de la Biblioteca"/> + <node name="popup" value="Mostrar lista de libros recientes"/> + </node> + <node name="showRecent"> + <node name="label" value="Libros Recientes"/> + <node name="tooltip" value="Mostrar lista de libros recientes"/> + </node> + <node name="byAuthor"> + <node name="label" value="Por Autor"/> + <node name="tooltip" value="Ordenar Libros por Autor"/> + </node> + <node name="byTag"> + <node name="label" value="Por Etiqueta"/> + <node name="tooltip" value="Ordenar Libros por Etiqueta"/> + </node> + <node name="addBook"> + <node name="label" value="Añadir Libro"/> + <node name="tooltip" value="Añadir Libro a la Biblioteca"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Red"/> + <node name="tooltip" value="Buscar Libros en la Web"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Búsqueda simple"/> + <node name="tooltip" value="Buscar en la Web"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Búsqueda"/> + <node name="tooltip" value="Búsqueda avanzada"/> + </node> + <node name="gotoHome"> + <node name="label" value="Ir al Inicio"/> + <node name="tooltip" value="Ir al Inicio del Libro"/> + </node> + <node name="undo"> + <node name="label" value="Anterior"/> + <node name="tooltip" value="Anterior"/> + </node> + <node name="redo"> + <node name="label" value="Siguiente"/> + <node name="tooltip" value="Siguiente"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Ir a la Página"/> + <node name="tooltip" value="Ir a la Página"/> + </node> + <node name="toc"> + <node name="label" value="Ãndice"/> + <node name="tooltip" value="Ãndice de Contenidos"/> + </node> + <node name="search"> + <node name="label" value="Buscar"/> + <node name="tooltip" value="Buscar Texto"/> + </node> + <node name="findNext"> + <node name="label" value="Siguiente"/> + <node name="tooltip" value="Buscar siguiente"/> + </node> + <node name="findPrevious"> + <node name="label" value="Anterior"/> + <node name="tooltip" value="Buscar anterior"/> + </node> + <node name="rotate"> + <node name="label" value="Girar"/> + <node name="tooltip" value="Girar texto"/> + </node> + <node name="showHelp"> + <node name="label" value="Ayuda"/> + <node name="tooltip" value="Información sobre TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Filtro"/> + <node name="tooltip" value="Filtro"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Información sobre el Libro"/> + <node name="tooltip" value="Mostrar Información sobre el Libro"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Buscar"/> + <node name="thisOnly" value="Solo esto"/> + <node name="withSubtags" value="Con subetiquetas"/> + <node name="removeLink" value="Borrar de la Biblioteca"/> + <node name="removeFile" value="Borrar del disco duro"/> + <node name="yesToAll" value="Si a &todo"/> + <node name="buy" value="&Comprar"/> + <node name="buyAndDownload" value="Comprar y &descargar"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Biblioteca"> + <node name="bookPath" value="Directorios de Libros"/> + <node name="lookInSubdirectories" value="Buscar libros en los subdirectorios"/> + <node name="collectBooksWithoutMetaInfo" value="Colección de libros sin información"/> + <node name="downloadDirectory" value="Directorio de libros descargados"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Búsqueda en la Web"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Usar servidor Proxy"/> + <node name="proxyHost" value="IP del servidor Proxy"/> + <node name="proxyPort" value="Puerto del servidor Proxy"/> + <node name="timeout" value="Tiempo de espera en operaciones de red (segundos)"/> + </node> + <node name="Web" value="Navegador"> + <node name="enableIntegration" value="Abrir enlaces externos en el Navegador Web"/> + <node name="defaultText" value="Abrir enlaces externos en Navegador Web"/> + <node name="choice" value="Usar Navegador Web"/> + <node name="command" value="Comando a ejecutar"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Idioma"> + <node name="autoDetect" value="Detectar automáticamente el idioma y la codificación"/> + <node name="defaultLanguage" value="Idioma predeterminado"/> + <node name="defaultEncodingSet" value="Juego de carácteres"/> + <node name="defaultEncoding" value="Codificación predeterminada"/> + <node name="useWindows1252Hack" value="Usar windows-1252 en lugar de iso-8859-1"/> + </node> + <node name="Config" value="Guardar"> + <node name="autoSave" value="Guardar posición automáticamente"/> + <node name="timeout" value="Guardar cada (segundos)"/> + </node> + <node name="Dictionary" value="Diccionario"> + <node name="enableIntegration" value="Activar la integración con Navegador Web"/> + <node name="defaultText" value="Activar la integración con el Diccionario"/> + <node name="choice" value="Integrar con"/> + <node name="singleClickOpen" value="Abrir con un click"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Acción sobre el botón, no en la presión"/> + <node name="minStylusPressure" value="MÃnima presión"/> + <node name="maxStylusPressure" value="Máxima presión"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Desplazamiento Vertical"> + <node name="keyScrollDelay" value="Retardo en desplazamiento vertical, milisegundos"/> + <node name="keyLinesToScroll" value="LÃneas desplazadas con flechas del teclado"/> + <node name="keyLinesToKeep" value="LÃneas desplazadas con avance de página (AvPág/RePág)"/> + <node name="enableTapScrolling" value="Activar desplazamiento vertical con un click del ratón"/> + <node name="fingerOnly" value="Sólo desplazamiento vertical con un click del ratón"/> + </node> + <node name="Selection" value="Selección"> + <node name="enableSelection" value="Permitir seleccionar el texto"/> + </node> + <node name="Indicator" value="Señalador"> + <node name="type" value="Mostrar como"> + <node name="osScrollbar" value="Barra de desplazamiento"/> + <node name="fbIndicator" value="Estilo personalizado"/> + <node name="none" value="No mostrar"/> + </node> + <node name="height" value="Altura de la barra señaladora"/> + <node name="offset" value="Margen inferior"/> + <node name="pageNumber" value="Mostrar el número de página"/> + <node name="time" value="Mostrar la Hora"/> + <node name="fontSize" value="Tamaño de la Fuente"/> + <node name="tocMarks" value="Mostrar marcadores del Ãndice"/> + <node name="navigation" value="Activar Navegación"/> + </node> + <node name="Rotation" value="Girar texto"> + <node name="direction" value="Tipo de giro"> + <node name="disabled" value="Desactivar"/> + <node name="clockwise" value="90 grados a la derecha"/> + <node name="counterclockwise" value="90 grados a la izquierda"/> + <node name="180" value="180 grados"/> + <node name="cycle" value="Girar en las cuatro direcciones"/> + </node> + </node> + <node name="Keys" value="Atajos"> + <node name="grabSystemKeys" value="Guardar atajos del teclado"/> + <node name="separate" value="Las combinaciones de teclas dependen de la orientación del texto"/> + <node name="orientation" value="Orientación"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Ninguno"/> + <node name="showLibrary" value="Mostrar la Biblioteca"/> + <node name="showNetLibrary" value="Mostrar Bibliotecas en la Web"/> + <node name="showRecent" value="Mostrar libros recientes"/> + <node name="previousBook" value="Abrir el libro anterior"/> + <node name="toc" value="Ver Ãndice de contenidos"/> + <node name="gotoHome" value="Ir al inicio"/> + <node name="gotoSectionStart" value="Ir al inicio del capÃtulo"/> + <node name="gotoSectionEnd" value="Ir al final del capÃtulo"/> + <node name="nextTOCSection" value="Ir al capÃtulo siguiente"/> + <node name="previousTOCSection" value="Ir al capÃtulo anterior"/> + <node name="pageForward" value="Ir a la página siguiente"/> + <node name="pageBackward" value="Ir a la página anterior"/> + <node name="lineForward" value="Ir a la lÃnea siguiente"/> + <node name="lineBackward" value="Ir a la lÃnea anterior"/> + <node name="undo" value="Deshacer"/> + <node name="redo" value="Rehacer"/> + <node name="copyToClipboard" value="Copiar al portapapeles"/> + <node name="openInDictionary" value="Abrir en el diccionario"/> + <node name="clearSelection" value="Deshacer selección"/> + <node name="search" value="Buscar"/> + <node name="findPrevious" value="Buscar anterior"/> + <node name="findNext" value="Buscar siguiente"/> + <node name="increaseFont" value="Aumentar tamaño de fuente"/> + <node name="decreaseFont" value="Disminuir tamaño de fuente"/> + <node name="toggleIndicator" value="Señalador de posición"/> + <node name="toggleFullscreen" value="Pantalla completa"/> + <node name="rotate" value="Girar pantalla"/> + <node name="addBook" value="Añadir Libro"/> + <node name="cancel" value="Cancelar"/> + <node name="quit" value="Salir"/> + <node name="bookInfo" value="Mostrar información del libro"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Cancelar y Salir"/> + <node name="keyDelay" value="Demora para aceptar"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Utilizar siempre Fuentes personalizadas"/> + </node> + <node name="Margins" value="Márgenes"> + <node name="left" value="Margen izquierdo"/> + <node name="right" value="Margen derecho"/> + <node name="top" value="Margen superior"/> + <node name="bottom" value="Margen inferior"/> + </node> + <node name="Format" value="Formato"> + <node name="optionsFor" value="Opciones para"/> + <node name="lineSpacing" value="Interlineado"> + <node name="unchanged" value="<sin cambios>"/> + </node> + <node name="firstLineIndent" value="SangrÃa en la primera lÃnea"/> + <node name="alignment" value="Alineación"> + <node name="left" value="Izquierda"/> + <node name="right" value="Derecha"/> + <node name="center" value="Centrado"/> + <node name="justify" value="Justificado"/> + <node name="unchanged" value="<sin cambios>"/> + </node> + <node name="spaceBefore" value="Espacio encima del párrafo"/> + <node name="spaceAfter" value="Espacio debajo del párrafo"/> + <node name="startIndent" value="SangrÃa al inicio del texto"/> + <node name="endIndent" value="SangrÃa al final del texto"/> + </node> + <node name="Styles" value="Estilos"> + <node name="optionsFor" value="Opciones para"/> + <node name="fontFamily" value="Fuente"> + <node name="unchanged" value="<sin cambios>"/> + </node> + <node name="fontSize" value="Tamaño"/> + <node name="fontSizeDifference" value="Diferencia de tamaño"/> + <node name="bold" value="Negrita"/> + <node name="italic" value="Itálica"/> + <node name="allowHyphenations" value="Permitir separación en sÃlabas"/> + <node name="autoHyphenations" value="Separación automática en sÃlabas"/> + </node> + <node name="Colors" value="Colores"> + <node name="colorFor" value="Colores para"> + <node name="background" value="Fondo del texto"/> + <node name="selectionBackground" value="Fondo del texto seleccionado"/> + <node name="text" value="Texto común"/> + <node name="internalLink" value="Enlace interior del texto"/> + <node name="externalLink" value="Enlace exterior del texto"/> + <node name="bookLink" value="Enlace a otro libro"/> + <node name="highlighted" value="Texto Resaltado"/> + <node name="treeLines" value="LÃneas"/> + <node name="indicator" value="Señalador de posición"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Información sobre el libro"/> + <node name="tab"> + <node name="Common" value="Datos"> + <node name="file" value="Ubicación"/> + <node name="title" value="TÃtulo"/> + <node name="language" value="Idioma"/> + <node name="encodingSet" value="Juego de carácteres"/> + <node name="encoding" value="Codificación"/> + </node> + <node name="Authors" value="Autor"> + <node name="authorDisplayName" value="Nombre del Autor"/> + </node> + <node name="Series" value="Colección"> + <node name="seriesTitle" value="TÃtulo de la Colección"/> + <node name="bookIndex" value="Ãndice del Libro"/> + </node> + <node name="Tags" value="Etiquetas"> + <node name="tags" value="Nombre de la etiqueta"/> + </node> + <node name="Text" value="Libro"> + <node name="breakType" value="Salto de párrafo"/> + <node name="ignoreIndent" value="Ignorar sangrÃa inferior a"/> + <node name="buildTOC" value="Generar Ãndice de Contenidos"/> + <node name="emptyLines" value="LÃneas vacÃas antes de un nuevo CapÃtulo"/> + </node> + <node name="<PRE>" value="Ver"> + <node name="breakType" value="Salto de párrafo"/> + <node name="ignoreIndent" value="Ignorar sangrÃa inferior a"/> + <node name="buildTOC" value="Generar Ãndice de Contenidos"/> + <node name="emptyLines" value="LÃneas vacÃas antes de un nuevo CapÃtulo"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Información del Autor"/> + <node name="name" value="Nombre del Autor"/> + <node name="sortKey" value="Ordenar por Autor"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Añadir libro a la Biblioteca"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Buscar texto"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignorar mayúsculas"/> + <node name="wholeText" value="En &todo el libro"/> + <node name="backward" value="&Hacia atrás"/> + <node name="currentSection" value="&En este capÃtulo solamente"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Búsqueda en la Web"/> + <node name="titleAndSeries" value="TÃtulo/Colección"/> + <node name="author" value="Autor"/> + <node name="category" value="CategorÃa"/> + <node name="description" value="Descripción"/> + <node name="annotation" value="Buscar resultado por: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Ir a la Página"/> + <node name="pageNumber" value="Ir a la Página número"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Editar Etiqueta"/> + <node name="name" value="Nombre de la Etiqueta"/> + <node name="includeSubtags" value="Incluir Subetiquetas"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Duplicar Etiqueta"/> + <node name="name" value="Nombre de la Etiqueta"/> + <node name="includeSubtags" value="Incluir Subetiquetas"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Borrar Libro"/> + <node name="message" value="¿Borrar Libro “%s†de la Biblioteca?"/> + <node name="deleteFile" value="¿Está seguro de borrar el archivo “%s†del disco duro?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Borrar Etiqueta"/> + <node name="message" value="¿Borrar Etiqueta “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Error"/> + <node name="message" value="Imposible abrir: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Error"/> + <node name="message" value="No se puede borrar el archivo %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Error"/> + <node name="message" value="Archivo de ayuda no encontrado"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Borrar lista de la Biblioteca"/> + <node name="authenticationFailed" value="Error de autenticación"/> + <node name="internalError" value="Error en el servidor interno"/> + <node name="purchaseNotEnoughMoney" value="No hay suficiente dinero"/> + <node name="purchaseMissingBook" value="Falta el Libro"/> + <node name="purchaseAlreadyPurchased" value="Ya está comprado"/> + <node name="bookNotPurchased" value="El libro no fue comprado"/> + <node name="downloadLimitExceeded" value="LÃmite excedido de descarga"/> + <node name="unsupportedOperation" value="Operación no permitida"/> + <node name="loginAlreadyTaken" value="El Nombre de usuario ya está en uso"/> + <node name="loginNotSpecified" value="Por favor, introduzca el nombre de usuario"/> + <node name="passwordNotSpecified" value="Por favor, introduzca la contraseña"/> + <node name="emailNotSpecified" value="Por favor, introduzca la dirección de correo electrónico"/> + <node name="invalidEMail" value="No es válida la dirección de correo electrónico"/> + <node name="tooManyRegistrations" value="Demasiadas conexiones; intentar nuevamente"/> + <node name="noUserEmail" value="Ningún usuario registrado con esta dirección de correo electrónico"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Error al descargar"/> + <node name="message" value="En este momento no se puede descargar este libro"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Cargando libro. Por favor, espere..."/> + <node name="loadingBookList" value="Cargando la Biblioteca. Por favor, espere..."/> + <node name="migrate" value="Actualizando a la nueva versión. Por favor, espere..."/> + <node name="downloadBookList" value="Descargando la lista de libros. Por favor, espere..."/> + <node name="downloadBook" value="Descargando libro. Por favor, espere..."/> + <node name="downloadImages" value="Descargando imagen. Por favor, espere..."/> + <node name="authentication" value="Autenticando. Por favor, espere..."/> + <node name="purchaseBook" value="Comprando libro. Por favor, espere..."/> + <node name="initializeAuthenticationManager" value="Descargando información de la cuenta. Por favor, espere..."/> + <node name="loadSubCatalog" value="Cargando catálogo. Por favor, espere..."/> + <node name="registerUser" value="Registrando nueva cuenta. Por favor, espere..."/> + <node name="passwordRecovery" value="Recuperando contraseña. Por favor, espere..."/> + <node name="authenticationCheck" value="Validando la cuenta. Por favor, espere..."/> + <node name="signOut" value="Saliendo de la cuenta. Por favor, espere..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Comprar este Libro"/> + <node name="message" value="¿Estás seguro de que desea comprar “%s†el libro?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Autenticación"/> + <node name="login" value="Nombre de Usuario"/> + <node name="password" value="Contraseña"/> + <node name="skipIP" value="No vincular a la dirección IP"/> + <node name="loginIsEmpty" value="El Nombre de Usuario no debe estar vacÃo"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Información"/> + <node name="message" value="El Catálogo está vacÃo."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Deshabilitar catálogo"/> + <node name="message" value="¿Estás seguro de que desea deshabilitar “%s†el catálogo? Se puede habilitar en el futuro en “ Búsqueda en la Web†en el diálogo de Preferencias."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Borrar Libro"/> + <node name="message" value="¿Estás seguro de que desea borrar “%s†el libro del disco duro?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Registro de Usuarios"/> + <node name="login" value="Nombre de Usuario"/> + <node name="password" value="Contraseña"/> + <node name="confirmPassword" value="Confirmar Contraseña"/> + <node name="email" value="E-mail" tooltip="Esta dirección se utiliza para recuperar su contraseña en caso de olvido. Si usted no ha especificado una dirección de correo electrónico no podrá recuperar su contraseña.."/> + <node name="differentPasswords" value="La contraseña y la confirmación de la contraseña debe ser la misma.."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Recuperar Contraseña"/> + <node name="email" value="Correo Electrónico"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Recuperar Contraseña"/> + <node name="message" value="Un mensaje con instrucciones adicionales se ha enviado a %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Error de descarga"/> + <node name="message" value="No se puede abrir el archivo descargado %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Formato básico"/> + <node name="Regular Paragraph" value="Párrafo normal"/> + <node name="Title" value="TÃtulo"/> + <node name="Section Title" value="TÃtulo del CapÃtulo"/> + <node name="Poem Title" value="TÃtulo del poema"/> + <node name="Subtitle" value="SubtÃtulo"/> + <node name="Annotation" value="Anotación"/> + <node name="Epigraph" value="EpÃgrafe"/> + <node name="Stanza" value="Estrofa"/> + <node name="Verse" value="Verso"/> + <node name="Preformatted text" value="Texto preformateado"/> + <node name="Image" value="Imagen"/> + <node name="Cite" value="Cita"/> + <node name="Author" value="Autor"/> + <node name="Date" value="Fecha"/> + <node name="Internal Hyperlink" value="Enlace interno"/> + <node name="Footnote" value="Nota al pie de página"/> + <node name="Emphasis" value="Énfasis"/> + <node name="Strong" value="Negrita"/> + <node name="Subscript" value="SubÃndice"/> + <node name="Superscript" value="SuperÃndice"/> + <node name="Code" value="Código"/> + <node name="StrikeThrough" value="Tachado"/> + <node name="Contents Table" value="Contenido del Ãndice"/> + <node name="Library Entry" value="Biblioteca de Entrada"/> + <node name="Recent Book List" value="Lista de libros recientes"/> + <node name="Italic" value="Itálica"/> + <node name="Bold" value="Negrita"/> + <node name="Definition" value="Definición"/> + <node name="Definition Description" value="Descripción de la definición"/> + <node name="Header 1" value="Encabezado 1"/> + <node name="Header 2" value="Encabezado 2"/> + <node name="Header 3" value="Encabezado 3"/> + <node name="Header 4" value="Encabezado 4"/> + <node name="Header 5" value="Encabezado 5"/> + <node name="Header 6" value="Encabezado 6"/> + <node name="External Hyperlink" value="Enlace externo"/> + <node name="Link to Another Book" value="Enlace a otro Libro"/> + </node> + <node name="external"> + <node name="browser" value="Navegador"/> + <node name="defaultBrowser" value="Navegador predeterminado"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Error desconocido"/> + <node name="unsupportedCompressionMethod" value="Método de compresión no soportado"/> + <node name="encryptedFile" value="Archivo protegido con DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Red de Bibliotecas"/> + </node> + <node name="library"> + <node name="caption" value="Biblioteca"/> + </node> +</resources> diff --git a/reader/data/resources/fi.xml b/reader/data/resources/fi.xml new file mode 100644 index 0000000..afe9b49 --- /dev/null +++ b/reader/data/resources/fi.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Finnish TDE-Ebook-Reader resources, by Marko Vertainen --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Näytä kirjat"/> + <node name="collapseTree" value="Piilota kirjat"/> + <node name="edit" value="Muokkaa tietoja"/> + <node name="unknownAuthor" value="Tuntematon tekijä"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Näytä kirjat"/> + <node name="collapseTree" value="Piilota kirjat"/> + <node name="edit" value="Muokkaa luokkaa"/> + <node name="clone" value="Kloonaa luokka"/> + <node name="delete" value="Poista luokka"/> + <node name="noTags" value="Kirjat ilman luokkaa"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Näytä kirjat"/> + <node name="collapseTree" value="Piilota kirjat"/> + </node> + <node name="bookNode"> + <node name="read" value="Lue kirja"/> + <node name="edit" value="Muokkaa tietoja"/> + <node name="delete" value="Poista kirja"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Laajenna"/> + <node name="collapseTree" value="Piilota"/> + <node name="reload" value="Lataa uudelleen"/> + <node name="openInBrowser" value="Avaa selaimessa"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Avaa luettelo"/> + <node name="collapseTree" value="Sulje luettelo"/> + <node name="login" value="Kirjaudu sisään"/> + <node name="logout" value="Kirjaudu ulos (%s)"/> + <node name="reload" value="Lataa uudelleen"/> + <node name="dontShow" value="Älä näytä tätä luetteloa"/> + <node name="topupAccount" value="Muuta tili (Nyt: %s)"/> + <node name="register" value="Rekisteröidy"/> + <node name="passwordRecovery" value="Palauta salasana"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Hakutulokset"/> + <node name="expandTree" value="Näytä tulokset"/> + <node name="collapseTree" value="Piilota tulokset"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Näytä kirjat"/> + <node name="collapseTree" value="Piilota kirjat"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Näytä kirjat"/> + <node name="collapseTree" value="Piilota kirjat"/> + </node> + <node name="bookNode"> + <node name="read" value="Lue paikallista kopiota"/> + <node name="delete" value="Poista paikallinen kopio"/> + <node name="download" value="Lataa"/> + <node name="readDemo" value="Lue demo"/> + <node name="downloadDemo" value="Lataa demo"/> + <node name="demo" value="demo"/> + <node name="buy" value="Osta (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Kirjan tiedot..."/> + <node name="toc" value="Sisällysluettelo"/> + <node name="showLibrary" value="Avaa kirjasto"/> + <node name="showNetLibrary" value="Verkkokirjasto"/> + <node name="addBook" value="Avaa tiedosto..."/> + <node name="showRecent" value="Viimeisimmät kirjat"/> + <node name="library" value="Kirjasto"> + <node name="showLibrary" value="Avaa kirjasto"/> + <node name="previousBook" value="Edellinen kirja"/> + <node name="showRecent" value="Viimeisimmät kirjat"/> + <node name="addBook" value="Lisää kirja..."/> + <node name="showHelp" value="Tietoja TDE-Ebook-Readerista"/> + </node> + <node name="gotoHome" value="Siirry dokumentin alkuun"/> + <node name="gotoPageNumber" value="Siirry sivulle..."/> + <node name="gotoSectionStart" value="Siirry tekstiosion alkuun"/> + <node name="gotoSectionEnd" value="Siirry tekstiosion loppuun"/> + <node name="nextTOCSection" value="Sisällysluettelon seuraavaan kohtaan"/> + <node name="previousTOCSection" value="Sisällysluettelon edelliseen kohtaan"/> + <node name="navigate" value="Navigoi"> + <node name="gotoHome" value="Siirry dokumentin alkuun"/> + <node name="gotoPageNumber" value="Siirry sivulle..."/> + <node name="gotoSectionStart" value="Siirry tekstiosion alkuun"/> + <node name="gotoSectionEnd" value="Siirry tekstiosion loppuun"/> + <node name="nextTOCSection" value="Sisällysluettelon seuraavaan kohtaan"/> + <node name="previousTOCSection" value="Sisällysluettelon edelliseen kohtaan"/> + <node name="undo" value="Siirry edelliseen kohtaan"/> + <node name="redo" value="Siirry eteenpäin"/> + </node> + <node name="selection" value="Valinta"> + <node name="copyToClipboard" value="Kopioi leikepöydälle"/> + <node name="openInDictionary" value="Avaa sanakirjassa"/> + <node name="clearSelection" value="Tyhjennä"/> + </node> + <node name="search" value="Etsi"> + <node name="search" value="Etsi teksti..."/> + <node name="findNext" value="Etsi seuraava"/> + <node name="findPrevious" value="Etsi edellinen"/> + </node> + <node name="view" value="Näytä"> + <node name="rotate" value="Kierrä näyttö"/> + <node name="toggleFullscreen" value="Koko näyttö"/> + <node name="toggleIndicator" value="Sijainninilmaisin"/> + </node> + <node name="preferences" value="Asetusvalikko..."/> + <node name="quit" value="Sulje"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Lue kirja"/> + <node name="tooltip" value="Näytä lukutila"/> + </node> + <node name="showLibrary"> + <node name="label" value="Kirjasto"/> + <node name="tooltip" value="Näytä kirjastopuu"/> + <node name="popup" value="Näytä viimeisimmät kirjat lista"/> + </node> + <node name="showRecent"> + <node name="label" value="Viimeisimmät kirjat"/> + <node name="tooltip" value="Näytä viimeisimmät kirjat"/> + </node> + <node name="byAuthor"> + <node name="label" value="Tekijä"/> + <node name="tooltip" value="Lajittele kirjat tekijän mukaan"/> + </node> + <node name="byTag"> + <node name="label" value="Luokka"/> + <node name="tooltip" value="Lajittele kirjat luokan mukaan"/> + </node> + <node name="addBook"> + <node name="label" value="Lisää tiedosto"/> + <node name="tooltip" value="Lisää tiedosto kirjastoon"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Verkko"/> + <node name="tooltip" value="Etsi verkkokirjastoista"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Yksinkertainen haku"/> + <node name="tooltip" value="Verkkohaku"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Etsi"/> + <node name="tooltip" value="Tarkennettu verkkohaku"/> + </node> + <node name="gotoHome"> + <node name="label" value="Siirry alkuun"/> + <node name="tooltip" value="Siirry tekstin alkuun"/> + </node> + <node name="undo"> + <node name="label" value="Siirry takaisin"/> + <node name="tooltip" value="Siirry edelliseen kohtaan"/> + </node> + <node name="redo"> + <node name="label" value="Siirry eteenpäin"/> + <node name="tooltip" value="Siirry eteenpäin"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Siirry sivulle"/> + <node name="tooltip" value="Siirry sivulle"/> + </node> + <node name="toc"> + <node name="label" value="Sisällys"/> + <node name="tooltip" value="Sisällysluettelo"/> + </node> + <node name="search"> + <node name="label" value="Etsi"/> + <node name="tooltip" value="Etsi teksti"/> + </node> + <node name="findNext"> + <node name="label" value="Seuraava"/> + <node name="tooltip" value="Etsi seuraava"/> + </node> + <node name="findPrevious"> + <node name="label" value="Edellinen"/> + <node name="tooltip" value="Etsi edellinen"/> + </node> + <node name="rotate"> + <node name="label" value="Kierrä"/> + <node name="tooltip" value="Kierrä teksti"/> + </node> + <node name="showHelp"> + <node name="label" value="Tietoja"/> + <node name="tooltip" value="Tietoja TDE-Ebook-Readerista"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Suodatin"/> + <node name="tooltip" value="Suodatin"/> + </node> + <node name="preferences"> + <node name="label" value="Edellinen asetusvalikko"/> + <node name="tooltip" value="Näytä viimeksi avattu asetusvalikko"/> + </node> + <node name="bookInfo"> + <node name="label" value="Kirjan tiedot"/> + <node name="tooltip" value="Näytä kirjan tiedot valintaikkuna"/> + </node> + <node name="libraryOptions"> + <node name="label" value="Kirjaston asetukset"/> + <node name="tooltip" value="Näytä kirjaston asetusvalikko"/> + </node> + <node name="networkOptions"> + <node name="label" value="Verkkoasetukset"/> + <node name="tooltip" value="Näytä verkkoasetusten valikko"/> + </node> + <node name="systemOptions"> + <node name="label" value="Näytä järjestelmäasetukset"/> + <node name="tooltip" value="Näytä järjestelmäasetusten valikko"/> + </node> + <node name="readingOptions"> + <node name="label" value="Lukuasetukset"/> + <node name="tooltip" value="Näytä lukuasetusten valikko"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" value="Ulkoasun asetukset"/> + <node name="tooltip" value="Näytä ulkoasuasetusten valikko"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Siirry"/> + <node name="thisOnly" value="Vain tämä"/> + <node name="withSubtags" value="Alaluokalliset"/> + <node name="removeLink" value="Poista kirjastosta"/> + <node name="removeFile" value="Poista levyltä"/> + <node name="yesToAll" value="Kyllä &kaikkiin"/> + <node name="buy" value="&Osta"/> + <node name="buyAndDownload" value="Osta ja &lataa"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Kirjaston asetukset"/> + <node name="tab"> + <node name="Library" value="Kirjasto"> + <node name="bookPath" value="Kirjaston hakemisto"/> + <node name="lookInSubdirectories" value="Hae kirjoja alihakemistoista"/> + <node name="collectBooksWithoutMetaInfo" value="Ryhmitä ilman metatietoja olevat kirjat"/> + <node name="downloadDirectory" value="Ladattujen kirjojen hakemisto"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Verkkoasetukset"/> + <node name="tab"> + <node name="NetworkLibrary" value="Verkkohaku"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Käytä välityspalvelinta"/> + <node name="proxyHost" value="Välityspalvelimen osoite"/> + <node name="proxyPort" value="Välityspalvelimen portti"/> + <node name="timeout" value="Verkkotoimintojen aikakatkaisu sekunteina"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Ulkoisten linkkien avaus: %s"/> + <node name="defaultText" value="Avaa ulkoiset linkit selaimessa"/> + <node name="choice" value="Käytä selainta"/> + <node name="command" value="Suorituskomento"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Järjestelmäasetukset"/> + <node name="tab"> + <node name="Language" value="Kieli"> + <node name="autoDetect" value="Tunnista kieli ja merkistö automaattisesti"/> + <node name="defaultLanguage" value="Oletuskieli"/> + <node name="defaultEncodingSet" value="Oletusmerkistöalue"/> + <node name="defaultEncoding" value="Oletusmerkistö"/> + <node name="useWindows1252Hack" value="Käytä windows-1252 merkistöä iso-8859-1 sijaan"/> + </node> + <node name="Config" value="Tila"> + <node name="autoSave" value="Tallenna tila automaattisesti"/> + <node name="timeout" value="Tallennusvälin aika sekunneissa"/> + </node> + <node name="Dictionary" value="Sanakirja"> + <node name="enableIntegration" value="Käytä sanakirjaa: %s"/> + <node name="defaultText" value="Käytettävä sanakirja"/> + <node name="choice" value="Integroi seuraavan kanssa:"/> + <node name="singleClickOpen" value="Avaa yhdellä kosketuksella"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Toiminta näppäimen vapautuksesta painalluksen sijaan"/> + <node name="minStylusPressure" value="Styluksen minimi paine"/> + <node name="maxStylusPressure" value="Styluksen maksimi paine"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Lukuasetukset"/> + <node name="tab"> + <node name="Scrolling" value="Vieritys"> + <node name="keyScrollDelay" value="Näppäinvierityksen painnallusten viive, msecs"/> + <node name="keyLinesToScroll" value="Vieritettävien rivien määtä rivi rivivierityksessä"/> + <node name="keyLinesToKeep" value="Säilytettävät rivit sivuvierityksessä"/> + <node name="enableTapScrolling" value="Ota käyttöön kosketusvieritys"/> + <node name="fingerOnly" value="Vieritä ainoastaan kosketuksesta"/> + </node> + <node name="Selection" value="Valinta"> + <node name="enableSelection" value="Ota käyttöön tekstinvalinta"/> + </node> + <node name="Indicator" value="Ilmaisin"> + <node name="type" value="Näytä"> + <node name="osScrollbar" value="Vierityspalkki"/> + <node name="fbIndicator" value="Perinteinen ilmaisin"/> + <node name="none" value="Ei ilmaisinta"/> + </node> + <node name="height" value="Ilmaisimen korkeus"/> + <node name="offset" value="Etäisyys tekstistä"/> + <node name="pageNumber" value="Näytä sijainti numeroina"/> + <node name="time" value="Näytä aika"/> + <node name="fontSize" value="Kirjasinkoko"/> + <node name="tocMarks" value="Näytä sisällysmerkit"/> + <node name="navigation" value="Salli navigointi"/> + </node> + <node name="Rotation" value="Kierto"> + <node name="direction" value="Kiertämistapa"> + <node name="disabled" value="Pois käytöstä"/> + <node name="clockwise" value="90 astetta myötäpäivään"/> + <node name="counterclockwise" value="90 astetta vastapäivään"/> + <node name="180" value="180 astetta"/> + <node name="cycle" value="Kierrä neljä suuntaa"/> + </node> + </node> + <node name="Keys" value="Näppäimet"> + <node name="grabSystemKeys" value="Valitse järjestelmänäppäimet"/> + <node name="separate" value="Näytön suunnasta riippuvat näppäintoiminnot"/> + <node name="orientation" value="Näytön suuntaus"> + <node name="degrees0" value="0 astetta"/> + <node name="degrees90ccw" value="90 astetta vastapäivään"/> + <node name="degrees180" value="180 astetta"/> + <node name="degrees90cw" value="90 astetta myötäpäivään"/> + </node> + <node name="action"> + <node name="none" value="Ei mitään"/> + <node name="showLibrary" value="Näytä kirjasto"/> + <node name="showNetLibrary" value="Näytä verkkokirjasto"/> + <node name="showRecent" value="Näytä viimeisimmät kirjat"/> + <node name="previousBook" value="Avaa edellinen kirja"/> + <node name="toc" value="Näytä sisällysluettelo"/> + <node name="gotoHome" value="Siirry alkuun"/> + <node name="gotoSectionStart" value="Siirry tekstiosion alkuun"/> + <node name="gotoSectionEnd" value="Siirry tekstiosion loppuun"/> + <node name="nextTOCSection" value="Sisällysluettelon seuraavaan kohtaan"/> + <node name="previousTOCSection" value="Sisällysluettelon edelliseen kohtaan"/> + <node name="pageForward" value="Vieritä sivu eteenpäin"/> + <node name="pageBackward" value="Vieritä sivu taaksepäin"/> + <node name="lineForward" value="Vieritä rivi eteenpäin"/> + <node name="lineBackward" value="Vieritä rivi taaksepäin"/> + <node name="undo" value="Peru"/> + <node name="redo" value="Palauta"/> + <node name="copyToClipboard" value="Kopioi valittu teksti leikepöydälle"/> + <node name="openInDictionary" value="Avaa valittu teksti sanakirjassa"/> + <node name="clearSelection" value="Tyhjennä valinta"/> + <node name="search" value="Etsi"/> + <node name="findPrevious" value="Etsi edellinen"/> + <node name="findNext" value="Etsi seuraava"/> + <node name="increaseFont" value="Suurenna kirjasinkokoa"/> + <node name="decreaseFont" value="Pienennä kirjasinkokoa"/> + <node name="toggleIndicator" value="Sijainninilmaisin päällä/pois"/> + <node name="toggleFullscreen" value="Koko näyttö päällä/pois"/> + <node name="rotate" value="Kierrä näyttöä"/> + <node name="addBook" value="Lisää kirja"/> + <node name="cancel" value="Peru"/> + <node name="quit" value="Lopeta"/> + <node name="bookInfo" value="Näytä kirjantiedot valintaikkuna"/> + <node name="preferences" value="Näytä viimeksi avattu asetusvalikko"/> + </node> + <node name="quitOnCancel" value="Sulje sovellus peruttaessa"/> + <node name="keyDelay" value="Hyväksyttyjen näppäinpainallusten viive"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Ulkoasun asetukset"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Käytä aina omaa kirjasinta"/> + </node> + <node name="Margins" value="Reunus"> + <node name="left" value="Vasenreunus"/> + <node name="right" value="Oikeareunus"/> + <node name="top" value="Yläreunus"/> + <node name="bottom" value="Alareunus"/> + </node> + <node name="Format" value="Muotoilu"> + <node name="optionsFor" value="Asetukset"/> + <node name="lineSpacing" value="Riviväli"> + <node name="unchanged" value="<ei muutosta>"/> + </node> + <node name="firstLineIndent" value="1. rivin sisennys"/> + <node name="alignment" value="Tasaus"> + <node name="left" value="Vasen"/> + <node name="right" value="Oikea"/> + <node name="center" value="Keskitetty"/> + <node name="justify" value="Tasattu"/> + <node name="unchanged" value="<ei muutosta>"/> + </node> + <node name="spaceBefore" value="Väli ennen"/> + <node name="spaceAfter" value="Väli jälkeen"/> + <node name="startIndent" value="Rivin alun sisennys"/> + <node name="endIndent" value="Rivin lopun sisennys"/> + </node> + <node name="Styles" value="Tyylit"> + <node name="optionsFor" value="Asetukset"/> + <node name="fontFamily" value="Kirjasinperhe"> + <node name="unchanged" value="<ei muutosta>"/> + </node> + <node name="fontSize" value="Koko"/> + <node name="fontSizeDifference" value="Koon ero"/> + <node name="bold" value="Lihavoitu"/> + <node name="italic" value="Kursivoitu"/> + <node name="allowHyphenations" value="Salli tavutus"/> + <node name="autoHyphenations" value="Automaattinen tavutus"/> + </node> + <node name="Colors" value="Värit"> + <node name="colorFor" value="Värit"> + <node name="background" value="Taustalle"/> + <node name="selectionBackground" value="Valitun tekstin taustalle"/> + <node name="text" value="Normaalille tekstille"/> + <node name="internalLink" value="Sisäisen linkin tekstille"/> + <node name="externalLink" value="Ulkoisen linkin tekstille"/> + <node name="bookLink" value="Linkille toiseen kirjaan"/> + <node name="highlighted" value="Korostetulle tekstille"/> + <node name="treeLines" value="Kirjastopuun viivoille"/> + <node name="indicator" value="Sijainninilmaisimelle"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Kirjan tiedot"/> + <node name="tab"> + <node name="Common" value="Yleiset"> + <node name="file" value="Tiedosto"/> + <node name="title" value="Nimi"/> + <node name="language" value="Kieli"/> + <node name="encodingSet" value="Merkistöalue"/> + <node name="encoding" value="Merkistö"/> + </node> + <node name="Authors" value="Tekijät"> + <node name="authorDisplayName" value="Tekijän nimi"/> + </node> + <node name="Series" value="Kirjasarja"> + <node name="seriesTitle" value="Sarjan nimi"/> + <node name="bookIndex" value="Kirjan numero"/> + </node> + <node name="Tags" value="Luokka"> + <node name="tags" value="Luokan nimi"/> + </node> + <node name="Text" value="Teksti"> + <node name="breakType" value="Katkaise kappale"/> + <node name="ignoreIndent" value="Hylkää pienempi sisennys kuin"/> + <node name="buildTOC" value="Luo sisällysluettelo"/> + <node name="emptyLines" value="Tyhjät rivit ennen uutta osaa"/> + </node> + <node name="<PRE>" value="<ESI>"> + <node name="breakType" value="Katkaise kappale"/> + <node name="ignoreIndent" value="Hylkää pienempi sisennys kuin"/> + <node name="buildTOC" value="Luo sisällysluettelo"/> + <node name="emptyLines" value="Tyhjät rivit ennen uutta osaa"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Tekijän tiedot"/> + <node name="name" value="Tekijän nimi"/> + <node name="sortKey" value="Tekijän lajitteluavain"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Lisää kirja kirjastoon"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Etsi teksti"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Älä huomioi kirjainkokoa"/> + <node name="wholeText" value="K&oko tekstistä"/> + <node name="backward" value="&Taaksepäin"/> + <node name="currentSection" value="&Vain tästä osasta"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Verkkohaku"/> + <node name="titleAndSeries" value="Nimi/Sarja"/> + <node name="author" value="Tekijä"/> + <node name="category" value="Kategoria"/> + <node name="description" value="Kuvaus"/> + <node name="annotation" value="Hakutulokset haulle: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Siirry sivulle"/> + <node name="pageNumber" value="Siirry sivunumerolle"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Muokkaa luokka"/> + <node name="name" value="Luokan nimi"/> + <node name="includeSubtags" value="Sisällytä alaluokat"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Kloonaa luokka"/> + <node name="name" value="Luokan nimi"/> + <node name="includeSubtags" value="Sisällytä alaluokat"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Poista kirja"/> + <node name="message" value="Poista "%s" kirjastosta?"/> + <node name="deleteFile" value="Oletko varma, että haluat poistaa tiedoston “%s†levyltä?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Poista luokka"/> + <node name="message" value="Poista luokka “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Virhe"/> + <node name="message" value="Ei voitu avata: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Virhe"/> + <node name="message" value="Ei voitu poistaa tiedostoa %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Virhe"/> + <node name="message" value="Ohjetiedostoa ei löytynyt"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Tyhjä kirjastolista"/> + <node name="authenticationFailed" value="Autentikointi epäonnistui"/> + <node name="internalError" value="Sisäinen palvelinvirhe"/> + <node name="purchaseNotEnoughMoney" value="Ei tarpeeksi rahaa"/> + <node name="purchaseMissingBook" value="Puuttuva kirja"/> + <node name="purchaseAlreadyPurchased" value="Jo ostettu"/> + <node name="bookNotPurchased" value="Kirjaa ei ostettu"/> + <node name="downloadLimitExceeded" value="Latausrajoitus ylitetty"/> + <node name="unsupportedOperation" value="Toimintoa ei tuettu"/> + <node name="loginAlreadyTaken" value="Käyttäjänimi on jo käytössä"/> + <node name="loginNotSpecified" value="Syötä käyttäjänimi"/> + <node name="passwordNotSpecified" value="Syötä salasana"/> + <node name="emailNotSpecified" value="Syötä sähköpostiosoite"/> + <node name="invalidEMail" value="Virheellinen sähköpostiosoite"/> + <node name="tooManyRegistrations" value="Liian monta rekisteröintiä IP-osoitteestasi; yritä udelleen muutaman minuutin kuluttua"/> + <node name="noUserEmail" value="Käyttäjää ei ole rekisteröity kyseiselle sähköpostiosoitteelle"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Virhe latauksessa"/> + <node name="message" value="Kirjaa ei voida ladata tällähekellä"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Avataan kirjaa..."/> + <node name="loadingBookList" value="Avataan kirjalistaa..."/> + <node name="migrate" value="Päivitetään uuteen versioon. Ole hyvä ja odota..."/> + <node name="downloadBookList" value="Ladataan kirjalistaa. Ole hyvä ja odota..."/> + <node name="downloadBook" value="Ladataan kirjaa. Ole hyvä ja odota..."/> + <node name="downloadImages" value="Ladataan kuvia. Ole hyvä ja odota..."/> + <node name="authentication" value="Tunnistaudutaan. Ole hyvä ja odota..."/> + <node name="purchaseBook" value="Ostetaan kirjaa. Ole hyvä ja odota..."/> + <node name="initializeAuthenticationManager" value="Ladataan tilin tietoja. Ole hyvä ja odota..."/> + <node name="loadSubCatalog" value="Ladataan luetteloa. Ole hyvä ja odota..."/> + <node name="registerUser" value="Rekisteröidään uutta tiliä. Ole hyvä ja odota..."/> + <node name="passwordRecovery" value="Palautetaan salasanaa. Ole hyvä ja odota..."/> + <node name="authenticationCheck" value="Tilin varmistus. Ole hyvä ja odota..."/> + <node name="signOut" value="Kirjaudutaan ulos. Ole hyvä ja odota..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Osta kirja"/> + <node name="message" value="Oletko varma, että haluat ostaa kirjan “%s†?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Tunnistautuminen"/> + <node name="login" value="Käyttäjänimi"/> + <node name="password" value="Salasana"/> + <node name="skipIP" value="Älä sido IP-osoitteeseen"/> + <node name="loginIsEmpty" value="Käyttäjänimi ei saa olla tyhjä"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Tietoja"/> + <node name="message" value="Luettelo on tyhjä."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Poista luettelo käytöstä"/> + <node name="message" value="Oletko varma, että haluat poistaa luettelon “%s†käytöstä? Voit ottaa sen uudelleen käyttöön asetusten “Verkkohaku†välilehdellä."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Poista kirja"/> + <node name="message" value="Oletko varma, että haluat poistaa kirjan “%s†levyltä?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Rekisteröi käyttäjä"/> + <node name="login" value="Käyttäjänimi"/> + <node name="password" value="Salasana"/> + <node name="confirmPassword" value="Vahvista salasana"/> + <node name="email" value="Sähköpostiosoite"/> + <node name="differentPasswords" value="Salasanat ei täsmää."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Salasanan palautus"/> + <node name="email" value="Sähköpostiosoite"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Salasanan palautus"/> + <node name="message" value="Viesti tarvittavilla jatkotoiminpiteillä on lähetetty osoiteeseen %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Latausvirhe"/> + <node name="message" value="Ei voida avata ladattua tiedostoa %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Perustekstille"/> + <node name="Regular Paragraph" value="Normaalille kappaleelle"/> + <node name="Title" value="Otsikolle"/> + <node name="Section Title" value="Valinnan otsikolle"/> + <node name="Poem Title" value="Runon otsikolle"/> + <node name="Subtitle" value="Alaotsikolle"/> + <node name="Annotation" value="Huomautukselle"/> + <node name="Epigraph" value="Epigraphille"/> + <node name="Stanza" value="Säkeistölle"/> + <node name="Verse" value="Jakeelle"/> + <node name="Preformatted text" value="Esimuotoillulle tekstille"/> + <node name="Image" value="Kuvalle"/> + <node name="Cite" value="Lainaukselle"/> + <node name="Author" value="Tekijälle"/> + <node name="Date" value="Päivämäärälle"/> + <node name="Internal Hyperlink" value="Sisäiselle linkille"/> + <node name="Footnote" value="Alaviitteelle"/> + <node name="Emphasis" value="Korostukselle"/> + <node name="Strong" value="Vahvennetulle"/> + <node name="Subscript" value="Viitteelle"/> + <node name="Superscript" value="Yläviitteelle"/> + <node name="Code" value="Koodille"/> + <node name="StrikeThrough" value="Yliviivatulle"/> + <node name="Contents Table" value="Sisällysluettelolle"/> + <node name="Library Entry" value="Kirjaston merkinnälle"/> + <node name="Recent Book List" value="Viimeisimmät kirjat listalle"/> + <node name="Italic" value="Kursivoidulle"/> + <node name="Bold" value="Lihavoidulle"/> + <node name="Definition" value="Määrittelylle"/> + <node name="Definition Description" value="Määrittelyn kuvaukselle"/> + <node name="Header 1" value="Otsikolle 1"/> + <node name="Header 2" value="Otsikolle 2"/> + <node name="Header 3" value="Otsikolle 3"/> + <node name="Header 4" value="Otsikolle 4"/> + <node name="Header 5" value="Otsikolle 5"/> + <node name="Header 6" value="Otsikolle 6"/> + <node name="External Hyperlink" value="Ulkoiselle linkille"/> + <node name="Link to Another Book" value="Linkille "/> + </node> + <node name="external"> + <node name="browser" value="Selain"/> + <node name="defaultBrowser" value="Oletusselain"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Tuntematon virhe"/> + <node name="unsupportedCompressionMethod" value="Tiivistysmuodolle ei tukea"/> + <node name="encryptedFile" value="Digitaalisesti suojattu tiedosto"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Verkkokirjasto"/> + </node> + <node name="library"> + <node name="caption" value="Kirjasto"/> + </node> +</resources> diff --git a/reader/data/resources/fr.xml b/reader/data/resources/fr.xml new file mode 100644 index 0000000..922580d --- /dev/null +++ b/reader/data/resources/fr.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- French TDE-Ebook-Reader resources, by Pierre Senellart --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Afficher les livres"/> + <node name="collapseTree" value="Masquer les livres"/> + <node name="edit" value="Éditer l'information"/> + <node name="unknownAuthor" value="Auteur inconnu"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Afficher les livres"/> + <node name="collapseTree" value="Masquer les livres"/> + <node name="edit" value="Éditer le tag"/> + <node name="clone" value="Cloner le tag"/> + <node name="delete" value="Supprimer le tag"/> + <node name="noTags" value="Livres sans tags"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Afficher les livres"/> + <node name="collapseTree" value="Masquer les livres"/> + </node> + <node name="bookNode"> + <node name="read" value="Lire le livre"/> + <node name="edit" value="Éditer l'information"/> + <node name="delete" value="Supprimer le livre"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Par auteur"> + <node name="summary" value="Livres triés par auteur"/> + </node> + <node name="byTitle" value="Par titre"> + <node name="summary" value="Livres triés par titre"/> + </node> + <node name="byDate" value="Par date"> + <node name="summary" value="Livres triés par date d'achat"/> + </node> + <node name="bySeries" value="Par série"> + <node name="summary" value="Livres triés par série"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Ouvrir"/> + <node name="collapseTree" value="Refermer"/> + <node name="reload" value="Recharger"/> + <node name="openInBrowser" value="Ouvrir dans un navigateur"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Ouvrir le catalogue"/> + <node name="collapseTree" value="Fermer le catalogue"/> + <node name="login" value="Connexion"/> + <node name="logout" value="Déconnexion (%s)"/> + <node name="reload" value="Recharger"/> + <node name="dontShow" value="Ne pas montrer ce catalogue"/> + <node name="topupAccount" value="Recréditer le compte (actuellement : %s)"/> + <node name="register" value="Inscription"/> + <node name="passwordRecovery" value="Récupérer le mot de passe"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Résultats de la recherche"/> + <node name="expandTree" value="Afficher les résultats"/> + <node name="collapseTree" value="Masquer les résultats"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Afficher les livres"/> + <node name="collapseTree" value="Masquer les livres"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Afficher les livres"/> + <node name="collapseTree" value="Masquer les livres"/> + </node> + <node name="bookNode"> + <node name="read" value="Lire la copie locale"/> + <node name="delete" value="Supprimer la copie locale"/> + <node name="download" value="Télécharger"/> + <node name="readDemo" value="Lire l'extrait"/> + <node name="downloadDemo" value="Télécharger l'extrait"/> + <node name="demo" value="l'extrait"/> + <node name="buy" value="Acheter (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informations sur le livre..."/> + <node name="toc" value="Table des matières"/> + <node name="showLibrary" value="Ouvrir la bibliothèque"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Bibliothèque"> + <node name="showLibrary" value="Ouvrir"/> + <node name="previousBook" value="Livre précédent"/> + <node name="showRecent" value="Récents"/> + <node name="addBook" value="Ajouter un livre..."/> + <node name="showHelp" value="À propos de TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Aller au début du document"/> + <node name="gotoPageNumber" value="Aller page..."/> + <node name="gotoSectionStart" value="Aller au début de la section"/> + <node name="gotoSectionEnd" value="Aller à la fin de la section"/> + <node name="nextTOCSection" value="Aller à l'entrée suivante de la TDM"/> + <node name="previousTOCSection" value="Aller à l'entrée précédente de la TDM"/> + <node name="navigate" value="Navigation"> + <node name="gotoHome" value="Aller au début du document"/> + <node name="gotoPageNumber" value="Aller page..."/> + <node name="gotoSectionStart" value="Aller au début de la section"/> + <node name="gotoSectionEnd" value="Aller à la fin de la section"/> + <node name="nextTOCSection" value="Aller à l'entrée suivante de la TDM"/> + <node name="previousTOCSection" value="Aller à l'entrée précédente de la TDM"/> + <node name="undo" value="Précédent"/> + <node name="redo" value="Suivant"/> + </node> + <node name="selection" value="Sélection"> + <node name="copyToClipboard" value="Copier dans le presse-papier"/> + <node name="openInDictionary" value="Ouvrir dans le dictionnaire"/> + <node name="clearSelection" value="Effacer"/> + </node> + <node name="search" value="Recherche"> + <node name="search" value="Rechercher le texte..."/> + <node name="findNext" value="Rechercher suivant"/> + <node name="findPrevious" value="Rechercher précédent"/> + </node> + <node name="view" value="Affichage"> + <node name="rotate" value="Tourner l'écran"/> + <node name="toggleFullscreen" value="Plein écran"/> + <node name="toggleIndicator" value="Afficher/Masquer l'indicateur"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Fermer"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="Afficher le mode de lecture"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Afficher l'arbre de la bibliothèque"/> + <node name="popup" value="Afficher la liste des livres récents"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Afficher la liste des livres récents"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="Classer les livres par auteur"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="Classer les livres par tag"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Ajouter un livre à la bibliothèque"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="Recherche dans bibliothèques réseau"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Recherche réseau"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Recherche réseau avancée"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Aller au début du texte"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="Précédent"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Suivant"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="Aller page"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Table des matières"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Rechercher"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Rechercher suivant"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Rechercher précédent"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Tourner l'écran"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="À propos de TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Afficher les informations sur le livre"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="O&k"/> + <node name="thisOnly" value="Seulement ceci"/> + <node name="withSubtags" value="Sous-tags compris"/> + <node name="removeLink" value="Supprimer de la bibliothèque"/> + <node name="removeFile" value="Supprimer du disque"/> + <node name="yesToAll" value="Oui à &tout"/> + <node name="buy" value="&Acheter"/> + <node name="buyAndDownload" value="Acheter et &télécharger"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Bibliothèque"> + <node name="bookPath" value="Chemin des livres"/> + <node name="lookInSubdirectories" value="Chercher des livres dans les sous-répertoires"/> + <node name="collectBooksWithoutMetaInfo" value="Rassembler les livres sans métainformation"/> + <node name="downloadDirectory" value="Répertoire des livres téléchargés"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Recherche réseau"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Utiliser un proxy"/> + <node name="proxyHost" value="Serveur proxy"/> + <node name="proxyPort" value="Port du proxy"/> + <node name="timeout" value="Délai réseau maximal, secondes"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Ouvrir les liens externes dans %s"/> + <node name="defaultText" value="Ouvrir les liens externes dans le navigateur"/> + <node name="choice" value="Utiliser le navigateur"/> + <node name="command" value="Commande à exécuter"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Langue"> + <node name="autoDetect" value="Detecter la langue et l'encodage automatiquement"/> + <node name="defaultLanguage" value="Langue par défaut "/> + <node name="defaultEncodingSet" value="Ensemble d'encodages par défaut"/> + <node name="defaultEncoding" value="Encodage par défaut"/> + <node name="useWindows1252Hack" value="Utiliser windows-1252 au lieu de iso-8859-1"/> + </node> + <node name="Config" value="Configuration"> + <node name="autoSave" value="Enregistrer l'état automatiquement"/> + <node name="timeout" value="Délai entre les enregistrements en secondes"/> + </node> + <node name="Dictionary" value="Dictionnaire"> + <node name="enableIntegration" value="Activer l'intégration avec %s"/> + <node name="defaultText" value="Activer l'intégration avec le dictionnaire"/> + <node name="choice" value="Intégration avec"/> + <node name="singleClickOpen" value="Ouvrir avec un simple clic"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Action au relâchement de la touche, pas à l'appui"/> + <node name="minStylusPressure" value="Pression minimale du stylet"/> + <node name="maxStylusPressure" value="Pression maximale du stylet"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Défilement"> + <node name="keyScrollDelay" value="Délai entre défilement par touche, msec"/> + <node name="keyLinesToScroll" value="Lignes à défiler par défilement de ligne"/> + <node name="keyLinesToKeep" value="Lignes à conserver par défilement de page"/> + <node name="enableTapScrolling" value="Activer le défilement par pression"/> + <node name="fingerOnly" value="Défiler seulement avec le doigt"/> + </node> + <node name="Selection" value="Sélection"> + <node name="enableSelection" value="Activer la sélection de texte"/> + </node> + <node name="Indicator" value="Indicateur"> + <node name="type" value="Afficher comme"> + <node name="osScrollbar" value="Barre de défilement"/> + <node name="fbIndicator" value="Indicateur ancien style"/> + <node name="none" value="Ne pas afficher"/> + </node> + <node name="height" value="Hauteur de l'indicateur"/> + <node name="offset" value="Décalage par rapport au texte"/> + <node name="pageNumber" value="Montrer les numéros de page"/> + <node name="time" value="Afficher l'heure"/> + <node name="fontSize" value="Taille de la police"/> + <node name="tocMarks" value="Afficher les marques de la TDM"/> + <node name="navigation" value="Autoriser la navigation"/> + </node> + <node name="Rotation" value="Rotation"> + <node name="direction" value="Type de rotation"> + <node name="disabled" value="Désactivée"/> + <node name="clockwise" value="90° (sens des aiguilles)"/> + <node name="counterclockwise" value="90° (sens inverse des aiguilles)"/> + <node name="180" value="180°"/> + <node name="cycle" value="Parcourt les 4 directions"/> + </node> + </node> + <node name="Keys" value="Touches"> + <node name="grabSystemKeys" value="Capturer les touches systèmes"/> + <node name="separate" value="Les touches dépendent de l'orientation"/> + <node name="orientation" value="Orientation"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Aucune"/> + <node name="showLibrary" value="Afficher la bibliothèque"/> + <node name="showNetLibrary" value="Afficher la bibliothèque réseau"/> + <node name="showRecent" value="Afficher les livres récents"/> + <node name="previousBook" value="Ouvrir le livre précédent"/> + <node name="toc" value="Afficher la table des matières"/> + <node name="gotoHome" value="Aller au début"/> + <node name="gotoSectionStart" value="Aller au début de la section"/> + <node name="gotoSectionEnd" value="Aller à la fin de la section"/> + <node name="nextTOCSection" value="Aller à la section précédente de la TDM"/> + <node name="previousTOCSection" value="Aller à la section suivante de la TDM"/> + <node name="pageForward" value="Défiler une page en avant"/> + <node name="pageBackward" value="Défiler une page en arrière"/> + <node name="lineForward" value="Défiler une ligne en avant"/> + <node name="lineBackward" value="Défiler une ligne en arrière"/> + <node name="undo" value="Annuler"/> + <node name="redo" value="Restaurer"/> + <node name="copyToClipboard" value="Copier la sélection dans le presse-papier"/> + <node name="openInDictionary" value="Ouvrir la sélection dans le dictionnaire"/> + <node name="clearSelection" value="Effacer la sélection"/> + <node name="search" value="Rechercher"/> + <node name="findPrevious" value="Rechercher précédent"/> + <node name="findNext" value="Rechercher suivant"/> + <node name="increaseFont" value="Augmenter la taille de la police"/> + <node name="decreaseFont" value="Réduire la taille de la police"/> + <node name="toggleIndicator" value="Afficher/Masquer l'indicateur"/> + <node name="toggleFullscreen" value="Activer/Désactiver le plein écran"/> + <node name="rotate" value="Tourner l'écran"/> + <node name="addBook" value="Ajouter un livre"/> + <node name="cancel" value="Annuler"/> + <node name="quit" value="Quitter"/> + <node name="bookInfo" value="Afficher les informations sur le livre"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Quitter l'application lors d'une annulation"/> + <node name="keyDelay" value="Délai entre appui sur les touches"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Toujours utiliser mes propres polices"/> + </node> + <node name="Margins" value="Marges"> + <node name="left" value="Marge gauche"/> + <node name="right" value="Marge droite"/> + <node name="top" value="Marge haut"/> + <node name="bottom" value="Marge bas"/> + </node> + <node name="Format" value="Format"> + <node name="optionsFor" value="Options pour"/> + <node name="lineSpacing" value="Interligne"> + <node name="unchanged" value="<inchangé>"/> + </node> + <node name="firstLineIndent" value="Alinéa"/> + <node name="alignment" value="Alignement"> + <node name="left" value="Gauche"/> + <node name="right" value="Droite"/> + <node name="center" value="Centré"/> + <node name="justify" value="Justifié"/> + <node name="unchanged" value="<inchangé>"/> + </node> + <node name="spaceBefore" value="Espace avant"/> + <node name="spaceAfter" value="Espace après"/> + <node name="startIndent" value="Retrait de début de ligne"/> + <node name="endIndent" value="Retrait de fin de ligne"/> + </node> + <node name="Styles" value="Styles"> + <node name="optionsFor" value="Options pour"/> + <node name="fontFamily" value="Famille"> + <node name="unchanged" value="<inchangé>"/> + </node> + <node name="fontSize" value="Taille"/> + <node name="fontSizeDifference" value="Différence de taille"/> + <node name="bold" value="Gras"/> + <node name="italic" value="Italique"/> + <node name="allowHyphenations" value="Autoriser la césure"/> + <node name="autoHyphenations" value="Césure automatique"/> + </node> + <node name="Colors" value="Couleurs"> + <node name="colorFor" value="Couleur pour"> + <node name="background" value="Arrière-plan"/> + <node name="selectionBackground" value="Arrière-plan de la sélection"/> + <node name="text" value="Texte normal"/> + <node name="internalLink" value="Hyperlien interne"/> + <node name="externalLink" value="Hyperlien externe"/> + <node name="bookLink" value="Lien vers un autre livre"/> + <node name="highlighted" value="Texte mis en valeur"/> + <node name="treeLines" value="Lignes de l'arbre"/> + <node name="indicator" value="Indicateur de position"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informations sur le livre"/> + <node name="tab"> + <node name="Common" value="Général"> + <node name="file" value="Fichier"/> + <node name="title" value="Titre"/> + <node name="language" value="Langue"/> + <node name="encodingSet" value="Ensemble d'encodages"/> + <node name="encoding" value="Encodage"/> + </node> + <node name="Authors" value="Auteurs"> + <node name="authorDisplayName" value="Nom de l'auteur"/> + </node> + <node name="Series" value="Série"> + <node name="seriesTitle" value="Titre de la série"/> + <node name="bookIndex" value="Numéro du livre"/> + </node> + <node name="Tags" value="Tags"> + <node name="tags" value="Nom du tag"/> + </node> + <node name="Text" value="Texte"> + <node name="breakType" value="Fin des paragraphes"/> + <node name="ignoreIndent" value="Ignorer une indentation inférieure à "/> + <node name="buildTOC" value="Construire la table des matières"/> + <node name="emptyLines" value="Lignes vides avant une nouvelle section"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Fin des paragraphes"/> + <node name="ignoreIndent" value="Ignorer une indentation inférieure à "/> + <node name="buildTOC" value="Construire la table des matières"/> + <node name="emptyLines" value="Lignes vides avant une novuelle section"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Information sur l'auteur"/> + <node name="name" value="Nom de l'auteur"/> + <node name="sortKey" value="Clef de tri de l'auteur"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Ajouter un livre à la bibliothèque"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Rechercher"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignorer la casse"/> + <node name="wholeText" value="&Dans tout le texte"/> + <node name="backward" value="&Vers l'arrière"/> + <node name="currentSection" value="&Cette section seulement"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Recherche réseau"/> + <node name="titleAndSeries" value="Titre/Série"/> + <node name="author" value="Auteur"/> + <node name="category" value="Catégorie"/> + <node name="description" value="Description"/> + <node name="annotation" value="Résultats de la recherche : %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Aller à la page"/> + <node name="pageNumber" value="Aller page"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Édition d'un tag"/> + <node name="name" value="Nom du tag"/> + <node name="includeSubtags" value="Inclure les sous-tags"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Clonage d'un tag"/> + <node name="name" value="Nom du tag"/> + <node name="includeSubtags" value="Inclure les sous-tags"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Suppression d'un livre"/> + <node name="message" value="Supprimer le livre "%s" de la bibliothèque ?"/> + <node name="deleteFile" value="Êtes-vous sûr de vouloir supprimer le fichier « %s » du disque ?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Suppression d'un tag"/> + <node name="message" value="Supprimer le tag « %s »?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Erreur"/> + <node name="message" value="Impossible d'ouvrir %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Erreur"/> + <node name="message" value="Impossible de supprimer le fichier %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Erreur"/> + <node name="message" value="Fichier d'aide non trouvé, désolé"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Liste de bibliothèques vide"/> + <node name="authenticationFailed" value="Authentification échouée"/> + <node name="internalError" value="Erreur interne du serveur"/> + <node name="purchaseNotEnoughMoney" value="Pas assez de crédit"/> + <node name="purchaseMissingBook" value="Livre manquant"/> + <node name="purchaseAlreadyPurchased" value="Déjà acheté"/> + <node name="bookNotPurchased" value="Le livre n'a pas été acheté"/> + <node name="downloadLimitExceeded" value="Limite de téléchargement atteinte"/> + <node name="unsupportedOperation" value="Opération non supportée"/> + <node name="loginAlreadyTaken" value="Identifiant déjà utilisé"/> + <node name="loginNotSpecified" value="Veuillez entrer un identifiant"/> + <node name="passwordNotSpecified" value="Veuillez entrer un mot de passe non vide"/> + <node name="emailNotSpecified" value="Veuillez entrer une adresse email"/> + <node name="invalidEMail" value="Adresse email invalide"/> + <node name="tooManyRegistrations" value="Trop d'inscriptions depuis votre IP ; essayer à nouvea dans quelques minutes"/> + <node name="noUserEmail" value="Aucun utilisateur n'est inscrit avec l'adresse email indiquée"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Erreur de téléchargement"/> + <node name="message" value="Impossible de télécharger ce livre en ce moment"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Chargement du livre. Veuillez patienter..."/> + <node name="loadingBookList" value="Chargement de la liste des livres. Veuillez patienter..."/> + <node name="migrate" value="Mise à jour en cours. Veuillez patienter..."/> + <node name="downloadBookList" value="Téléchargement de la liste de livres en cours. Veuillez patienter..."/> + <node name="downloadBook" value="Téléchargement du livre. Veuillez patienter..."/> + <node name="downloadImages" value="Téléchargement des images. Veuillez patienter..."/> + <node name="authentication" value="Authentification. Veuillez patienter..."/> + <node name="purchaseBook" value="Achat du livre. Veuillez patienter..."/> + <node name="initializeAuthenticationManager" value="Téléchargement des informations du compte. Veuillez patienter..."/> + <node name="loadSubCatalog" value="Chargement du catalogue. Veuillez patienter..."/> + <node name="registerUser" value="Inscription en cours. Veuillez patienter..."/> + <node name="passwordRecovery" value="Récupération du mot de passe. Veuillez patienter..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Achat du livre"/> + <node name="message" value="Êtes-vous sûr de vouloir acheter le livre « %s » ?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Authentification"/> + <node name="login" value="Identifiant"/> + <node name="password" value="Mot de passe"/> + <node name="skipIP" value="Ne pas associer à l'adresse IP"/> + <node name="loginIsEmpty" value="L'identifiant ne doit pas être vide"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Information"/> + <node name="message" value="Le catalogue est vide."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Désactivation du catalogue"/> + <node name="message" value="Êtes-vous sûr de vouloir désactiver le catalogue « %s » ? Vous pouvez l'activer dans l'avenir avec l'onglet « Recherche réseau » de la boîte de dialogue Options."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Suppression du livre"/> + <node name="message" value="Êtes-vous sûr de vouloir supprimer le livre « %s » du disque ?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Inscription"/> + <node name="login" value="Identifiant"/> + <node name="password" value="Mot de passe"/> + <node name="confirmPassword" value="Confirmer le mot de passe"/> + <node name="email" value="Email"/> + <node name="differentPasswords" value="Les deux mots de passe indiqués doivent être les mêmes."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Récupération du mot de passe"/> + <node name="email" value="Email"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Récupération du mot de passe"/> + <node name="message" value="Un message avec des instructions a été envoyé à %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Erreur de téléchargement"/> + <node name="message" value="Impossible d'ouvrir le fichier téléchargé %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Base"/> + <node name="Regular Paragraph" value="Paragraphe normal"/> + <node name="Title" value="Titre"/> + <node name="Section Title" value="Titre de section"/> + <node name="Poem Title" value="Titre de poème"/> + <node name="Subtitle" value="Sous-titre"/> + <node name="Annotation" value="Annotation"/> + <node name="Epigraph" value="Épigraphe"/> + <node name="Stanza" value="Strophe"/> + <node name="Verse" value="Vers"/> + <node name="Preformatted text" value="Texte préformatté"/> + <node name="Image" value="Image"/> + <node name="Cite" value="Citation"/> + <node name="Author" value="Auteur"/> + <node name="Date" value="Date"/> + <node name="Internal Hyperlink" value="Hyperlien interne"/> + <node name="Footnote" value="Note de bas de page"/> + <node name="Emphasis" value="Emphase"/> + <node name="Strong" value="Forte emphase"/> + <node name="Subscript" value="Indice"/> + <node name="Superscript" value="Exposant"/> + <node name="Code" value="Code"/> + <node name="StrikeThrough" value="Barré"/> + <node name="Contents Table" value="Table des matières"/> + <node name="Library Entry" value="Entrée de la bibliothèque"/> + <node name="Recent Book List" value="Liste des livres récents"/> + <node name="Italic" value="Italique"/> + <node name="Bold" value="Gras"/> + <node name="Definition" value="Définition"/> + <node name="Definition Description" value="Contenu de la définition"/> + <node name="Header 1" value="En-tête 1"/> + <node name="Header 2" value="En-tête 2"/> + <node name="Header 3" value="En-tête 3"/> + <node name="Header 4" value="En-tête 4"/> + <node name="Header 5" value="En-tête 5"/> + <node name="Header 6" value="En-tête 6"/> + <node name="External Hyperlink" value="Hyperlien externe"/> + <node name="Link to Another Book" value="Lien vers un autre livre"/> + </node> + <node name="external"> + <node name="browser" value="Navigateur"/> + <node name="defaultBrowser" value="Navigateur par défaut"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Erreur inconnue"/> + <node name="unsupportedCompressionMethod" value="Méthode de compression non supportée"/> + <node name="encryptedFile" value="Fichier protégé par MTP"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Bibliothèque réseau"/> + </node> + <node name="library"> + <node name="caption" value="Bibliothèque"/> + </node> +</resources> diff --git a/reader/data/resources/he.xml b/reader/data/resources/he.xml new file mode 100644 index 0000000..17f9f9c --- /dev/null +++ b/reader/data/resources/he.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Hebrew TDE-Ebook-Reader resources, by David Kachan --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + <node name="edit" value="×ודות"/> + <node name="unknownAuthor" value="מחבר ×œ× ×™×“×•×¢"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + <node name="edit" value="×©×™× ×•×™ ש×"/> + <node name="clone" value="שיכפול"/> + <node name="delete" value="מחיקה"/> + <node name="noTags" value="×¡×¤×¨×™× ×œ×œ× ×ª×’×™×•×ª"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + </node> + <node name="bookNode"> + <node name="read" value="קרי××”"/> + <node name="edit" value="×ודות"/> + <node name="delete" value="מחיקה"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + <node name="reload" value="×¨×¢× ×•×Ÿ"/> + <node name="openInBrowser" value="הצג בדפדפן"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="פתיחת קטלוג"/> + <node name="collapseTree" value="סגירת קטלוג"/> + <node name="login" value="×›× ×™×¡×”"/> + <node name="logout" value="יצי××” (%s)"/> + <node name="reload" value="×¨×¢× ×•×Ÿ"/> + <node name="dontShow" value="הסתר קטלוג"/> + <node name="topupAccount" value="הפקדת כסף (חשבון × ×•×›×—×™: %s)"/> + <node name="register" value="הרשמה"/> + <node name="passwordRecovery" value="שכחת סיסמ×?"/> + </node> + <node name="searchResultNode"> + <node name="title" value="תוצ×ות חיפוש"/> + <node name="expandTree" value="הצג תוצ×ות"/> + <node name="collapseTree" value="הסתר תוצ×ות"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="הצג ספרי×"/> + <node name="collapseTree" value="הסתר ספרי×"/> + </node> + <node name="bookNode"> + <node name="read" value="קרי×ת עותק מקומי"/> + <node name="delete" value="מחיקת עותק מקומי"/> + <node name="download" value="הורדה"/> + <node name="readDemo" value="קרי×ת קטע"/> + <node name="downloadDemo" value="הורדת קטע"/> + <node name="demo" value="קטע"/> + <node name="buy" value="×§× ×™×™×ª (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="×ודות הספר"/> + <node name="toc" value="תוכן ×”×¢× ×™× ×™×"/> + <node name="showLibrary" value="פתח ספריה"/> + <node name="showNetLibrary" value="הצג ספריית רשת"/> + <node name="addBook" value="פתח קובץ"/> + <node name="showRecent" value="×¡×¤×¨×™× ×§×•×“×ž×™×"/> + <node name="library" value="ספריה"> + <node name="showLibrary" value="פתיחה"/> + <node name="previousBook" value="ספר קוד×"/> + <node name="showRecent" value="×¡×¤×¨×™× ×©× ×§×¨×ו"/> + <node name="addBook" value="הוספת ספר"/> + <node name="showHelp" value="×ודות TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="לתחילת הספר"/> + <node name="gotoPageNumber" value="עבור לעמוד מס' "/> + <node name="gotoSectionStart" value="לתחילת הסעיף"/> + <node name="gotoSectionEnd" value="לסוף הסעיף"/> + <node name="nextTOCSection" value="לפרק הב×"/> + <node name="previousTOCSection" value="לפרק קוד×"/> + <node name="navigate" value="מעבר"> + <node name="gotoHome" value="לתחילת הספר"/> + <node name="gotoPageNumber" value="לעמוד מס' "/> + <node name="gotoSectionStart" value="לתחילת הסעיף"/> + <node name="gotoSectionEnd" value="לסוף הסעיף"/> + <node name="nextTOCSection" value="לפרק הב×"/> + <node name="previousTOCSection" value="לפרק קוד×"/> + <node name="undo" value="×חורה"/> + <node name="redo" value="קדימה"/> + </node> + <node name="selection" value="בחירה"> + <node name="copyToClipboard" value="העתקה"/> + <node name="openInDictionary" value="פתיחה בתוך מילון"/> + <node name="clearSelection" value="בטל בחירה"/> + </node> + <node name="search" value="חיפוש"> + <node name="search" value="חיפוש"/> + <node name="findNext" value="חפש הב×"/> + <node name="findPrevious" value="חפש קוד×"/> + </node> + <node name="view" value="×יור"> + <node name="rotate" value="סיבוב"/> + <node name="toggleFullscreen" value="מסך מל×"/> + <node name="toggleIndicator" value="סמן מיקו×"/> + </node> + <node name="preferences" value="הגדרות"/> + <node name="quit" value="סגירה"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="קרי×ת ספר"/> + <node name="tooltip" value="חזור לספר"/> + </node> + <node name="showLibrary"> + <node name="label" value="ספריה"/> + <node name="tooltip" value="ספריה"/> + <node name="popup" value="הצג ×¡×¤×¨×™× ×‘×¡×¤×¨×™×”"/> + </node> + <node name="showRecent"> + <node name="label" value="היסטוריה"/> + <node name="tooltip" value="×¡×¤×¨×™× ×©× ×§×¨×ו ל××—×¨×•× ×”"/> + </node> + <node name="byAuthor"> + <node name="label" value="לפי מחבר"/> + <node name="tooltip" value="תצוגה לפי מחברי×"/> + </node> + <node name="byTag"> + <node name="label" value="לפי תגיות"/> + <node name="tooltip" value="לפי תגיות"/> + </node> + <node name="addBook"> + <node name="label" value="הוספה"/> + <node name="tooltip" value="הוספת ספר לספריה"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="רשת"/> + <node name="tooltip" value="גישה לספריות רשת"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="חיפוש מהיר"/> + <node name="tooltip" value="חיפוש מהיר ברשת"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="חיפוש מתקד×"/> + <node name="tooltip" value="חיפוש ×ž×ª×§×“× ×‘×¨×©×ª"/> + </node> + <node name="gotoHome"> + <node name="label" value="להתחלה"/> + <node name="tooltip" value="לתחילת הספר"/> + </node> + <node name="undo"> + <node name="label" value="×חורה"/> + <node name="tooltip" value="×חורה"/> + </node> + <node name="redo"> + <node name="label" value="קדימה"/> + <node name="tooltip" value="קדימה"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="מעבר ל"/> + <node name="tooltip" value="מעבר לעמוד"/> + </node> + <node name="toc"> + <node name="label" value="תוכן ×”×¢× ×™× ×™×"/> + <node name="tooltip" value="תוכן ×”×¢× ×™× ×™×"/> + </node> + <node name="search"> + <node name="label" value="חיפוש"/> + <node name="tooltip" value="חיפוש"/> + </node> + <node name="findNext"> + <node name="label" value="הב×"/> + <node name="tooltip" value="×ž×¦× ×ת הב×"/> + </node> + <node name="findPrevious"> + <node name="label" value="קוד×"/> + <node name="tooltip" value="×ž×¦× ×ת הקוד×"/> + </node> + <node name="rotate"> + <node name="label" value="סיבוב"/> + <node name="tooltip" value="סיבוב של הטקסט"/> + </node> + <node name="showHelp"> + <node name="label" value="×ודות ×”×ª×•×›× ×”"/> + <node name="tooltip" value="×ודות ×”×ª×•×›× ×”"/> + </node> + <node name="filterLibrary"> + <node name="label" value="×¡×™× ×•×Ÿ"/> + <node name="tooltip" value="×¡×™× ×•×Ÿ"/> + </node> + <node name="preferences"> + <node name="label" value="הגדרות"/> + <node name="tooltip" value="הגדרות"/> + </node> + <node name="bookInfo"> + <node name="label" value="×ודות הספר"/> + <node name="tooltip" value="×ודות הספר"/> + </node> + <node name="libraryOptions"> + <node name="label" value="הגדרות ספריה"/> + <node name="tooltip" value="הצגת הגדרות ספריה"/> + </node> + <node name="networkOptions"> + <node name="label" value="הגדרות רשת"/> + <node name="tooltip" value="הגדרות רשת"/> + </node> + <node name="systemOptions"> + <node name="label" value="הגדרות מערכת"/> + <node name="tooltip" value="הגדרות מערכת"/> + </node> + <node name="readingOptions"> + <node name="label" value="הגדרות קרי××”"/> + <node name="tooltip" value="הגדרות קרי××”"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" value="הגדרות מר××”"/> + <node name="tooltip" value="הגדרות מר××”"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&חפש"/> + <node name="thisOnly" value="רק ×ת ×–×”"/> + <node name="withSubtags" value="×¢× ×ª×ª-קטגוריות"/> + <node name="removeLink" value="מחיקה מספריה"/> + <node name="removeFile" value="מחיקה מהמחשב"/> + <node name="yesToAll" value="כן &עבור כול×"/> + <node name="buy" value="&×§× ×™×”"/> + <node name="buyAndDownload" value="×§× ×™×” &והורדה"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Library Options" toBeTranslated="true"/> + <node name="tab"> + <node name="Library" value="ספריה"> + <node name="bookPath" value="× ×ª×™×‘ הספריה"/> + <node name="lookInSubdirectories" value="חיפוש ×¡×¤×¨×™× ×‘×ª×ª-תיקיות"/> + <node name="collectBooksWithoutMetaInfo" value="חיפוש ×¡×¤×¨×™× ×œ×œ× ×ª×’×™×•×ª"/> + <node name="downloadDirectory" value="תיקיה עבור ×¡×¤×¨×™× ×©×”×•×¨×“×•"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Network Options" toBeTranslated="true"/> + <node name="tab"> + <node name="NetworkLibrary" value="חיפוש ברשת"> + </node> + <node name="Connection" value="Connection" toBeTranslated="true"> + <node name="useProxy" value="השתמש בשרת פרוקסי"/> + <node name="proxyHost" value="כתובת שרת פרוקסי"/> + <node name="proxyPort" value="פורט בשרת הפרוקסי"/> + <node name="timeout" value="זמן העיכוב המקסימלי ×‘×©× ×™×•×ª"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="פתיחת ×§×™×©×•×¨×™× ×—×™×¦×•× ×™×™× ×¢×œ ידי %s"/> + <node name="defaultText" value="תפיחת ×§×™×©×•×¨×™× ×—×™×¦×•× ×™×™× ×¢×œ ידי דפדפן"/> + <node name="choice" value="דפדפן"/> + <node name="command" value="הפעל פקודה"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - System Options" toBeTranslated="true"/> + <node name="tab"> + <node name="Language" value="שפה"> + <node name="autoDetect" value="זיהוי שפה וקידוד ×וטומתי"/> + <node name="defaultLanguage" value="שפת ברירת מחדל"/> + <node name="defaultEncodingSet" value="רשימת קידודי ברירת מחדל"/> + <node name="defaultEncoding" value="קידוד ברירת מחדל"/> + <node name="useWindows1252Hack" value="השתמש ב-windows-1252 ×‘×ž×§×•× iso-8859-1"/> + </node> + <node name="Config" value="הגדרות"> + <node name="autoSave" value="שמירה ×וטומטית"/> + <node name="timeout" value="עיכוב בין שמירות ×וטומטיות"/> + </node> + <node name="Dictionary" value="×ž×™×œ×•× ×™×"> + <node name="enableIntegration" value="הפעל ××™× ×˜×’×¨×¦×™×” ×¢× %s"/> + <node name="defaultText" value="×פשר ××™× ×˜×’×¨×¦×™×” ×¢× ×ž×™×œ×•×Ÿ"/> + <node name="choice" value="השמשה"/> + <node name="singleClickOpen" value="פתיחת המילון על ידי לחיצה על המילה"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="הגב על שחרור מילה ×•×œ× ×¢×œ לחיצה על מילה"/> + <node name="minStylusPressure" value="לחץ חרט ×ž×™× ×™×ž×œ×™"/> + <node name="maxStylusPressure" value="לחץ חרט מקסימלי"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Reading Options" toBeTranslated="true"/> + <node name="tab"> + <node name="Scrolling" value="דפדוף"> + <node name="keyScrollDelay" value="עיכוב בדפדוף על ידי ×œ×—×¦× ×™×"/> + <node name="keyLinesToScroll" value="כמה שורות לדפדף בבת ×חת"/> + <node name="keyLinesToKeep" value="כמה שורות מעמוד ×§×•×“× ×œ×”×©×יר"/> + <node name="enableTapScrolling" value="הפעל דפדוף על ידי לחיצה על המסך"/> + <node name="fingerOnly" value="רק בעת לחיצה על ידי ×צבע"/> + </node> + <node name="Selection" value="בחירה"> + <node name="enableSelection" value="×פשר בחירת טקסט"/> + </node> + <node name="Indicator" value="שורת מצב"> + <node name="type" value="מר××”"> + <node name="osScrollbar" value="פס גלילה"/> + <node name="fbIndicator" value="צג תחתון"/> + <node name="none" value="×œ× ×œ×”×¦×™×’"/> + </node> + <node name="height" value="גובה צג"/> + <node name="offset" value="מרחק מהטקסט"/> + <node name="pageNumber" value="הצג מספרי עמודי×"/> + <node name="time" value="הצג שעון"/> + <node name="fontSize" value="גודל גופן"/> + <node name="tocMarks" value="הצג ×ž×¦×™×™× ×™ תחילת פרק"/> + <node name="navigation" value="הגב ללחיצות"/> + </node> + <node name="Rotation" value="סיבוב"> + <node name="direction" value="הגדרת סיבוב"> + <node name="disabled" value="×œ× ×œ×¡×•×‘×‘"/> + <node name="clockwise" value="90 מעלות בכיוון השעון"/> + <node name="counterclockwise" value="90 מעלות × ×’×“ כיוון השעון"/> + <node name="180" value="180 מעלות"/> + <node name="cycle" value="לעבור בין 4 ×›×™×•×•× ×™×"/> + </node> + </node> + <node name="Keys" value="כפתורי×"> + <node name="grabSystemKeys" value="יירוט לחיצת קיצורי מערכת הפעלה"/> + <node name="separate" value="הגדרות מיוחדות עבור כל סיבוב של הטקסט"/> + <node name="orientation" value="בסיבוב של:"> + <node name="degrees0" value="0 מעלות"/> + <node name="degrees90ccw" value="90 מעלות × ×’×“ כיוון השעו"/> + <node name="degrees180" value="180 מעלות"/> + <node name="degrees90cw" value="90 מעלות בכיוון השעו"/> + </node> + <node name="action"> + <node name="none" value="×ין פעולה"/> + <node name="showLibrary" value="הצג ספריה"/> + <node name="showNetLibrary" value="ספריות רשת"/> + <node name="showRecent" value="הצג ×¡×¤×¨×™× ×©× ×§×¨×ו"/> + <node name="previousBook" value="פתיחת ספר קוד×"/> + <node name="toc" value="תוכן ×”×¢× ×™× ×™×"/> + <node name="gotoHome" value="מעבר להתחלה"/> + <node name="gotoSectionStart" value="מעבר לתחילת הסעיף"/> + <node name="gotoSectionEnd" value="מעבר לסוף הסעיף"/> + <node name="nextTOCSection" value="מעבר לפרק הב×"/> + <node name="previousTOCSection" value="מעבר לפרק קוד×"/> + <node name="pageForward" value="מעבר לעמוד הב×"/> + <node name="pageBackward" value="מעבר לעמוד קוד×"/> + <node name="lineForward" value="מעבר לשורה הב××”"/> + <node name="lineBackward" value="מעבר לשורה קודמת"/> + <node name="undo" value="ביטול מעבר"/> + <node name="redo" value="חזרה על המעבר"/> + <node name="copyToClipboard" value="העתק"/> + <node name="openInDictionary" value="פתח בתוך מילון"/> + <node name="clearSelection" value="× ×§×” בחירה"/> + <node name="search" value="חיפוש"/> + <node name="findPrevious" value="חיפוש ×חורה"/> + <node name="findNext" value="חיפוש קדימה"/> + <node name="increaseFont" value="הגדלת גופן"/> + <node name="decreaseFont" value="×”×§×˜× ×ª גופן"/> + <node name="toggleIndicator" value="הצג\הסתר סמן מצב"/> + <node name="toggleFullscreen" value="×פשר\בטל מסך מל×"/> + <node name="rotate" value="סיבוב טקסט"/> + <node name="addBook" value="הוספת ספר לספריה"/> + <node name="cancel" value="ביטול"/> + <node name="quit" value="סגירת ×”×ª×•×›× ×”"/> + <node name="bookInfo" value="×ודות הספר"/> + <node name="preferences" value="הגדרות"/> + </node> + <node name="quitOnCancel" value="יצי××” ×ž×”×ª×•×›× ×™×ª"/> + <node name="keyDelay" value="עיכוב בין לחיצת כפתורי×"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Look & Feel Options" toBeTranslated="true"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="×œ× ×œ×”×©×ª×ž×© ×‘×’×•×¤× ×™ ברירת מחדל"/> + </node> + <node name="Margins" value="שוליי×"> + <node name="left" value="שול שמ×לי"/> + <node name="right" value="שול ×™×ž× ×™"/> + <node name="top" value="שול עליון"/> + <node name="bottom" value="שול תחתון"/> + </node> + <node name="Format" value="פירמוט"> + <node name="optionsFor" value="הגדרות עבור"/> + <node name="lineSpacing" value="רווח"> + <node name="unchanged" value="<×œ× ×œ×©× ×•×ª>"/> + </node> + <node name="firstLineIndent" value="שורה ר××©×•× ×”"/> + <node name="alignment" value="קו יישור"> + <node name="left" value="שמ×לה"/> + <node name="right" value="×™×ž×™× ×”"/> + <node name="center" value="×מצע"/> + <node name="justify" value="לקצוות"/> + <node name="unchanged" value="<×œ× ×œ×©× ×•×ª>"/> + </node> + <node name="spaceBefore" value="רווח ×œ×¤× ×™"/> + <node name="spaceAfter" value="רווח ×חרי"/> + <node name="startIndent" value="רווח בתחילת השורה"/> + <node name="endIndent" value="רווח בסוף השורה"/> + </node> + <node name="Styles" value="×¡×’× ×•× ×•×ª"> + <node name="optionsFor" value="הגדרות עבור"/> + <node name="fontFamily" value="גופן"> + <node name="unchanged" value="<×œ× ×œ×©× ×•×ª>"/> + </node> + <node name="fontSize" value="גודל"/> + <node name="fontSizeDifference" value="גודל"/> + <node name="bold" value="טקסט מודגש"/> + <node name="italic" value="טקסט × ×˜×•×™"/> + <node name="allowHyphenations" value="מקופי×"/> + <node name="autoHyphenations" value="מקופי×"/> + </node> + <node name="Colors" value="צבעי×"> + <node name="colorFor" value="צבע עבור"> + <node name="background" value="רקע"/> + <node name="selectionBackground" value="רקע בחירה"/> + <node name="text" value="טקסט רגיל"/> + <node name="internalLink" value="קישור"/> + <node name="externalLink" value="קישור ×—×™×¦×•× ×™"/> + <node name="bookLink" value="קישור לספר"/> + <node name="highlighted" value="טקסט מודגש"/> + <node name="treeLines" value="קווי×"/> + <node name="indicator" value="צג"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - ×ודות הספר"/> + <node name="tab"> + <node name="Common" value="מידע בסיסי"> + <node name="file" value="קובץ"/> + <node name="title" value="ש×"/> + <node name="language" value="שפה"/> + <node name="encodingSet" value="רשימת קידודי×"/> + <node name="encoding" value="קידוד"/> + </node> + <node name="Authors" value="מחברי×"> + <node name="authorDisplayName" value="×©× ×ž×—×‘×¨"/> + </node> + <node name="Series" value="סדרה"> + <node name="seriesTitle" value="×©× ×”×¡×“×¨×”"/> + <node name="bookIndex" value="מספר הספר בסדרה"/> + </node> + <node name="Tags" value="תגיות"> + <node name="tags" value="×©× ×ª×’×™×ª"/> + </node> + <node name="Text" value="טקסט"> + <node name="breakType" value="סעיף חדש לפי"/> + <node name="ignoreIndent" value="×”×ª×¢×œ× ×ž×¨×•×•×— פחות מ"/> + <node name="buildTOC" value="×‘× ×™×™×ª תוכן ×”×¢× ×™× ×™×"/> + <node name="emptyLines" value="שורות ריקות בין הפרקי×"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="פרק חדש לפי"/> + <node name="ignoreIndent" value="×”×ª×¢×œ× ×ž×¨×•×•×— פחות מ"/> + <node name="buildTOC" value="×‘× ×™×™×ª תוכן ×”×¢× ×™× ×™×"/> + <node name="emptyLines" value="שורות ריקות בין הפרקי×"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - ×ודות מחבר"/> + <node name="name" value="ש×"/> + <node name="sortKey" value="מיין לפי"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - הוספת ספר לספריה"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="חיפוש בטקסט"/> + <node name="text" value=""/> + <node name="ignoreCase" value="התעלמות מגודל ×”×ותיות"/> + <node name="wholeText" value="מתחילת הטקסט"/> + <node name="backward" value="×חורה"/> + <node name="currentSection" value="רק בסעיף × ×•×›×—×™"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="חיפוש ברשת"/> + <node name="titleAndSeries" value="×©× ×¡×¤×¨\סדרה"/> + <node name="author" value="מחבר"/> + <node name="category" value="קטגוריה"/> + <node name="description" value="תי×ור"/> + <node name="annotation" value="תוצ×ות חיפוש עבור: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="מעבר לעמוד"/> + <node name="pageNumber" value="מס' עמוד"/> + </node> + <node name="editTagDialog"> + <node name="title" value="×©×™× ×•×™ ×©× ×ª×’×™×ª"/> + <node name="name" value="ש×"/> + <node name="includeSubtags" value="כולל תת-תגיות"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="שכפול תגיות"/> + <node name="name" value="ש×"/> + <node name="includeSubtags" value="כולל תת-תגיות"/> + </node> + <node name="removeBookBox"> + <node name="title" value="מחיקת ספר"/> + <node name="message" value="למחוק ספר «%s» מספריה?"/> + <node name="deleteFile" value="×”×× ×‘×¨×¦×•× ×š למחוק קובץ «%s» מהמחשב?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="מחיקת תגית"/> + <node name="message" value="×”×× ×œ×ž×—×•×§ תגית «%s»?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="שגי××”"/> + <node name="message" value="×œ× × ×™×ª×Ÿ לפתוח: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="שגי××”"/> + <node name="message" value="×œ× × ×™×ª×Ÿ למחוק קובץ %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="שגי××”"/> + <node name="message" value="×œ×¦×¢×¨× ×• קובץ ×œ× ×§×™×™×"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="×œ× × ×‘×—×¨×• ספריות"/> + <node name="authenticationFailed" value="×ימות ×¤×¨×˜×™× × ×›×©×œ"/> + <node name="internalError" value="שגי×ת שרת ×¤× ×™×ž×™×ª"/> + <node name="purchaseNotEnoughMoney" value="×ין מספיק כסף בחשבון"/> + <node name="purchaseMissingBook" value="הספר ×œ× ×§×™×™× ×‘×ž×›×™×¨×•×ª"/> + <node name="purchaseAlreadyPurchased" value="הספר כבר × ×¨×›×©"/> + <node name="bookNotPurchased" value="הספר ×œ× × ×¨×›×©"/> + <node name="downloadLimitExceeded" value="חריגה ממגבלת הורדות"/> + <node name="unsupportedOperation" value="פעולה ××™× ×” × ×ª×ž×›×ª"/> + <node name="loginAlreadyTaken" value="×©× ×ž×©×ª×ž×© תפוס"/> + <node name="loginNotSpecified" value="הזן ×©× ×ž×©×ª×ž×©"/> + <node name="passwordNotSpecified" value="הזן סיסמ×"/> + <node name="emailNotSpecified" value="הזן כתובת"/> + <node name="invalidEMail" value="כתובת ×œ× ×ª×§×™× ×”"/> + <node name="tooManyRegistrations" value="× ×¡×™×•× ×•×ª הרשמה ×¨×‘×™× ×ž×“×™ מכתובת ×”-IP שלך; × ×¡×” שוב בעוד כמה דקות"/> + <node name="noUserEmail" value="משתמש ×¢× ×›×ª×•×‘×ª דו×''ל ×©×¦×•×™×™× ×” ×œ× ×§×™×™×"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="שגי××” בעת הורדה"/> + <node name="message" value="הורדת ספר ×œ× ×”×¦×œ×™×—×”"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="טוען ספר. ×× × ×”×ž×ª×Ÿ..."/> + <node name="loadingBookList" value="×˜×¢×™× ×ª רשימת ספרי×. ×× × ×”×ž×ª×Ÿ..."/> + <node name="migrate" value="מעדכן גרסה. ×× × ×”×ž×ª×Ÿ..."/> + <node name="downloadBookList" value="הורדת רשימת ספרי×. ×× × ×”×ž×ª×Ÿ..."/> + <node name="downloadBook" value="מוריד ספר. ×× × ×”×ž×ª×Ÿ..."/> + <node name="downloadImages" value="×˜×¢×™× ×ª ×יורי×. ×× × ×”×ž×ª×Ÿ..."/> + <node name="authentication" value="×ימות פרטי×. ×× × ×”×ž×ª×Ÿ...."/> + <node name="purchaseBook" value="מתבצעת ×§× ×™×™×ª ספר. ×× × × ×ž×ª×Ÿ..."/> + <node name="initializeAuthenticationManager" value="×˜×¢×™× ×ª פרטי משתמש. ×× × ×”×ž×ª×Ÿ..."/> + <node name="loadSubCatalog" value="×˜×¢×™× ×ª קטלוג. ×× × ×”×ž×ª×Ÿ..."/> + <node name="registerUser" value="הרשמת משתמש. ×× × ×”×ž×ª×Ÿ..."/> + <node name="passwordRecovery" value="בקשה לשחזור ×¡×™×¡×ž× ×ž×ª×‘×¦×¢×ª. ×× × ×”×ž×ª×Ÿ..."/> + <node name="authenticationCheck" value="×ימות פרטי×. ×× × ×”×ž×ª×Ÿ..."/> + <node name="signOut" value="×”×ª× ×ª×§×•×ª ממערכת, ×× × ×”×ž×ª×Ÿ..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="×§× ×™×™×ª ספר"/> + <node name="message" value="×‘×¨×¦×•× ×š ×œ×§× ×•×ª ספר «%s» ×”×× ×œ×”×ž×©×™×š?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="×ימות פרטי×"/> + <node name="login" value="×©× ×ž×©×ª×ž×©"/> + <node name="password" value="סיסמ×"/> + <node name="skipIP" value="×œ× ×œ×–×›×•×¨ כתובת IP"/> + <node name="loginIsEmpty" value="שדה ×©× ×ž×©×ª×ž×© ×œ× ×™×›×•×œ להיות ריק"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="מידע"/> + <node name="message" value="הקטלוג ריק."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="השבתת קטלוג"/> + <node name="message" value="×”×× ×תה בטוח ×©×‘×¨×¦×•× ×š להשבית ×ת קטלוג «%s»? תוכל להפעיל ×ותו מחדש בתוך ×œ×©×•× ×™×ª ''חיפוש ב××™× ×˜×¨× ×˜'' בחלון ההגדרות."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="מחיקת ספר"/> + <node name="message" value="×”×× ×‘×¨×¦×•× ×š למחוק ספר «%s» מהמחשב?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="הרשמה"/> + <node name="login" value="×©× ×ž×©×ª×ž×©"/> + <node name="password" value="סיסמ×"/> + <node name="confirmPassword" value="×¡×™×¡×ž× ×©×•×‘"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="סיסמ×ות ××™× ×Ÿ זהות"/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="שחזור סיסמ×"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="שחזור סיסמ×"/> + <node name="message" value="הור×ות לשחזור ×¡×™×¡×ž× × ×©×œ×—×• לכתובת %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="שגי××”"/> + <node name="message" value="×œ× × ×™×ª×Ÿ לפתוח קובץ שהורד %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="טקסט ברירת מחדל"/> + <node name="Regular Paragraph" value="טקסט רגיל"/> + <node name="Title" value="כותרת"/> + <node name="Section Title" value="כותרת סעיף"/> + <node name="Poem Title" value="הכותרת של השיר"/> + <node name="Subtitle" value="כתובית"/> + <node name="Annotation" value="בי×ור"/> + <node name="Epigraph" value="×פיגרף"/> + <node name="Stanza" value="בית"/> + <node name="Verse" value="פסוק"/> + <node name="Preformatted text" value="טקסט בתוך <pre>"/> + <node name="Image" value="×יור"/> + <node name="Cite" value="ציטוט"/> + <node name="Author" value="×©× ×ž×—×‘×¨"/> + <node name="Date" value="ת×ריך"/> + <node name="Internal Hyperlink" value="קישור ×¤× ×™×ž×™"/> + <node name="Footnote" value="הערה"/> + <node name="Emphasis" value="בחירת (emphasis)"/> + <node name="Strong" value="בחירת (strong)"/> + <node name="Subscript" value="כתב תחתי"/> + <node name="Superscript" value="כתב עילי"/> + <node name="Code" value="קוד"/> + <node name="StrikeThrough" value="טקסט חצוי"/> + <node name="Contents Table" value="תוכן ×”×¢×™× ×™× ×™×"/> + <node name="Library Entry" value="ספריה"/> + <node name="Recent Book List" value="רשימת ספרי×"/> + <node name="Italic" value="טקסט × ×˜×•×™"/> + <node name="Bold" value="טקסט מודגש"/> + <node name="Definition" value="תי×ור"/> + <node name="Definition Description" value="הגדרת תי×ור"/> + <node name="Header 1" value="טקסט בתוך <h1>"/> + <node name="Header 2" value="טקסט בתוך <h2>"/> + <node name="Header 3" value="טקסט בתוך <h3>"/> + <node name="Header 4" value="טקסט בתוך <h4>"/> + <node name="Header 5" value="טקסט בתוך <h5>"/> + <node name="Header 6" value="טקסט בתוך <h6>"/> + <node name="External Hyperlink" value="קישור ×—×™×¦×•× ×™"/> + <node name="Link to Another Book" value="קישור לספר ×חר"/> + </node> + <node name="external"> + <node name="browser" value="דפדפן"/> + <node name="defaultBrowser" value="דפדפן"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="שגי××” ×œ× ×™×“×•×¢×”"/> + <node name="unsupportedCompressionMethod" value="סוג דחיסה ×–×” ××™× ×• × ×ª×ž×š"/> + <node name="encryptedFile" value="קובץ מוגן על ידי DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="חיפוש בספריות ברשת"/> + </node> + <node name="library"> + <node name="caption" value="ספריה"/> + </node> +</resources> diff --git a/reader/data/resources/hu.xml b/reader/data/resources/hu.xml new file mode 100644 index 0000000..90d7fe4 --- /dev/null +++ b/reader/data/resources/hu.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Hungarian TDE-Ebook-Reader resources, by Sándor Gábor --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Könyvek megjelenÃtése"/> + <node name="collapseTree" value="Könyvek elrejtése"/> + <node name="edit" value="Adatok módosÃtása"/> + <node name="unknownAuthor" value="Ismeretlen szerzÅ‘"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Könyvek megjelenÃtése"/> + <node name="collapseTree" value="Könyvek elrejtése"/> + <node name="edit" value="Kulccsó módosÃtása"/> + <node name="clone" value="Kulcsszó másolása"/> + <node name="delete" value="Kulcsszó eltávolÃtása"/> + <node name="noTags" value="Nem jelölt könyvek"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Könyvek megjelenÃtése"/> + <node name="collapseTree" value="Könyvek elrejtése"/> + </node> + <node name="bookNode"> + <node name="read" value="Olvasás"/> + <node name="edit" value="Adatok módosÃtása"/> + <node name="delete" value="EltávolÃtás"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="SzerzÅ‘"> + <node name="summary" value="Könyvek szerzÅ‘ szerint"/> + </node> + <node name="byTitle" value="CÃm"> + <node name="summary" value="Könyvek cÃm szerint"/> + </node> + <node name="byDate" value="Dátum"> + <node name="summary" value="Könyvek letöltés dátuma szerint"/> + </node> + <node name="bySeries" value="Sorozat"> + <node name="summary" value="Könyvek sorozat szerint"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Kibontva"/> + <node name="collapseTree" value="Összecsukva"/> + <node name="reload" value="Újratöltés"/> + <node name="openInBrowser" value="Megnyitás a böngészÅ‘ben"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Katalógus megnyitása"/> + <node name="collapseTree" value="Katalógus bezárása"/> + <node name="login" value="Belépés"/> + <node name="logout" value="Kijelentkezés (%s)"/> + <node name="reload" value="Újratöltés"/> + <node name="dontShow" value="Ezt a katalógust ne mutassa"/> + <node name="topupAccount" value="Fiók újratöltése (jelenleg: %s)"/> + <node name="register" value="Regisztráció"/> + <node name="passwordRecovery" value="Elfelejtett jelszó"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Keresés"/> + <node name="expandTree" value="Találatok"/> + <node name="collapseTree" value="Találatok elrejtése"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Könyvek megjelenÃtése"/> + <node name="collapseTree" value="Könyvek elrejtése"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Könyvek megjelenÃtése"/> + <node name="collapseTree" value="Könyvek elrejtése"/> + </node> + <node name="bookNode"> + <node name="read" value="Helyi másolat olvasása"/> + <node name="delete" value="Heyli másolat törlése"/> + <node name="download" value="Letöltés"/> + <node name="readDemo" value="Minta olvasása"/> + <node name="downloadDemo" value="Minta letöltése"/> + <node name="demo" value="Minta"/> + <node name="buy" value="(%s)- megvásárlása"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Könyv adatai..."/> + <node name="toc" value="Tartalomjegyzék"/> + <node name="showLibrary" value="Könyvtár megnyitása"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Könyvtár"> + <node name="showLibrary" value="Megnyitás"/> + <node name="previousBook" value="ElÅ‘zÅ‘ kötet"/> + <node name="showRecent" value="Legutóbbi"/> + <node name="addBook" value="Könyv hozzáadása..."/> + <node name="showHelp" value="TDE-Ebook-Reader névjegye"/> + </node> + <node name="gotoHome" value="A kötet elejére"/> + <node name="gotoPageNumber" value="Ugrás egy oldalra..."/> + <node name="gotoSectionStart" value="Ugrás a szakasz elejére"/> + <node name="gotoSectionEnd" value="Ugrás a szakasz végére"/> + <node name="nextTOCSection" value="Ugrás a következÅ‘ fejezethez"/> + <node name="previousTOCSection" value="Ugrás az elÅ‘zÅ‘ fejezethez"/> + <node name="navigate" value="PozÃcionálás"> + <node name="gotoHome" value="A kötet eljére"/> + <node name="gotoPageNumber" value="Ugrás egy oldalra..."/> + <node name="gotoSectionStart" value="Ugrás a szakasz elejére"/> + <node name="gotoSectionEnd" value="Ugrás a szakasz végére"/> + <node name="nextTOCSection" value="Ugrás a következÅ‘ fejezethez"/> + <node name="previousTOCSection" value="Ugrás az elÅ‘zÅ‘ fejezethez"/> + <node name="undo" value="Vissza"/> + <node name="redo" value="ElÅ‘re"/> + </node> + <node name="selection" value="Selection"> + <node name="copyToClipboard" value="Másolás a vágólapra"/> + <node name="openInDictionary" value="Megnyitás a szótárban"/> + <node name="clearSelection" value="Törlés"/> + </node> + <node name="search" value="Find"> + <node name="search" value="Új keresés..."/> + <node name="findNext" value="KövetkezÅ‘ keresése"/> + <node name="findPrevious" value="ElÅ‘zÅ‘ keresése"/> + </node> + <node name="view" value="View"> + <node name="rotate" value="KépernyÅ‘ elforgatása"/> + <node name="toggleFullscreen" value="Teljes képernyÅ‘"/> + <node name="toggleIndicator" value="Helyzet jelzÅ‘ átkapcsolása"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Bezár"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Kötet olvasása"/> + <node name="tooltip" value="Olvasó ablak"/> + </node> + <node name="showLibrary"> + <node name="label" value="Könyvtár"/> + <node name="tooltip" value="Könyvtár"/> + <node name="popup" value="Legutóbbi kötetek listája"/> + </node> + <node name="showRecent"> + <node name="label" value="Legutóbbi kötetek"/> + <node name="tooltip" value="Legutóbbi kötetek listája"/> + </node> + <node name="byAuthor"> + <node name="label" value="SzerzÅ‘k szerint"/> + <node name="tooltip" value="SzerzÅ‘k szerint csoportosÃtva"/> + </node> + <node name="byTag"> + <node name="label" value="Kulcsszavak szerint"/> + <node name="tooltip" value="Kulcsszavak szerint csoportosÃtva"/> + </node> + <node name="addBook"> + <node name="label" value="Fájl hozzáadása"/> + <node name="tooltip" value="Fájl hozzáadása a könyvtárhoz"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Internet"/> + <node name="tooltip" value="Keresés az Internetes könyvtárakban"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Egyszerű keresés"/> + <node name="tooltip" value="Keresés az Interneten"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Keresés"/> + <node name="tooltip" value="Összetett Internetes keresés"/> + </node> + <node name="gotoHome"> + <node name="label" value="Az elejére"/> + <node name="tooltip" value="A szöveg elejére"/> + </node> + <node name="undo"> + <node name="label" value="Vissza"/> + <node name="tooltip" value="Vissza"/> + </node> + <node name="redo"> + <node name="label" value="ElÅ‘re"/> + <node name="tooltip" value="ElÅ‘re"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Ugrás az oldalra"/> + <node name="tooltip" value="Ugrás a megadott oldalra"/> + </node> + <node name="toc"> + <node name="label" value="Tartalom"/> + <node name="tooltip" value="Tartalomjegyzék"/> + </node> + <node name="search"> + <node name="label" value="Keresés"/> + <node name="tooltip" value="Új keresés"/> + </node> + <node name="findNext"> + <node name="label" value="KövetkezÅ‘"/> + <node name="tooltip" value="KövetkezÅ‘ keresése"/> + </node> + <node name="findPrevious"> + <node name="label" value="ElÅ‘zÅ‘"/> + <node name="tooltip" value="ElÅ‘zÅ‘ keresése"/> + </node> + <node name="rotate"> + <node name="label" value="Elforgatás"/> + <node name="tooltip" value="A szöveg elforgatása"/> + </node> + <node name="showHelp"> + <node name="label" value="Névjegy"/> + <node name="tooltip" value="TDE-Ebook-Reader névjegye"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Szűrés"/> + <node name="tooltip" value="Válogatás a könyvtár köteteibÅ‘l"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Könyv adatai"/> + <node name="tooltip" value="A könyv adatainak módosÃtása"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Ugrás!"/> + <node name="thisOnly" value="&Csak ezt"/> + <node name="withSubtags" value="Kulcsszavbakkal &együtt"/> + <node name="removeLink" value="Törlés a &könyvtárból"/> + <node name="removeFile" value="Törlés a &lemezrÅ‘l"/> + <node name="yesToAll" value="&Mindenre igen"/> + <node name="buy" value="&Vásárlás"/> + <node name="buyAndDownload" value="Vásárlás &és letöltés"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Könyvtár"> + <node name="bookPath" value="A könyvek helye"/> + <node name="lookInSubdirectories" value="Alkönyvtárakba rendezve"/> + <node name="collectBooksWithoutMetaInfo" value="Gyüjtsd össze az információk nélküli köteteket is"/> + <node name="downloadDirectory" value="A letöltendÅ‘ kötetek helye"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Keresés az Interneten"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Proxy használat"/> + <node name="proxyHost" value="Proxy IP cÃme"/> + <node name="proxyPort" value="Proxy port"/> + <node name="timeout" value="Várakozás hálózati válaszra, másodpercben"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="KülsÅ‘ csatolások megnyitása: %s"/> + <node name="defaultText" value="KülsÅ‘ csatolások megnyitása a böngészÅ‘ben"/> + <node name="choice" value="BöngészÅ‘ használata"/> + <node name="command" value="Végrehajtandó parancs"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Nyelv"> + <node name="autoDetect" value="Nyelv és kódlap automatikus kiválasztása"/> + <node name="defaultLanguage" value="ElsÅ‘dleges nyelv"/> + <node name="defaultEncodingSet" value="ElsÅ‘dleges kódlap készlet"/> + <node name="defaultEncoding" value="ElsÅ‘dleges kódlap"/> + <node name="useWindows1252Hack" value="Használja a windows-1252-t az iso-8859-1 helyett"/> + </node> + <node name="Config" value="BeállÃtások"> + <node name="autoSave" value="Ãllapot automatikus mentése"/> + <node name="timeout" value="Mentések közötti várakozás, másodperc"/> + </node> + <node name="Dictionary" value="Szótár"> + <node name="enableIntegration" value="A(z) %s összekapcsolása a programmal"/> + <node name="defaultText" value="KülsÅ‘ szótárral együttműködés engedélyezése"/> + <node name="choice" value="Együttműködés:"/> + <node name="singleClickOpen" value="Egy gombos megnyitás"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Végrehajtás a billentyű elengedésekor"/> + <node name="minStylusPressure" value="Minimális nyomás"/> + <node name="maxStylusPressure" value="Maximális nyomás"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Görgetés"> + <node name="keyScrollDelay" value="Várakozás a billentyűlenyomás után, ezredmásodperc"/> + <node name="keyLinesToScroll" value="Egyszerre gördÃtett sorok"/> + <node name="keyLinesToKeep" value="Oldalankénti léptetéskor megtartott sorok"/> + <node name="enableTapScrolling" value="ÉrintÅ‘ görgetés engedélyezve"/> + <node name="fingerOnly" value="Csak érintÅ‘ görgetés"/> + </node> + <node name="Selection" value="Kijelölés"> + <node name="enableSelection" value="Szöveg kijelÅ‘lés engedélyezve"/> + </node> + <node name="Indicator" value="Helyzet jelzÅ‘"> + <node name="type" value="TÃpusa"> + <node name="osScrollbar" value="Operációsrendszer görgetÅ‘sáv"/> + <node name="fbIndicator" value="Klasszikus helyzet jelzÅ‘"/> + <node name="none" value="Nem szükséges"/> + </node> + <node name="height" value="JelzÅ‘sáv magassága"/> + <node name="offset" value="Távolsága a szövegtÅ‘l"/> + <node name="pageNumber" value="Számokkal is mutassa a helyzetet"/> + <node name="time" value="Óra"/> + <node name="fontSize" value="Betűméret"/> + <node name="tocMarks" value="Mutassa a tartalom bejegyzéseket"/> + <node name="navigation" value="PozÃcionálás engedélyezve"/> + </node> + <node name="Rotation" value="Elforgatás"> + <node name="direction" value="Elforgatás"> + <node name="disabled" value="Tiltva"/> + <node name="clockwise" value="90 fok jobbra"/> + <node name="counterclockwise" value="90 fok balra"/> + <node name="180" value="180 fok"/> + <node name="cycle" value="Sorban mind a 4 pozÃcioba"/> + </node> + </node> + <node name="Keys" value="Billentyűk"> + <node name="grabSystemKeys" value="A rendszerbillentyűk használata"/> + <node name="separate" value="ElforgatásfüggÅ‘ billentyűhozzárendelés"/> + <node name="orientation" value="Elforgatás"> + <node name="degrees0" value="0 fok"/> + <node name="degrees90ccw" value="90 fok balra"/> + <node name="degrees180" value="180 fok"/> + <node name="degrees90cw" value="90 90 fok jobbra"/> + </node> + <node name="action"> + <node name="none" value="Nem"/> + <node name="showLibrary" value="Könyvtár mutatása"/> + <node name="showNetLibrary" value="Internetes könyvtár mutatása"/> + <node name="showRecent" value="Legutóbbi kötetek"/> + <node name="previousBook" value="ElÅ‘zÅ‘ kötet megnyitása"/> + <node name="toc" value="Tartalomjegyzék"/> + <node name="gotoHome" value="KezdÅ‘lap"/> + <node name="gotoSectionStart" value="Ugrás a szakasz kezdetére"/> + <node name="gotoSectionEnd" value="Ugrás a szakasz végére"/> + <node name="nextTOCSection" value="Ugrás a következÅ‘ fejezethez"/> + <node name="previousTOCSection" value="Ugrás az elÅ‘zÅ‘ fejezethez"/> + <node name="pageForward" value="Lapozás elÅ‘re"/> + <node name="pageBackward" value="Lapozás hátra"/> + <node name="lineForward" value="Görgetés elÅ‘re"/> + <node name="lineBackward" value="Görgetés hátra"/> + <node name="undo" value="Visszavonás"/> + <node name="redo" value="Újra"/> + <node name="copyToClipboard" value="Kijelölt szöveg másolása a vágólapra"/> + <node name="openInDictionary" value="Kijelölt szöveg megnyitása a szótárban"/> + <node name="clearSelection" value="Kijelölés törlése"/> + <node name="search" value="Keresés"/> + <node name="findPrevious" value="ElÅ‘zÅ‘ keresése"/> + <node name="findNext" value="KövetkezÅ‘ keresése"/> + <node name="increaseFont" value="Betűméret növelése"/> + <node name="decreaseFont" value="Betűméret csökkentése"/> + <node name="toggleIndicator" value="Helyzet jelzÅ‘ kapcsolása"/> + <node name="toggleFullscreen" value="Teljes képernyÅ‘re"/> + <node name="rotate" value="KépernyÅ‘ elforgatása"/> + <node name="addBook" value="Kötet hozzáadása"/> + <node name="cancel" value="Mégsem"/> + <node name="quit" value="Kilépés"/> + <node name="bookInfo" value="Kötet adatainak módosÃtása"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="“Mégsem†után kilépés a programból"/> + <node name="keyDelay" value="Várakozás a billentyűleütések között"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Kizárólag saját fontok használata"/> + </node> + <node name="Margins" value="Margók"> + <node name="left" value="Bal margó"/> + <node name="right" value="Jobb margó"/> + <node name="top" value="Oldal tetején"/> + <node name="bottom" value="Oldal alján"/> + </node> + <node name="Format" value="Formátum"> + <node name="optionsFor" value="BeállÃtások"/> + <node name="lineSpacing" value="Sorköz"> + <node name="unchanged" value="<változatlan>"/> + </node> + <node name="firstLineIndent" value="ElsÅ‘ sor behúzása"/> + <node name="alignment" value="IgazÃtás"> + <node name="left" value="Bal"/> + <node name="right" value="Jobb"/> + <node name="center" value="Középre"/> + <node name="justify" value="Sorkizárt"/> + <node name="unchanged" value="<változatlan>"/> + </node> + <node name="spaceBefore" value="Sorköz elÅ‘tte"/> + <node name="spaceAfter" value="Sorköz utánna"/> + <node name="startIndent" value="Behúzás sor elején"/> + <node name="endIndent" value="Behúzás sor végén"/> + </node> + <node name="Styles" value="StÃlusok"> + <node name="optionsFor" value="BeállÃtások"/> + <node name="fontFamily" value="Betűkészlet"> + <node name="unchanged" value="<változatlan>"/> + </node> + <node name="fontSize" value="Méret"/> + <node name="fontSizeDifference" value="Méret eltérés"/> + <node name="bold" value="Vastag"/> + <node name="italic" value="DÅ‘lt"/> + <node name="allowHyphenations" value="Elválasztás engedélyezve"/> + <node name="autoHyphenations" value="Automatikus elválasztás"/> + </node> + <node name="Colors" value="SzÃnek"> + <node name="colorFor" value="SzÃnek"> + <node name="background" value="Háttér"/> + <node name="selectionBackground" value="Kijelölt rész háttere"/> + <node name="text" value="Szöveg"/> + <node name="internalLink" value="BelsÅ‘ mutató"/> + <node name="externalLink" value="KülsÅ‘ mutató"/> + <node name="bookLink" value="Mutató másik kötetre"/> + <node name="highlighted" value="Kiemelt szöveg"/> + <node name="treeLines" value="Könyvtárfa vonalai"/> + <node name="indicator" value="Helyzet jelzÅ‘"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Kötet adatai"/> + <node name="tab"> + <node name="Common" value="Alapadatok"> + <node name="file" value="File"/> + <node name="title" value="CÃm"/> + <node name="language" value="Nyelv"/> + <node name="encodingSet" value="Kódlap készlet"/> + <node name="encoding" value="Kódlap"/> + </node> + <node name="Authors" value="SzerzÅ‘(k)"> + <node name="authorDisplayName" value="SzerzÅ‘ neve"/> + </node> + <node name="Series" value="Sorozat"> + <node name="seriesTitle" value="Sorozat cÃme"/> + <node name="bookIndex" value="Kötet helye a sorozatban"/> + </node> + <node name="Tags" value="Kulcsszavak"> + <node name="tags" value="Kulcs neve"/> + </node> + <node name="Text" value="Szöveg"> + <node name="breakType" value="Bekezdés megtörése a"/> + <node name="ignoreIndent" value="Behúzás letiltása, ha kisebb, mint"/> + <node name="buildTOC" value="Tartalomjegyzék készÃtése"/> + <node name="emptyLines" value="Üres sorok a következÅ‘ szakasz elé"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Bekezdés megtörése a("/> + <node name="ignoreIndent" value="Behúzás letiltása, ha kisebb, mint"/> + <node name="buildTOC" value="Tartalomjegyzék készÃtése"/> + <node name="emptyLines" value="Üres sorok a következÅ‘ szakasz elé"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - SzerzÅ‘ adatai"/> + <node name="name" value="SzerzÅ‘ neve"/> + <node name="sortKey" value="SzerzÅ‘ rendezési kulcs"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Kötet hozzáadása a könyvtárhoz"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Szöveg keresése"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Kis- és nagybetű egyaránt"/> + <node name="wholeText" value="&Teljes szövegben"/> + <node name="backward" value="&Visszafelé"/> + <node name="currentSection" value="Csak ebben a &szakaszban"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Keresés Interneten"/> + <node name="titleAndSeries" value="CÃm/SorozatcÃm"/> + <node name="author" value="SzerzÅ‘"/> + <node name="category" value="Kategória"/> + <node name="description" value="LeÃrás"/> + <node name="annotation" value="Találatok a(z) %s keresésre"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Ugrás az oldalra"/> + <node name="pageNumber" value="Ugrás a megadott oldalra"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Kulccszó javÃtása"/> + <node name="name" value="Kulcsszó"/> + <node name="includeSubtags" value="Másodlagos kulcsokat is használ"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Kulcsszó másolása"/> + <node name="name" value="Kulccszó"/> + <node name="includeSubtags" value="Másodlagos kulcsokat is használ"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Kötet törlése"/> + <node name="message" value="Törlöd a “%sâ€-t a könyvtárból?"/> + <node name="deleteFile" value="Biztosan törölni akarod a “%sâ€-t a lemezrÅ‘l is?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Kulccsó törlése"/> + <node name="message" value="Törlöd a“%s†kulcsot?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Hiba"/> + <node name="message" value="Nem lehet megnyitni: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Hiba"/> + <node name="message" value="A %s nem törölhetÅ‘..."/> + </node> + <node name="noHelpBox"> + <node name="title" value="Hiba"/> + <node name="message" value="Bocs, súgó fájl nem található"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="ÜrÃtsd ki a könyvtárlistát"/> + <node name="authenticationFailed" value="AzonosÃtási hiba"/> + <node name="internalError" value="BelsÅ‘ szerverhiba"/> + <node name="purchaseNotEnoughMoney" value="Kevés a pénzed"/> + <node name="purchaseMissingBook" value="Nincs ilyen kötet"/> + <node name="purchaseAlreadyPurchased" value="Már megvetted"/> + <node name="bookNotPurchased" value="A kötet nincs kifizetve"/> + <node name="downloadLimitExceeded" value="Elérted a letöltési korlátot"/> + <node name="unsupportedOperation" value="Nem támogatott művelet"/> + <node name="loginAlreadyTaken" value="Ez a felhasználónév már foglalt"/> + <node name="loginNotSpecified" value="Add meg a felhasználói neved"/> + <node name="passwordNotSpecified" value="Üres jelszó nem használható"/> + <node name="emailNotSpecified" value="Adj meg egy érvényes e-mail cÃmet"/> + <node name="invalidEMail" value="Érvénytelen e-mail cÃm"/> + <node name="tooManyRegistrations" value="Túl sok regisztrációs kérés az IP-cÃmedrÅ‘l; próbáld meg pár perc múlva ismét!"/> + <node name="noUserEmail" value="Nincs regisztrált felhasználónk ezzel az e-mail cÃmmel"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Letöltési hiba"/> + <node name="message" value="A kötet jelenleg nem letölthetÅ‘"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Türelem, töltöm a kötetet..."/> + <node name="loadingBookList" value="Türelem, töltöm a könyvtárat..."/> + <node name="migrate" value="Türelem, új verzióra frissÃtek..."/> + <node name="downloadBookList" value="Türelem, töltöm a könyvek listáját..."/> + <node name="downloadBook" value="Türelem, letöltöm a kötetet..."/> + <node name="downloadImages" value="Türelem, ltöltöm a képeket..."/> + <node name="authentication" value="AzonosÃtás, várj egy kicsit..."/> + <node name="purchaseBook" value="Megvesszük a kötetet, várj egy kicsit..."/> + <node name="initializeAuthenticationManager" value="Letöltöm a felhasználói adatokat, türelem..."/> + <node name="loadSubCatalog" value="Töltöm a katalógust..."/> + <node name="registerUser" value="Új felhasználó regisztrálás, várj egy kicsit..."/> + <node name="passwordRecovery" value="Jelszó visszaszerzése, türelem..."/> + <node name="authenticationCheck" value="Adatok ellenörzése, várj egy kicsit..."/> + <node name="signOut" value="Kijelentkezés. Türelem..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Kötet megvásárlása"/> + <node name="message" value="Biztosan meg akarod venni a “%sâ€-t?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="AzonosÃtás"/> + <node name="login" value="Felhasználói név"/> + <node name="password" value="Jelszó"/> + <node name="skipIP" value="Nem tudom az IP cÃmhez kötni..."/> + <node name="loginIsEmpty" value="Üres felhasználói név nem használható"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Információk"/> + <node name="message" value="A katalógus üres."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Katalógus letiltása"/> + <node name="message" value="Biztosan le akarod tiltani a “%s†katalógust? A késÅ‘bbiekben ismét engedélyezheted a “Keresés az Interneten†fülön a BeállÃtások panelen."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Kötet törlése"/> + <node name="message" value="Biztoasn törölni akarod a(z) “%s†kötetet a lemezrÅ‘l?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Regisztráció"/> + <node name="login" value="Felhasználói név"/> + <node name="password" value="Jelszó"/> + <node name="confirmPassword" value="Jelszó megerÅ‘sÃtése"/> + <node name="email" value="E-mail" tooltip="Érvényes e-mail cÃm szükséges az elfelejtett jelszÅ‘ újra létrehozásához. Ha nem adsz meg e-mail cÃmet, nem tudsz új jelszót kérni."/> + <node name="differentPasswords" value="A jelszónak és a megerÅ‘sÃtésének azonosnak kell lennie."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Elfelejtett jelszó"/> + <node name="email" value="E-mail cÃm"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Elfelejtett jelszó"/> + <node name="message" value="A szükséges lépéseket leÃró e-mail elküldve a(z) %s cÃmre"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Letöltési hiba"/> + <node name="message" value="Nem lehet megnyitni a letöltött fájlt: %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Alap (Base)"/> + <node name="Regular Paragraph" value="Normál bekezdés (Regular)"/> + <node name="Title" value="CÃm (Title)"/> + <node name="Section Title" value="SzakaszcÃm (Section Title)"/> + <node name="Poem Title" value="Vers cÃm (Poem Title)"/> + <node name="Subtitle" value="AlcÃm (Subtitle)"/> + <node name="Annotation" value="IsmertetÅ‘ (Annotation)"/> + <node name="Epigraph" value="Jegyzet (Epigraph)"/> + <node name="Stanza" value="Versszak (Stanza)"/> + <node name="Verse" value="Versszak (Verse)"/> + <node name="Preformatted text" value="Formázott szöveg (Preformatted)"/> + <node name="Image" value="Kép (Image)"/> + <node name="Cite" value="Idézet (Cite)"/> + <node name="Author" value="SzerzÅ‘ (Author)"/> + <node name="Date" value="Dátum (Date)"/> + <node name="Internal Hyperlink" value="BelsÅ‘ mutató (Internal Hyperlink)"/> + <node name="Footnote" value="Lábjegyzet (Footnote)"/> + <node name="Emphasis" value="DÅ‘lt betű (Emphasis)"/> + <node name="Strong" value="VastagÃtott betű (Strong)"/> + <node name="Subscript" value="Alsó index (Subscript)"/> + <node name="Superscript" value="FelsÅ‘ index (Superscript)"/> + <node name="Code" value="Kód (Code)"/> + <node name="StrikeThrough" value="Ãthúzott szöveg (Strikethrough)"/> + <node name="Contents Table" value="Tartalomjegyzék (Contents Table)"/> + <node name="Library Entry" value="Könyvtári bejegyzés (Library Entry)"/> + <node name="Recent Book List" value="Korábbi kötetek listája (Recent Book List)"/> + <node name="Italic" value="DÅ‘lt betű (Italic)"/> + <node name="Bold" value="VastagÃtott betű (Bold)"/> + <node name="Definition" value="Meghatározás (Definition)"/> + <node name="Definition Description" value="Meghatározás leÃrása (Definition Description)"/> + <node name="Header 1" value="CÃmsor 1 (Header 1)"/> + <node name="Header 2" value="CÃmsor 2 (Header 2)"/> + <node name="Header 3" value="CÃmsor 3 (Header 3)"/> + <node name="Header 4" value="CÃmsor 4 (Header 4)"/> + <node name="Header 5" value="CÃmsor 5 (Header 5)"/> + <node name="Header 6" value="CÃmsor 6 (Header 6)"/> + <node name="External Hyperlink" value="KülsÅ‘ mutató (External Hyperlink)"/> + <node name="Link to Another Book" value="Mutató más kötetre (Link to another Book)"/> + </node> + <node name="external"> + <node name="browser" value="BöngészÅ‘"/> + <node name="defaultBrowser" value="Alapételmezett böngészÅ‘"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Ismeretlen hiba"/> + <node name="unsupportedCompressionMethod" value="Nem támogatott tömörÃtési eljárás"/> + <node name="encryptedFile" value="DRM-védett fájl"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Internetes könyvtár"/> + </node> + <node name="library"> + <node name="caption" value="Könyvtár"/> + </node> +</resources> diff --git a/reader/data/resources/id.xml b/reader/data/resources/id.xml new file mode 100644 index 0000000..036f583 --- /dev/null +++ b/reader/data/resources/id.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Indonesian TDE-Ebook-Reader resources, by Ketut Putu Kumajaya --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + <node name="edit" toBeTranslated="true" value="Edit information"/> + <node name="unknownAuthor" toBeTranslated="true" value="Unknown Author"/> + </node> + <node name="tagNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + <node name="edit" toBeTranslated="true" value="Edit tag"/> + <node name="clone" toBeTranslated="true" value="Clone tag"/> + <node name="delete" toBeTranslated="true" value="Remove tag"/> + <node name="noTags" toBeTranslated="true" value="Books with no tags"/> + </node> + <node name="seriesNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="bookNode"> + <node name="read" toBeTranslated="true" value="Read book"/> + <node name="edit" toBeTranslated="true" value="Edit information"/> + <node name="delete" toBeTranslated="true" value="Remove book"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" toBeTranslated="true" value="Expand"/> + <node name="collapseTree" toBeTranslated="true" value="Collapse"/> + <node name="reload" toBeTranslated="true" value="Reload"/> + <node name="openInBrowser" toBeTranslated="true" value="Open in browser"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" toBeTranslated="true" value="Open catalog"/> + <node name="collapseTree" toBeTranslated="true" value="Close catalog"/> + <node name="login" toBeTranslated="true" value="Sign in"/> + <node name="logout" toBeTranslated="true" value="Sign out (%s)"/> + <node name="reload" toBeTranslated="true" value="Reload"/> + <node name="dontShow" toBeTranslated="true" value="Don't show this catalog"/> + <node name="topupAccount" toBeTranslated="true" value="Top up account (currently: %s)"/> + <node name="register" toBeTranslated="true" value="Sign up"/> + <node name="passwordRecovery" toBeTranslated="true" value="Recover password"/> + </node> + <node name="searchResultNode"> + <node name="title" toBeTranslated="true" value="Search results"/> + <node name="expandTree" toBeTranslated="true" value="Show results"/> + <node name="collapseTree" toBeTranslated="true" value="Hide results"/> + </node> + <node name="authorNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="seriesNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="bookNode"> + <node name="read" toBeTranslated="true" value="Read local copy"/> + <node name="delete" toBeTranslated="true" value="Delete local copy"/> + <node name="download" toBeTranslated="true" value="Download"/> + <node name="readDemo" toBeTranslated="true" value="Read sample"/> + <node name="downloadDemo" toBeTranslated="true" value="Download sample"/> + <node name="demo" toBeTranslated="true" value="sample"/> + <node name="buy" toBeTranslated="true" value="Buy (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informasi Buku..."/> + <node name="toc" value="Daftar Isi"/> + <node name="showLibrary" toBeTranslated="true" value="Open library"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Pustaka"> + <node name="showLibrary" value="Buka"/> + <node name="previousBook" value="Buku Sebelumnya"/> + <node name="showRecent" value="Buku-buku Sebelumnya"/> + <node name="addBook" value="Tambah Buku..."/> + <node name="showHelp" value="Mengenai TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Ke Awal Dokumen"/> + <node name="gotoPageNumber" value="Ke Halaman..."/> + <node name="gotoSectionStart" value="Ke Bagian Awal Teks"/> + <node name="gotoSectionEnd" value="Ke Bagian Akhir Teks"/> + <node name="nextTOCSection" value="Ke Item Daftar Isi Berikutnya"/> + <node name="previousTOCSection" value="Ke Item Daftar Isi Sebelumnya"/> + <node name="navigate" value="Navigasi"> + <node name="gotoHome" value="Ke Awal Dokumen"/> + <node name="gotoPageNumber" value="Ke Halaman..."/> + <node name="gotoSectionStart" value="Ke Bagian Awal Teks"/> + <node name="gotoSectionEnd" value="Ke Bagian Akhir Teks"/> + <node name="nextTOCSection" value="Ke Item Daftar Isi Berikutnya"/> + <node name="previousTOCSection" value="Ke Item Daftar Isi Sebelumnya"/> + <node name="undo" value="Mundur"/> + <node name="redo" value="Maju"/> + </node> + <node name="selection" value="Seleksi"> + <node name="copyToClipboard" value="Salin ke Clipboard"/> + <node name="openInDictionary" value="Buka di Kamus"/> + <node name="clearSelection" value="Bersihkan"/> + </node> + <node name="search" value="Cari"> + <node name="search" value="Pencarian Teks..."/> + <node name="findNext" value="Pencarian Maju"/> + <node name="findPrevious" value="Pencarian Mundur"/> + </node> + <node name="view" value="Tampilan"> + <node name="rotate" value="Putar Layar"/> + <node name="toggleFullscreen" value="Layar Penuh"/> + <node name="toggleIndicator" value="Hidup/Matikan Indikator"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Keluar"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="Tampilkan Mode Baca"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Tampilkan Daftar Pustaka"/> + <node name="popup" value="Tampilkan Daftar Buku-buku Sebelumnya"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Tampilkan Daftar Buku-buku Sebelumnya"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="Atur Buku-buku berdasarkan Pengarang"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="Atur Buku-buku berdasarkan Tag"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Tambahkan Berkas ke Pustaka"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="Cari dalam Pustaka Jaringan"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Pencarian dalam Jaringan"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Pencarian dalam Jaringan Tingkat Lanjut"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Ke Bagian Awal Teks"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="Mundur"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Maju"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="Ke Halaman"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Daftart Isi"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Pencarian Teks"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Pencarian Maju"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Pencarian Mundur"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Putar Layar"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="Mengenai TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Tampilkan Dialog Informasi Buku"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Mulai!"/> + <node name="thisOnly" value="Hanya ini"/> + <node name="withSubtags" value="Dengan subtag"/> + <node name="removeLink" toBeTranslated="true" value="Remove from library"/> + <node name="removeFile" toBeTranslated="true" value="Remove from disk"/> + <node name="yesToAll" toBeTranslated="true" value="Yes to &all"/> + <node name="buy" toBeTranslated="true" value="&Buy"/> + <node name="buyAndDownload" toBeTranslated="true" value="Buy and &download"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Pustaka"> + <node name="bookPath" value="Lokasi Buku"/> + <node name="lookInSubdirectories" value="Tampilkan Buku-buku yang Ada di Sub Direktori"/> + <node name="collectBooksWithoutMetaInfo" value="Kumpulkan Buku-buku tanpa MetaInfo"/> + <node name="downloadDirectory" value="Direktori Buku-buku hasil Download"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Pencarian Jaringan"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Gunakan Proxy"/> + <node name="proxyHost" value="Alamat Proxy"/> + <node name="proxyPort" value="Nomor Port Proxy"/> + <node name="timeout" value="Waktu Tunggu Operasi Jaringan, detik"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Buka Tautan Eksternal dengan %s"/> + <node name="defaultText" value="Buka Tautan Eksternal dengan Browser"/> + <node name="choice" value="Gunakan Browser"/> + <node name="command" value="Perintah yang Dieksekusi"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Bahasa"> + <node name="autoDetect" value="Deteksi Bahasa dan Enkode secara Otomatis"/> + <node name="defaultLanguage" value="Bahasa Standar"/> + <node name="defaultEncodingSet" value="Set Enkode Standar"/> + <node name="defaultEncoding" value="Enkode Standar"/> + <node name="useWindows1252Hack" value="Gunakan windows-1252 daripada iso-8859-1"/> + </node> + <node name="Config" value="Konfigurasi"> + <node name="autoSave" value="Simpan Status Secara Otomatis"/> + <node name="timeout" value="Waktu Tunda Antara Penyimpanan, detik"/> + </node> + <node name="Dictionary" value="Kamus"> + <node name="enableIntegration" value="Aktifkan Integrasi dengan %s"/> + <node name="defaultText" value="Aktifkan Integrasi dengan Kamus"/> + <node name="choice" value="Integrasikan dengan"/> + <node name="singleClickOpen" value="Buka dengan Klik Tunggal"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Tombol Aktif saat Dilepas, bukan saat Ditekan"/> + <node name="minStylusPressure" value="Tekanan Minimal Stylus"/> + <node name="maxStylusPressure" value="Tekanan Maksimal Stylus"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Geser Layar"> + <node name="keyScrollDelay" toBeTranslated="true" value="Delay between Key Scrollings, msecs"/> + <node name="keyLinesToScroll" toBeTranslated="true" value="Lines to Scroll per Line Scrolling"/> + <node name="keyLinesToKeep" toBeTranslated="true" value="Lines to Keep per Page Scrolling"/> + <node name="enableTapScrolling" toBeTranslated="true" value="Enable Tap Scrolling"/> + <node name="fingerOnly" value="Geser Hanya Menggunakan Layar Sentuh"/> + </node> + <node name="Selection" value="Seleksi"> + <node name="enableSelection" value="Aktifkan Seleksi Teks"/> + </node> + <node name="Indicator" value="Indikator"> + <node name="type" value="Tampilkan sebagai"> + <node name="osScrollbar" value="Scrollbar OS"/> + <node name="fbIndicator" value="Indikator Model Lama"/> + <node name="none" value="Jangan Ditampilkan"/> + </node> + <node name="height" value="Tinggi Indikator"/> + <node name="offset" value="Jarak dari Teks"/> + <node name="pageNumber" value="Tampilkan Posisi sebagai Nomor"/> + <node name="time" value="Tampilkan Waktu"/> + <node name="fontSize" value="Ukuran Huruf"/> + <node name="tocMarks" value="Tampilkan Penanda Daftar Isi"/> + <node name="navigation" value="Aktifkan Navigasi"/> + </node> + <node name="Rotation" value="Rotasi"> + <node name="direction" value="Tipe Rotasi"> + <node name="disabled" value="Non-aktifkan"/> + <node name="clockwise" value="90 Derajat Searah Jarum Jam"/> + <node name="counterclockwise" value="90 Derajat Berlawanan Jarum Jam"/> + <node name="180" value="180 Derajat"/> + <node name="cycle" value="Rotasi 4 Arah Bergantian"/> + </node> + </node> + <node name="Keys" value="Tombol"> + <node name="grabSystemKeys" value="Tangkap Tombol Sistem"/> + <node name="separate" value="Tombol Tergantung dari Orientasi"/> + <node name="orientation" value="Orientasi"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Tidak Terpakai"/> + <node name="showLibrary" value="Tampilkan Pustaka"/> + <node name="showNetLibrary" value="Tampilkan Pustaka Jaringan"/> + <node name="showRecent" value="Tampilkan Buku-buku Sebelumnya"/> + <node name="previousBook" value="Buka Buku Sebelumnya"/> + <node name="toc" value="Tampilkan Daftar Isi"/> + <node name="gotoHome" value="Ke Awal Dokumen"/> + <node name="gotoSectionStart" value="Ke Awal Seksi"/> + <node name="gotoSectionEnd" value="Ke Akhir Seksi"/> + <node name="nextTOCSection" value="Ke Seksi Daftar Isi Berikutnya"/> + <node name="previousTOCSection" value="Ke Seksi Daftar Isi Sebelumnya"/> + <node name="pageForward" toBeTranslated="true" value="Scroll page forward"/> + <node name="pageBackward" toBeTranslated="true" value="Scroll page backward"/> + <node name="lineForward" toBeTranslated="true" value="Scroll line forward"/> + <node name="lineBackward" toBeTranslated="true" value="Scroll line backward"/> + <node name="undo" value="Mundur"/> + <node name="redo" value="Maju"/> + <node name="copyToClipboard" value="Salin Teks yang Diseleksi ke Clipboard"/> + <node name="openInDictionary" value="Buka Teks yang Diseleksi di Kamus"/> + <node name="clearSelection" value="Bersihkan Seleksi"/> + <node name="search" value="Pencarian"/> + <node name="findPrevious" value="Pencarian Mundur"/> + <node name="findNext" value="Pencarian Maju"/> + <node name="increaseFont" value="Besarkan Ukuran Huruf"/> + <node name="decreaseFont" value="Kecilkan Ukuran Huruf"/> + <node name="toggleIndicator" value="Hidup/Matikan Indikator"/> + <node name="toggleFullscreen" value="Hidup/Matikan Layar Penuh"/> + <node name="rotate" value="Putar Layar"/> + <node name="addBook" value="Tambah Buku"/> + <node name="cancel" value="Batal"/> + <node name="quit" value="Keluar"/> + <node name="bookInfo" value="Tampilkan Dialog Informasi Buku"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Keluar dari Aplikasi Ketika Pembatalan"/> + <node name="keyDelay" value="Waktu Tunda Antara Penekanan Tombol"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Gunakan Selalu Bentuk Huruf Milik Saya"/> + </node> + <node name="Margins" value="Margin"> + <node name="left" value="Margin Kiri"/> + <node name="right" value="Margin Kanan"/> + <node name="top" value="Margin Atas"/> + <node name="bottom" value="Margin Bawah"/> + </node> + <node name="Format" value="Format"> + <node name="optionsFor" value="Pengaturan untuk"/> + <node name="lineSpacing" value="Jarak Baris"> + <node name="unchanged" value="<tidak diubah>"/> + </node> + <node name="firstLineIndent" value="Indentasi Baris Pertama"/> + <node name="alignment" value="Perataan Teks"> + <node name="left" value="Kiri"/> + <node name="right" value="Kanan"/> + <node name="center" value="Tengah"/> + <node name="justify" value="Rata Kanan Kiri"/> + <node name="unchanged" value="<tidak diubah>"/> + </node> + <node name="spaceBefore" value="Jarak Sebelumnya"/> + <node name="spaceAfter" value="Jarak Setelahnya"/> + <node name="startIndent" value="Indentasi Baris Awal"/> + <node name="endIndent" value="Indentasi Baris Akhir"/> + </node> + <node name="Styles" value="Bentuk"> + <node name="optionsFor" value="Pengaturan untuk"/> + <node name="fontFamily" value="Keluarga"> + <node name="unchanged" value="<tidak diubah>"/> + </node> + <node name="fontSize" value="Ukuran"/> + <node name="fontSizeDifference" value="Perbedaan Ukuran"/> + <node name="bold" value="Tebal"/> + <node name="italic" value="Miring"/> + <node name="allowHyphenations" value="Ijinkan Pemenggalan Kata"/> + <node name="autoHyphenations" value="Pemenggalan Kata Otomatis"/> + </node> + <node name="Colors" value="Warna"> + <node name="colorFor" value="Warna untuk"> + <node name="background" value="Latar Belakang"/> + <node name="selectionBackground" value="Latar Belakang Seleksi"/> + <node name="text" value="Teks Biasa"/> + <node name="internalLink" value="Tautan Teks Internal"/> + <node name="externalLink" value="Tautan Teks Eksternal"/> + <node name="bookLink" value="Tautan ke Buku Lainnya"/> + <node name="highlighted" value="Teks Berwarna Cerah"/> + <node name="treeLines" value="Garis Diagram Pohon"/> + <node name="indicator" value="Indikator Posisi"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informasi Buku"/> + <node name="tab"> + <node name="Common" value="Umum"> + <node name="file" value="Berkas"/> + <node name="title" value="Judul"/> + <node name="language" value="Bahasa"/> + <node name="encodingSet" value="Set Enkode"/> + <node name="encoding" value="Enkode"/> + </node> + <node name="Authors" toBeTranslated="true" value="Authors"> + <node name="authorDisplayName" toBeTranslated="true" value="Author Name"/> + </node> + <node name="Series" value="Seri"> + <node name="seriesTitle" value="Judul Seri"/> + <node name="bookIndex" value="Nomor Buku"/> + </node> + <node name="Tags" value="Tag"> + <node name="tags" toBeTranslated="true" value="Tag Name"/> + </node> + <node name="Text" value="Teks"> + <node name="breakType" value="Penggal Paragraf pada"/> + <node name="ignoreIndent" value="Abaikan Indentasi Kurang dari"/> + <node name="buildTOC" value="Buat Daftar Isi"/> + <node name="emptyLines" value="Baris Kosong Sebelum Seksi Baru"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Penggal Paragraf pada"/> + <node name="ignoreIndent" value="Abaikan Indentasi Kurang dari"/> + <node name="buildTOC" value="Buat Daftar Isi"/> + <node name="emptyLines" value="Baris Kosong Sebelum Seksi Baru"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Author Info"/> + <node name="name" toBeTranslated="true" value="Author Name"/> + <node name="sortKey" toBeTranslated="true" value="Author Sort Key"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Tambahkan Buku ke Pustaka"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Pencarian Text"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Abaikan huruf besar/kecil"/> + <node name="wholeText" value="&Dalam keseluruhan teks"/> + <node name="backward" value="&Pencarian mundur"/> + <node name="currentSection" value="&Hanya dalam seksi ini"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Pencarian Jaringan"/> + <node name="titleAndSeries" value="Judul/Seri"/> + <node name="author" value="Pengarang"/> + <node name="category" value="Kategori"/> + <node name="description" value="Deskripsi"/> + <node name="annotation" toBeTranslated="true" value="Search results for: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Ke Halaman"/> + <node name="pageNumber" value="Ke Nomor Halaman"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Ubah Tag"/> + <node name="name" value="Nama Tag"/> + <node name="includeSubtags" value="Termasuk Sub Tag"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Gandakan Tag"/> + <node name="name" value="Nama Tag"/> + <node name="includeSubtags" value="Termasuk Sub Tag"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Hapus Buku"/> + <node name="message" value="Hapus buku "%s" dari Pustaka?"/> + <node name="deleteFile" toBeTranslated="true" value="Are you sure you want to remove file “%s†from the disk?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Hapus Tag"/> + <node name="message" value="Hapus Tag “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Ada Kesalahan"/> + <node name="message" value="Tidak dapat membuka: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" toBeTranslated="true" value="Error"/> + <node name="message" toBeTranslated="true" value="Couldn't remove file %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Ada Kesalahan"/> + <node name="message" value="Berkas tidak ditemukan, maaf"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Daftar pustaka kosong"/> + <node name="authenticationFailed" toBeTranslated="true" value="Authentication failed"/> + <node name="internalError" toBeTranslated="true" value="Internal server error"/> + <node name="purchaseNotEnoughMoney" toBeTranslated="true" value="Not enough money"/> + <node name="purchaseMissingBook" toBeTranslated="true" value="Missing book"/> + <node name="purchaseAlreadyPurchased" toBeTranslated="true" value="Already purchased"/> + <node name="bookNotPurchased" toBeTranslated="true" value="Book was not purchased"/> + <node name="downloadLimitExceeded" toBeTranslated="true" value="Download limit exceeded"/> + <node name="unsupportedOperation" toBeTranslated="true" value="Unsupported operation"/> + <node name="loginAlreadyTaken" toBeTranslated="true" value="Username is already in use"/> + <node name="loginNotSpecified" toBeTranslated="true" value="Please, enter a username"/> + <node name="passwordNotSpecified" toBeTranslated="true" value="Please, enter a non-empty password"/> + <node name="emailNotSpecified" toBeTranslated="true" value="Please, enter an e-mail address"/> + <node name="invalidEMail" toBeTranslated="true" value="Invalid e-mail address"/> + <node name="tooManyRegistrations" toBeTranslated="true" value="Too many registrations from your IP; try again in a few minutes"/> + <node name="noUserEmail" toBeTranslated="true" value="No user was registered with specified e-mail address"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Bermasalah waktu melakukan download"/> + <node name="message" value="Sementara tidak dapat melakukan download buku ini"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Membaca buku. Silakan tunggu..."/> + <node name="loadingBookList" value="Membaca daftar buku. Silakan tunggu..."/> + <node name="migrate" value="Melakukan pembaruan ke versi baru. Silakan tunggu..."/> + <node name="downloadBookList" value="Daftar buku sedang di-download. Harap tunggu..."/> + <node name="downloadBook" value="Buku sedang di-download. Harap tunggu..."/> + <node name="downloadImages" toBeTranslated="true" value="Downloading images. Please, wait..."/> + <node name="authentication" toBeTranslated="true" value="Authentication. Please, wait..."/> + <node name="purchaseBook" toBeTranslated="true" value="Purchase book. Please, wait..."/> + <node name="initializeAuthenticationManager" toBeTranslated="true" value="Downloading account information. Please, wait..."/> + <node name="loadSubCatalog" toBeTranslated="true" value="Loading catalog. Please, wait..."/> + <node name="registerUser" toBeTranslated="true" value="Registering new account. Please, wait..."/> + <node name="passwordRecovery" toBeTranslated="true" value="Recovering password. Please, wait..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" toBeTranslated="true" value="Purchase book"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to buy “%s†book?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" toBeTranslated="true" value="Authentication"/> + <node name="login" toBeTranslated="true" value="Username"/> + <node name="password" toBeTranslated="true" value="Password"/> + <node name="skipIP" toBeTranslated="true" value="Don't bound to ip-address"/> + <node name="loginIsEmpty" toBeTranslated="true" value="Username should be non-empty"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" toBeTranslated="true" value="Information"/> + <node name="message" toBeTranslated="true" value="Catalog is empty."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" toBeTranslated="true" value="Disable catalog"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to disable “%s†catalog? ou can enable it in the future at “Network Search†tab in the Options dialog."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" toBeTranslated="true" value="Delete Book"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to remove “%s†book from the disk?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" toBeTranslated="true" value="Register User"/> + <node name="login" toBeTranslated="true" value="Username"/> + <node name="password" toBeTranslated="true" value="Password"/> + <node name="confirmPassword" toBeTranslated="true" value="Password confirmation"/> + <node name="email" toBeTranslated="true" value="E-mail"/> + <node name="differentPasswords" toBeTranslated="true" value="Password and password confirmation must be the same."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" toBeTranslated="true" value="Password Recovery"/> + <node name="email" toBeTranslated="true" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" toBeTranslated="true" value="Password Recovery"/> + <node name="message" toBeTranslated="true" value="A message with further instructions has been sent to %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" toBeTranslated="true" value="Download Error"/> + <node name="message" toBeTranslated="true" value="Can't open downloaded file %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Dasar"/> + <node name="Regular Paragraph" value="Paragraf Biasa"/> + <node name="Title" value="Judul"/> + <node name="Section Title" value="Judul Seksi"/> + <node name="Poem Title" value="Judul Syair"/> + <node name="Subtitle" value="Sub Judul"/> + <node name="Annotation" value="Anotasi"/> + <node name="Epigraph" value="Inskripsi"/> + <node name="Stanza" value="Bait"/> + <node name="Verse" value="Ayat"/> + <node name="Preformatted text" value="Teks Terformat"/> + <node name="Image" value="Gambar"/> + <node name="Cite" value="Cuplikan"/> + <node name="Author" value="Pengarang"/> + <node name="Date" value="Tanggal"/> + <node name="Internal Hyperlink" value="Tautan Internal"/> + <node name="Footnote" value="Catatan Kaki"/> + <node name="Emphasis" value="Aksentuasi"/> + <node name="Strong" value="Strong"/> + <node name="Subscript" value="Subscript"/> + <node name="Superscript" value="Superscript"/> + <node name="Code" value="Kode"/> + <node name="StrikeThrough" value="Teks Tercoret"/> + <node name="Contents Table" value="Daftar Isi"/> + <node name="Library Entry" value="Entri Pustaka"/> + <node name="Recent Book List" value="Daftar Buku-buku Sebelumnya"/> + <node name="Italic" value="Miring"/> + <node name="Bold" value="Tebal"/> + <node name="Definition" value="Definisi"/> + <node name="Definition Description" value="Deskripsi Definisi"/> + <node name="Header 1" value="Header 1"/> + <node name="Header 2" value="Header 2"/> + <node name="Header 3" value="Header 3"/> + <node name="Header 4" value="Header 4"/> + <node name="Header 5" value="Header 5"/> + <node name="Header 6" value="Header 6"/> + <node name="External Hyperlink" value="Tautan Eksternal"/> + <node name="Link to Another Book" value="Tautan ke Buku Lain"/> + </node> + <node name="external"> + <node name="browser" value="Browser"/> + <node name="defaultBrowser" value="Browser Standar"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Ada Kesalahan"/> + <node name="unsupportedCompressionMethod" value="Metode kompresi tidak didukung"/> + <node name="encryptedFile" value="Berkas terproteksi DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Pustaka Jaringan"/> + </node> + <node name="library"> + <node name="caption" value="Pustaka"/> + </node> +</resources> diff --git a/reader/data/resources/it.xml b/reader/data/resources/it.xml new file mode 100644 index 0000000..df2d10c --- /dev/null +++ b/reader/data/resources/it.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Italian TDE-Ebook-Reader resources, by Floriano Scioscia --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Mostra libri"/> + <node name="collapseTree" value="Nascondi libri"/> + <node name="edit" tvalue="Modifica informazioni"/> + <node name="unknownAuthor" value="Autore Sconosciuto"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Mostra libri"/> + <node name="collapseTree" value="Nascondi libri"/> + <node name="edit" value="Modifica etichetta"/> + <node name="clone" value="Duplica etichetta"/> + <node name="delete" value="Elimina etichetta"/> + <node name="noTags" value="Libri senza etichette"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Mostra libri"/> + <node name="collapseTree" value="Nascondi libri"/> + </node> + <node name="bookNode"> + <node name="read" value="Leggi libro"/> + <node name="edit" value="Modifica informazioni"/> + <node name="delete" value="Elimina libro"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Per autore"> + <node name="summary" value="Libri ordinati per autore"/> + </node> + <node name="byTitle" value="Per titolo"> + <node name="summary" value="Libri ordinati per titolo"/> + </node> + <node name="byDate" value="Per data"> + <node name="summary" value="Libri ordinati per data di acquisto"/> + </node> + <node name="bySeries" value="Per serie"> + <node name="summary" value="Libri ordinati per serie"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Espandi"/> + <node name="collapseTree" value="Riduci"/> + <node name="reload" value="Ricarica"/> + <node name="openInBrowser" value="Apri nel browser"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Apri catalogo"/> + <node name="collapseTree" value="Chiudi catalogo"/> + <node name="login" value="Accedi"/> + <node name="logout" value="Esci (%s)"/> + <node name="reload" value="Ricarica"/> + <node name="dontShow" value="Non mostrare questo catalogo"/> + <node name="topupAccount" value="Fai una ricarica (attualmente: %s)"/> + <node name="register" value="Registrati"/> + <node name="passwordRecovery" value="Recupera password"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Cerca risultati"/> + <node name="expandTree" value="Mostra risultati"/> + <node name="collapseTree" value="Nascondi risultati"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Mostra libri"/> + <node name="collapseTree" value="Nascondi libri"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Mostra libri"/> + <node name="collapseTree" value="Nascondi libri"/> + </node> + <node name="bookNode"> + <node name="read" value="Leggi copia locale"/> + <node name="delete" value="Elimina copia locale"/> + <node name="download" value="Scarica"/> + <node name="readDemo" value="Leggi demo"/> + <node name="downloadDemo" value="Scarica demo"/> + <node name="demo" value="demo"/> + <node name="buy" value="Compra (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informazioni Libro..."/> + <node name="toc" value="Indice"/> + <node name="showLibrary" value="Apri biblioteca"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Biblioteca"> + <node name="showLibrary" value="Apri"/> + <node name="previousBook" value="Libro Precedente"/> + <node name="showRecent" value="Recenti"/> + <node name="addBook" value="Aggiungi Libro..."/> + <node name="showHelp" value="Informazioni su TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Vai all'Inizio del Documento"/> + <node name="gotoPageNumber" value="Vai a Pagina..."/> + <node name="gotoSectionStart" value="Vai all'Inizio di Sezione"/> + <node name="gotoSectionEnd" value="Vai alla Fine di Sezione"/> + <node name="nextTOCSection" value="Vai al Successivo Elemento dell'Indice"/> + <node name="previousTOCSection" value="Vai al Precedente Elemento dell'Indice"/> + <node name="navigate" value="Navigazione"> + <node name="gotoHome" value="Vai all'Inizio del Documento"/> + <node name="gotoPageNumber" value="Vai a Pagina..."/> + <node name="gotoSectionStart" value="Vai all'Inizio di Sezione"/> + <node name="gotoSectionEnd" value="Vai alla Fine di Sezione"/> + <node name="nextTOCSection" value="Vai al Successivo Elemento dell'Indice"/> + <node name="previousTOCSection" value="Vai al Precedente Elemento dell'Indice"/> + <node name="undo" value="Vai Indietro"/> + <node name="redo" value="Vai Avanti"/> + </node> + <node name="selection" value="Selezione"> + <node name="copyToClipboard" value="Copia negli Appunti"/> + <node name="openInDictionary" value="Apri in Dizionario"/> + <node name="clearSelection" value="Deseleziona"/> + </node> + <node name="search" value="Trova"> + <node name="search" value="Trova Testo..."/> + <node name="findNext" value="Trova Successivo"/> + <node name="findPrevious" value="Trova Precedente"/> + </node> + <node name="view" value="Visualizzazione"> + <node name="rotate" value="Ruota Schermo"/> + <node name="toggleFullscreen" value="A Tutto Schermo"/> + <node name="toggleIndicator" value="Alterna Indicatore"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Chiudi"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" value="Mostra Modalità Lettura"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Mostra Albero Biblioteca"/> + <node name="popup" value="Mostra Elenco Libri Recenti"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Mostra Elenco Libri Recenti"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" value="Organizza Libri per Autore"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" value="Organizza Libri per Etichette"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Aggiungi File alla Biblioteca"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" value="Cerca in Biblioteche in Rete"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" value="Ricerca Rete"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Ricerca Rete Avanzata"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="Vai all'Inizio del Testo"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="Vai Indietro"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="Vai Avanti"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" value="Vai a Pagina"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="Indice"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Trova Testo"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Trova Successivo"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Trova Precedente"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Ruota Testo"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="Informazioni su TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Mostra Finestra Informazioni Libro"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Vai!"/> + <node name="thisOnly" value="Solo questo"/> + <node name="withSubtags" value="Con sotto-etichette"/> + <node name="removeLink" value="Elimina dalla biblioteca"/> + <node name="removeFile" value="Elimina dal disco"/> + <node name="yesToAll" value="Sì a tutti"/> + <node name="buy" value="&Compra"/> + <node name="buyAndDownload" value="Compra e &scarica"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Biblioteca"> + <node name="bookPath" value="Percorso Libri"/> + <node name="lookInSubdirectories" value="Cerca Libri in Sottocartelle"/> + <node name="collectBooksWithoutMetaInfo" value="Raccogli Libri senza Metadati"/> + <node name="downloadDirectory" value="Cartella per Libri Scaricati"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Ricerca Rete"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Usa Proxy"/> + <node name="proxyHost" value="Host del Proxy"/> + <node name="proxyPort" value="Porta del Proxy"/> + <node name="timeout" value="Tempo Limite per Operazioni di Rete, secondi"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Apri Collegamenti Esterni in %s"/> + <node name="defaultText" value="Apri Collegamenti Esterni in Browser"/> + <node name="choice" value="Usa Browser"/> + <node name="command" value="Comando da Eseguire"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Lingua"> + <node name="autoDetect" value="Riconosci Lingua e Codifica Automaticamente"/> + <node name="defaultLanguage" value="Lingua Predefinita"/> + <node name="defaultEncodingSet" value="Insieme Predefinito di Codifica"/> + <node name="defaultEncoding" value="Codifica Predefinita"/> + <node name="useWindows1252Hack" value="Usa windows-1252 invece di iso-8859-1"/> + </node> + <node name="Config" value="Configurazione"> + <node name="autoSave" value="Salva Stato Automaticamente"/> + <node name="timeout" value="Intervallo tra Salvataggi, sec"/> + </node> + <node name="Dictionary" value="Dizionario"> + <node name="enableIntegration" value="Abilita Integrazione con %s"/> + <node name="defaultText" value="Abilita Integrazione con Dizionario"/> + <node name="choice" value="Integra con"/> + <node name="singleClickOpen" value="Apri con Clic Singolo"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Azione su Rilascio Tasto, non su Pressione"/> + <node name="minStylusPressure" value="Pressione Minima con Pennino"/> + <node name="maxStylusPressure" value="Pressione Massima con Pennino"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Scorrimento"> + <node name="keyScrollDelay" value="Rtiardo tra Scorrimento Tasti, msec"/> + <node name="keyLinesToScroll" value="Righe da Scorrere con Scorrimento Righe"/> + <node name="keyLinesToKeep" value="Righe da Mantenere in Scorrimento Pagina"/> + <node name="enableTapScrolling" value="Abilita Scorrimento al Tocco"/> + <node name="fingerOnly" value="Scorri Solo con Tocco delle Dita"/> + </node> + <node name="Selection" value="Selezione"> + <node name="enableSelection" value="Abilita Selezione Testo"/> + </node> + <node name="Indicator" value="Indicatore"> + <node name="type" value="Mostra come"> + <node name="osScrollbar" value="Barra di Scorrimento del Sistema"/> + <node name="fbIndicator" value="Indicatore Vecchio Stile"/> + <node name="none" value="Non Mostrare"/> + </node> + <node name="height" value="Altezza Indicatore"/> + <node name="offset" value="Distanza dal Testo"/> + <node name="pageNumber" value="Mostra Posizione come Numero"/> + <node name="time" value="Mostra Orario"/> + <node name="fontSize" value="Dimensioni Carattere"/> + <node name="tocMarks" value="Mostra Segni Indice"/> + <node name="navigation" value="Abilita Navigazione"/> + </node> + <node name="Rotation" value="Rotazione"> + <node name="direction" value="Tipo di Rotazione"> + <node name="disabled" value="Disabilitata"/> + <node name="clockwise" value="Oraria 90 Gradi"/> + <node name="counterclockwise" value="Antioraria 90 Gradi"/> + <node name="180" value="180 Gradi"/> + <node name="cycle" value="Cicla Tra Tutte le 4 Direzioni"/> + </node> + </node> + <node name="Keys" value="Tasti"> + <node name="grabSystemKeys" value="Intercetta Tasti di Sistema"/> + <node name="separate" value="Funzione Tasti Dipendente dall'Orientamento"/> + <node name="orientation" value="Orientamento"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Nessuno"/> + <node name="showLibrary" value="Mostra Biblioteca"/> + <node name="showNetLibrary" value="Mostra biblioteca in rete"/> + <node name="showRecent" value="Mostra Libri Recenti"/> + <node name="previousBook" value="Apri Libro Precedente"/> + <node name="toc" value="Mostra Indice"/> + <node name="gotoHome" value="Vai alla Pagina Principale"/> + <node name="gotoSectionStart" value="Vai all'Inizio di Sezione"/> + <node name="gotoSectionEnd" value="Vai alla Fine di Sezione"/> + <node name="nextTOCSection" value="Vai alla Sezione Successiva dell'Indice"/> + <node name="previousTOCSection" value="Vai alla Sezione Precedente dell'Indice"/> + <node name="pageForward" value="Scorri pagina in avanti"/> + <node name="pageBackward" value="Sorri pagina indietro"/> + <node name="lineForward" value="Scorri riga in avanti"/> + <node name="lineBackward" value="Scroll riga indietro"/> + <node name="undo" value="Annulla"/> + <node name="redo" value="Ripristina"/> + <node name="copyToClipboard" value="Copia Testo Selezionato negli Appunti"/> + <node name="openInDictionary" value="Apri Testo Selezionato in Dizionario"/> + <node name="clearSelection" value="Deseleziona"/> + <node name="search" value="Trova"/> + <node name="findPrevious" value="Trova Precedente"/> + <node name="findNext" value="Trova Successivo"/> + <node name="increaseFont" value="Ingrandisci Carattere"/> + <node name="decreaseFont" value="Riduci Carattere"/> + <node name="toggleIndicator" value="Alterna Indicatore di Posizione"/> + <node name="toggleFullscreen" value="Alterna Modalità Schermo Intero"/> + <node name="rotate" value="Ruota Schermo"/> + <node name="addBook" value="Aggiungi Libro"/> + <node name="cancel" value="Annulla"/> + <node name="quit" value="Esci"/> + <node name="bookInfo" value="Mostra Finestra Informazioni Libro"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Esci dall'Applicazione su Annullamento"/> + <node name="keyDelay" value="Ritardo Tra Pressione Tasti Accettati"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Usa Sempre i Miei Font"/> + </node> + <node name="Margins" value="Margini"> + <node name="left" value="Margine Sinistro"/> + <node name="right" value="Margine Destro"/> + <node name="top" value="Margine Superiore"/> + <node name="bottom" value="Margine Inferiore"/> + </node> + <node name="Format" value="Formato"> + <node name="optionsFor" value="Opzioni per"/> + <node name="lineSpacing" value="Spaziatura Righe"> + <node name="unchanged" value="<invariata>"/> + </node> + <node name="firstLineIndent" value="Rientro Prima Riga"/> + <node name="alignment" value="Allineamento"> + <node name="left" value="Sinistra"/> + <node name="right" value="Destra"/> + <node name="center" value="Centrato"/> + <node name="justify" value="Giustificato"/> + <node name="unchanged" value="<invariato>"/> + </node> + <node name="spaceBefore" value="Spazio Prima"/> + <node name="spaceAfter" value="Spazio Dopo"/> + <node name="startIndent" value="Rientro Inizio Riga"/> + <node name="endIndent" value="Rientro Fine Riga"/> + </node> + <node name="Styles" value="Stili"> + <node name="optionsFor" value="Opzioni per"/> + <node name="fontFamily" value="Famiglia Caratteri"> + <node name="unchanged" value="<invariata>"/> + </node> + <node name="fontSize" value="Dimensioni"/> + <node name="fontSizeDifference" value="Differenza di Dimensioni"/> + <node name="bold" value="Grassetto"/> + <node name="italic" value="Corsivo"/> + <node name="allowHyphenations" value="Permetti Sillabazione"/> + <node name="autoHyphenations" value="Sillabazione Automatica"/> + </node> + <node name="Colors" value="Colori"> + <node name="colorFor" value="Colore di"> + <node name="background" value="Sfondo"/> + <node name="selectionBackground" value="Sfondo della Selezione"/> + <node name="text" value="Testo Normale"/> + <node name="internalLink" value="Testo Collegamento Interno"/> + <node name="externalLink" value="Testo Collegamento Esterno"/> + <node name="bookLink" value="Link ad Altro Libro"/> + <node name="highlighted" value="Testo Evidenziato"/> + <node name="treeLines" value="Linee Albero"/> + <node name="indicator" value="Indicatore Posizione"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informazioni Libro"/> + <node name="tab"> + <node name="Common" value="Comuni"> + <node name="file" value="File"/> + <node name="title" value="Titolo"/> + <node name="language" value="Lingua"/> + <node name="encodingSet" value="Insieme di Codifica"/> + <node name="encoding" value="Codifica"/> + </node> + <node name="Authors" value="Autori"> + <node name="authorDisplayName" value="Nome dell'Autore"/> + </node> + <node name="Series" value="Serie"> + <node name="seriesTitle" value="Titolo della Serie"/> + <node name="bookIndex" value="Libro Numero"/> + </node> + <node name="Tags" value="Etichetta"> + <node name="tags" value="Nome dell'etichetta"/> + </node> + <node name="Text" value="Testo"> + <node name="breakType" value="Interrompi Paragrafo a"/> + <node name="ignoreIndent" value="Ignora Rientri Inferiori a"/> + <node name="buildTOC" value="Crea Indice"/> + <node name="emptyLines" value="Righe Vuote Prima di Nuova Sezione"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Interrompi Paragrafo a"/> + <node name="ignoreIndent" value="Ignora Rientri Inferiori a"/> + <node name="buildTOC" value="Crea Indice"/> + <node name="emptyLines" value="Righe Vuote Prima di Nuova Sezione"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informazioni sull'Autore"/> + <node name="name" value="Nome dell'Autore"/> + <node name="sortKey" value="Tasto Ordinamento Autori"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Aggiungi Libro alla Biblioteca"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Trova Testo"/> + <node name="text" value="Testo"/> + <node name="ignoreCase" value="&Ignora maiuscole/minuscole"/> + <node name="wholeText" value="In &tutto il testo"/> + <node name="backward" value="&All'indietro"/> + <node name="currentSection" value="&Solo questa sezione"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Ricerca Rete"/> + <node name="titleAndSeries" value="Titolo/Serie"/> + <node name="author" value="Autore"/> + <node name="category" value="Categoria"/> + <node name="description" value="Descrizione"/> + <node name="annotation" value="Cerca risultati per: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Vai a Pagina"/> + <node name="pageNumber" value="Vai a Numero di Pagina"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Modifica Etichetta"/> + <node name="name" value="Nome Etichetta"/> + <node name="includeSubtags" value="Includi Sotto-etichette"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Duplica Etichetta"/> + <node name="name" value="Nome Etichetta"/> + <node name="includeSubtags" value="Includi Sotto-etichette"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Elimina Libro"/> + <node name="message" value="Eliminare il Libro "%s" dalla Biblioteca?"/> + <node name="deleteFile" value="Sei sicuro di voler eliminare il file “%s†dal disco?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Elimina Etichetta"/> + <node name="message" value="Eliminare l'Etichetta“%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Errore"/> + <node name="message" value="Impossibile aprire: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Errore"/> + <node name="message" value="Impossibile eliminare il file %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Errore"/> + <node name="message" value="Spiacente, file della Guida non trovato"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Elenco biblioteche vuoto"/> + <node name="authenticationFailed" value="Autenticazione fallita"/> + <node name="internalError" value="Errore interno del server"/> + <node name="purchaseNotEnoughMoney" value="Denaro insufficiente"/> + <node name="purchaseMissingBook" value="Libro mancante"/> + <node name="purchaseAlreadyPurchased" value="Già acquistato"/> + <node name="bookNotPurchased" value="Il libro non è stato acquistato"/> + <node name="downloadLimitExceeded" value="Limite di scaricamento superato"/> + <node name="unsupportedOperation" value="Operazione non supportata"/> + <node name="loginAlreadyTaken" value="Il nome utente è già usato"/> + <node name="loginNotSpecified" value="Prego, inserire un nome utente"/> + <node name="passwordNotSpecified" value="Prego, inserire una password non vuota"/> + <node name="emailNotSpecified" value="Prego, inserire un indirizzo e-mail"/> + <node name="invalidEMail" value="Indirizzo e-mail non valido"/> + <node name="tooManyRegistrations" value="Troppe registrazioni dal tuo IP; riprovare fra qualche minuto"/> + <node name="noUserEmail" value="Nessun utente risulta registrato con l'indirizzo e-mail specificato"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Errore durante lo scaricamento"/> + <node name="message" value="Impossibile scaricare questo libro al momento"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Caricamento libro. Attendere, prego..."/> + <node name="loadingBookList" value="Caricamento elenco libri. Attendere, prego..."/> + <node name="migrate" value="Aggiornamento alla nuova versione. Attendere, prego..."/> + <node name="downloadBookList" value="Scaricamento elenco libri. Attendere, prego..."/> + <node name="downloadBook" value="Scaricamento libro. Attendere, prego..."/> + <node name="downloadImages" value="Scaricamento immagini in corso. Attendere, prego..."/> + <node name="authentication" value="Autenticazione. Attendere, prego..."/> + <node name="purchaseBook" value="Acquisto del libro. Attendere, prego..."/> + <node name="initializeAuthenticationManager" value="Scaricamento informazioni account in corso. Attendere, prego..."/> + <node name="loadSubCatalog" value="Caricamento catalogo. Attendere, prego..."/> + <node name="registerUser" value="Registrazione nuovo account in corso. Attendere, prego..."/> + <node name="passwordRecovery" value="Recupero password in corso. Attendere, prego..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Acquista libro"/> + <node name="message" value="Sei sicuro di voler comprare il libro “%s†?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Autenticazione"/> + <node name="login" value="Nome utente"/> + <node name="password" value="Password"/> + <node name="skipIP" value="Non legare a indirizzo IP"/> + <node name="loginIsEmpty" value="Il nome utente deve essere non vuoto"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informazioni"/> + <node name="message" value="Il catalogo è vuoto."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Disabilita catalogo"/> + <node name="message" value="Sei sicuro di voler disabilitare il catalogo “%sâ€? Potrai abilitarlo in seguito dalla scheda “Ricerca in Rete†nella finestra Opzioni."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Elimina Libro"/> + <node name="message" value="Sei sicuro di voler eliminare il libro “%s†dal disco?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Registra Utente"/> + <node name="login" value="Nome utente"/> + <node name="password" value="Password"/> + <node name="confirmPassword" value="Conferma password"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="Password e conferma password devono coincidere."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Recupero Password"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Recupero Password"/> + <node name="message" value="Un messaggio con ulteriori istruzioni èstato inviato a %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Errore di Scaricamento"/> + <node name="message" value="Impossibile aprire il file scaricato %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Base"/> + <node name="Regular Paragraph" value="Paragrafo Normale"/> + <node name="Title" value="Titolo"/> + <node name="Section Title" value="Titolo di Sezione"/> + <node name="Poem Title" value="Titolo di Poesia"/> + <node name="Subtitle" value="Sottotitolo"/> + <node name="Annotation" value="Annozione"/> + <node name="Epigraph" value="Epigrafe"/> + <node name="Stanza" value="Strofa"/> + <node name="Verse" value="Verso"/> + <node name="Preformatted text" value="Testo preformattato"/> + <node name="Image" value="Immagine"/> + <node name="Cite" value="Citazione"/> + <node name="Author" value="Autore"/> + <node name="Date" value="Data"/> + <node name="Internal Hyperlink" value="Collegamento Interno"/> + <node name="Footnote" value="Nota"/> + <node name="Emphasis" value="Enfasi"/> + <node name="Strong" value="Rafforzato"/> + <node name="Subscript" value="Pedice"/> + <node name="Superscript" value="Apice"/> + <node name="Code" value="Codice"/> + <node name="StrikeThrough" value="Barrato"/> + <node name="Contents Table" value="Tabella di Contenuti"/> + <node name="Library Entry" value="Voce di Biblioteca"/> + <node name="Recent Book List" value="Elenco Libri Recenti"/> + <node name="Italic" value="Corsivo"/> + <node name="Bold" value="Grassetto"/> + <node name="Definition" value="Definizione"/> + <node name="Definition Description" value="Descrizione di Definizione"/> + <node name="Header 1" value="Intestazione 1"/> + <node name="Header 2" value="Intestazione 2"/> + <node name="Header 3" value="Intestazione 3"/> + <node name="Header 4" value="Intestazione 4"/> + <node name="Header 5" value="Intestazione 5"/> + <node name="Header 6" value="Intestazione 6"/> + <node name="External Hyperlink" value="Collegamento Esterno"/> + <node name="Link to Another Book" value="Collegamento ad Altro Libro"/> + </node> + <node name="external"> + <node name="browser" value="Browser"/> + <node name="defaultBrowser" value="Browser Predefinito"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Errore Sconosciuto"/> + <node name="unsupportedCompressionMethod" value="Metodo di Compressione non Supportato"/> + <node name="encryptedFile" value="File Protetto da DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Biblioteca in Rete"/> + </node> + <node name="library"> + <node name="caption" value="Biblioteca"/> + </node> +</resources> diff --git a/reader/data/resources/lt.xml b/reader/data/resources/lt.xml new file mode 100644 index 0000000..6c5fbda --- /dev/null +++ b/reader/data/resources/lt.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Lithuanian TDE-Ebook-Reader resources, by Stanislovas Zacharovas --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Rodyti knygas"/> + <node name="collapseTree" value="PaslÄ—pti knygas"/> + <node name="edit" value="Taisyti informacijÄ…"/> + <node name="unknownAuthor" value="Nežinomas autorius"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Rodyti knygas"/> + <node name="collapseTree" value="PaslÄ—pti knygas"/> + <node name="edit" value="Redaguoti žymÄ™"/> + <node name="clone" value="Klonuoti žymÄ™"/> + <node name="delete" value="IÅ¡trinti žymÄ™"/> + <node name="noTags" value="Knyga be žymių"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Rodyti knygas"/> + <node name="collapseTree" value="PaslÄ—pti knygas"/> + </node> + <node name="bookNode"> + <node name="read" value="Skaityti knygÄ…"/> + <node name="edit" value="Taisyti informacijÄ…"/> + <node name="delete" value="IÅ¡trinti knygÄ…"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="IÅ¡skleisti"/> + <node name="collapseTree" value="Suskleisti"/> + <node name="reload" value="Ä®krauti iÅ¡ naujo"/> + <node name="openInBrowser" value="Atidaryti narÅ¡yklÄ—je"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Atidaryti katalogÄ…"/> + <node name="collapseTree" value="Uždaryti katalogÄ…"/> + <node name="login" value="Prisijungti"/> + <node name="logout" value="Atsijungti (%s)"/> + <node name="reload" value="Ä®krauti iÅ¡ naujo"/> + <node name="dontShow" value="Nerodyti Å¡io katalogo"/> + <node name="topupAccount" value="Papildyti sÄ…skaitÄ… (dabar: %s)"/> + <node name="register" value="Registruotis"/> + <node name="passwordRecovery" value="Atstatyti slaptažodį"/> + </node> + <node name="searchResultNode"> + <node name="title" value="IeÅ¡koti tarp rezultatų"/> + <node name="expandTree" value="Rodyti rezultatus"/> + <node name="collapseTree" value="PaslÄ—pti rezultatus"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Rodyti knygas"/> + <node name="collapseTree" value="PaslÄ—pti knygas"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Rodyti knygas"/> + <node name="collapseTree" value="PaslÄ—pti knygas"/> + </node> + <node name="bookNode"> + <node name="read" value="Skaityti vietinÄ™ kopijÄ…"/> + <node name="delete" value="IÅ¡trinti vietinÄ™ kopijÄ…"/> + <node name="download" value="Atsisiųsti"/> + <node name="readDemo" value="Skaityti iÅ¡traukÄ…"/> + <node name="downloadDemo" value="Atsisiųsti iÅ¡traukÄ…"/> + <node name="demo" value="iÅ¡traukÄ…"/> + <node name="buy" value="Pirkti (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Apie knygÄ…..."/> + <node name="toc" value="Turinys"/> + <node name="showLibrary" value="Atidaryti bibliotekÄ…"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Biblioteka"> + <node name="showLibrary" value="Atidaryti"/> + <node name="previousBook" value="AnkstesnÄ— knyga"/> + <node name="showRecent" value="PaskutinÄ—s žiÅ«rÄ—tos"/> + <node name="addBook" value="PridÄ—ti knygÄ…..."/> + <node name="showHelp" value="Apie TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Eiti į pradžiÄ…"/> + <node name="gotoPageNumber" value="Atversti puslapį Nr..."/> + <node name="gotoSectionStart" value="Eiti į skirsnio pradžiÄ…"/> + <node name="gotoSectionEnd" value="Eiti į skirsnio galÄ…"/> + <node name="nextTOCSection" value="Eiti prie sekanÄio turinio elemento"/> + <node name="previousTOCSection" value="Eiti prie ankstesnio turinio elemento"/> + <node name="navigate" value="Navigacija"> + <node name="gotoHome" value="Eiti į pradžiÄ…"/> + <node name="gotoPageNumber" value="Atversti puslapį Nr..."/> + <node name="gotoSectionStart" value="Eiti į skirsnio pradžiÄ…"/> + <node name="gotoSectionEnd" value="Eiti į skirsnio galÄ…"/> + <node name="nextTOCSection" value="Eiti prie sekanÄio turinio elemento"/> + <node name="previousTOCSection" value="Eiti prie praeito turinio elemento"/> + <node name="undo" value="Atgal"/> + <node name="redo" value="Pirmyn"/> + </node> + <node name="selection" value="PažymÄ—jimas"> + <node name="copyToClipboard" value="Kopijuoti"/> + <node name="openInDictionary" value="Atidaryti žodynÄ™"/> + <node name="clearSelection" value="Nuimti pažymÄ—jimÄ…"/> + </node> + <node name="search" value="Surasti"> + <node name="search" value="Surasti tekstÄ…..."/> + <node name="findNext" value="Rasti sekantį"/> + <node name="findPrevious" value="Rasti buvusį"/> + </node> + <node name="view" value="Vaizdas"> + <node name="rotate" value="Pasukti ekranÄ…"/> + <node name="toggleFullscreen" value="Užpildyti ekranÄ…"/> + <node name="toggleIndicator" value="Ä®jungti indikatorių"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Uždaryti"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Skaityti knygÄ…"/> + <node name="tooltip" value="Skaityti pasirinktÄ… knygÄ…"/> + </node> + <node name="showLibrary"> + <node name="label" value="Biblioteka"/> + <node name="tooltip" value="Rodyti bibliotekos struktÅ«rÄ…"/> + <node name="popup" value="Rodyti neseniai skaitytas knygas"/> + </node> + <node name="showRecent"> + <node name="label" value="Neseniai skaitytos knygos"/> + <node name="tooltip" value="Rodyti neseniai skaitytų knygų sÄ…rašą"/> + </node> + <node name="byAuthor"> + <node name="label" value="Pagal autorių"/> + <node name="tooltip" value="Rūšiuoti knygas pagal autorius"/> + </node> + <node name="byTag"> + <node name="label" value="Pagal žymes"/> + <node name="tooltip" value="Rūšiuoti knygas pagal žymes"/> + </node> + <node name="addBook"> + <node name="label" value="PridÄ—ti failÄ…"/> + <node name="tooltip" value="PridÄ—ti failÄ… prie bibliotekos"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Internetas"/> + <node name="tooltip" value="IeÅ¡koti Interneto bibliotekose"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Tinklas"/> + <node name="tooltip" value="IeÅ¡koti tinkle"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Tiksli paieÅ¡ka tinkle"/> + <node name="tooltip" value="Patikslintoji paieÅ¡ka tinkle"/> + </node> + <node name="gotoHome"> + <node name="label" value="Ä® pradžiÄ…"/> + <node name="tooltip" value="Eiti į teksto pradžiÄ…"/> + </node> + <node name="undo"> + <node name="label" value="Atgal"/> + <node name="tooltip" value="Eiti į prieÅ¡ tai buvusį puslapį"/> + </node> + <node name="redo"> + <node name="label" value="Pirmyn"/> + <node name="tooltip" value="Eiti į sekantį puslapį"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Puslapis Nr. __"/> + <node name="tooltip" value="Atversti puslapį Nr.__"/> + </node> + <node name="toc"> + <node name="label" value="Turinys"/> + <node name="tooltip" value="Turinys"/> + </node> + <node name="search"> + <node name="label" value="PaieÅ¡ka"/> + <node name="tooltip" value="IeÅ¡koti tekste"/> + </node> + <node name="findNext"> + <node name="label" value="Sekantis"/> + <node name="tooltip" value="Rasti sekantį"/> + </node> + <node name="findPrevious"> + <node name="label" value="Ankstesnis"/> + <node name="tooltip" value="Rasti ankstesnį"/> + </node> + <node name="rotate"> + <node name="label" value="Pasukti"/> + <node name="tooltip" value="Pasukti tekstÄ…"/> + </node> + <node name="showHelp"> + <node name="label" value="Apie"/> + <node name="tooltip" value="Apie TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Filtras"/> + <node name="tooltip" value="Filtruoti pagal __"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Informacija"/> + <node name="tooltip" value="Informacija apie knygÄ…"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Vykdyti!"/> + <node name="thisOnly" value="Tik Å¡itÄ…"/> + <node name="withSubtags" value="Su subžymÄ—mis"/> + <node name="removeLink" value="IÅ¡trinti iÅ¡ bibliotekos"/> + <node name="removeFile" value="IÅ¡trinti iÅ¡ kompiuterio"/> + <node name="yesToAll" value="Taip &viskÄ…"/> + <node name="buy" value="&Pirkti"/> + <node name="buyAndDownload" value="Pirkti ir &nusikrauti"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Biblioteka"> + <node name="bookPath" value="Kelias prie knygos (knygų)"/> + <node name="lookInSubdirectories" value="IeÅ¡koti knygos pakatalogiuose"/> + <node name="collectBooksWithoutMetaInfo" value="Atrinkti knygas be MetaInfo"/> + <node name="downloadDirectory" value="Atsisiųstų knygų saugojimo vieta"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Interneto bibliotekos"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Naudoti Proxy"/> + <node name="proxyHost" value="Proxy Host'as"/> + <node name="proxyPort" value="Proxy Port'as"/> + <node name="timeout" value="Veiksmo vykdymo laukimas, sekundemis"/> + </node> + <node name="Web" value="Internetas"> + <node name="enableIntegration" value="Leisti prisijungti prie Interneto"/> + <node name="defaultText" value="Atidaryti iÅ¡orinÄ™ nuorodÄ… narÅ¡yklÄ—je"/> + <node name="choice" value="Naudoti narÅ¡yklÄ™"/> + <node name="command" value="Ä®vykdyti komandÄ…"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Kalba"> + <node name="autoDetect" value="Automatinis kalbos ir koduotÄ—s atpažinimas"/> + <node name="defaultLanguage" value="PagrindinÄ— kalba"/> + <node name="defaultEncodingSet" value="PagrindinÄ—s koduotÄ—s aibÄ—"/> + <node name="defaultEncoding" value="PagrindinÄ— koduotÄ—"/> + <node name="useWindows1252Hack" value="Naudoti windows-1252 vietoje iso-8859-1"/> + </node> + <node name="Config" value="KonfigÅ«racija"> + <node name="autoSave" value="AutomatiÅ¡kai saugoti bÅ«senÄ…"/> + <node name="timeout" value="Laiko tarpas tarp saugojimų, sekundÄ—s"/> + </node> + <node name="Dictionary" value="Žodynas"> + <node name="enableIntegration" value="Leisti sujungimÄ…"/> + <node name="defaultText" value="Leisti sujungimÄ… su žodynu"/> + <node name="choice" value="Sujungti su"/> + <node name="singleClickOpen" value="Atidaryti vienu pelÄ—s paspaudimu"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Veikmas atleidžiant paspaustÄ… mygtukÄ…"/> + <node name="minStylusPressure" value="Silpniausias bakstuko paspaudimas"/> + <node name="maxStylusPressure" value="Stipriausias bakstuko paspaudimas"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Puslapio keitimas"> + <node name="keyScrollDelay" value="Puslapio keitimo užlaikymas, msec."/> + <node name="keyLinesToScroll" value="EiluÄių skaiÄius keiÄiamas vienu paspaudimu"/> + <node name="keyLinesToKeep" value="EiluÄių skaiÄius paliekamas pakeiÄiant puslapį"/> + <node name="enableTapScrolling" value="Leisti keisti puslapį bakstelnant ekranÄ…"/> + <node name="fingerOnly" value="Keisti puslapį tik prisilietus pirÅ¡tu"/> + </node> + <node name="Selection" value="Teksto žymÄ—jimas"> + <node name="enableSelection" value="Leisti teksto žymÄ—jimÄ…"/> + </node> + <node name="Indicator" value="Indikatorius"> + <node name="type" value="Rodyti kaip"> + <node name="osScrollbar" value="OperacinÄ—s sistemos slinkties rodyklÄ—"/> + <node name="fbIndicator" value="Indikatorius apaÄioje"/> + <node name="none" value="Nerodyti"/> + </node> + <node name="height" value="Indikatoriaus aukÅ¡tis"/> + <node name="offset" value="Atstumas nuo teksto"/> + <node name="pageNumber" value="Rodyti puslapių numerius"/> + <node name="time" value="Rodyti laikÄ…"/> + <node name="fontSize" value="Å rifto dydis"/> + <node name="tocMarks" value="Rodyti turinio žymes"/> + <node name="navigation" value="Leisti NavigacijÄ…"/> + </node> + <node name="Rotation" value="Pasukimas"> + <node name="direction" value="Sukti puslapį"> + <node name="disabled" value="Nesukti"/> + <node name="clockwise" value="90 laipsnių pagal laikrodžio rodyklÄ™"/> + <node name="counterclockwise" value="90 laipsnių prieÅ¡ laikrodžio rodyklÄ™"/> + <node name="180" value="180 laipsnių"/> + <node name="cycle" value="Keturiomis kryptimis"/> + </node> + </node> + <node name="Keys" value="Mygtukai"> + <node name="grabSystemKeys" value="Ä®siminti mygtukÄ…"/> + <node name="separate" value="Mygtukų priskyrimas priklauso nuo pasukimo"/> + <node name="orientation" value="Pasukimas"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Nieko"/> + <node name="showLibrary" value="Rodyti bibliotekÄ…"/> + <node name="showNetLibrary" value="Rodyti Interneto bibliotekÄ…"/> + <node name="showRecent" value="Rodyti neseniai žiÅ«rÄ—tas knygas"/> + <node name="previousBook" value="Atidaryti ankstesnÄ™ knygÄ…"/> + <node name="toc" value="Rodyti turinį"/> + <node name="gotoHome" value="Eiti į pradžiÄ…"/> + <node name="gotoSectionStart" value="Eiti į skirsnio pradžiÄ…"/> + <node name="gotoSectionEnd" value="Eiti į skirsnio pabaigÄ…"/> + <node name="nextTOCSection" value="Eiti prie sekanÄio turinio elemento"/> + <node name="previousTOCSection" value="Eiti prie praeito turinio elemento"/> + <node name="pageForward" value="Atversti sekantį puslapį"/> + <node name="pageBackward" value="Atversti ankstesnį puslapį"/> + <node name="lineForward" value="Atversti sekanÄiÄ… eilutÄ™"/> + <node name="lineBackward" value="Atversti ankstesnÄ™ eilutÄ™"/> + <node name="undo" value="Atstatyti"/> + <node name="redo" value="Pakartoti veiksmÄ…"/> + <node name="copyToClipboard" value="Kopijuoti"/> + <node name="openInDictionary" value="Atidaryti žodyne"/> + <node name="clearSelection" value="Nuimti pažymÄ—jimÄ…"/> + <node name="search" value="IeÅ¡koti"/> + <node name="findPrevious" value="Rasti ankstesnį"/> + <node name="findNext" value="Rasti sekantį"/> + <node name="increaseFont" value="Padidinti Å¡rifto dydį"/> + <node name="decreaseFont" value="Sumažinti Å¡rifto dydį"/> + <node name="toggleIndicator" value="Ä®jungti puslapių indikatorių"/> + <node name="toggleFullscreen" value="Ä®jungti ekrano užpildymÄ…"/> + <node name="rotate" value="Pasukti ekranÄ…"/> + <node name="addBook" value="PridÄ—ti knygÄ…"/> + <node name="cancel" value="AtÅ¡aukti"/> + <node name="quit" value="IÅ¡eiti"/> + <node name="bookInfo" value="Parodyti knygos informacijÄ…"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="IÅ¡eiti iÅ¡ programos pasirinkus AtÅ¡aukti"/> + <node name="keyDelay" value="Užlaikymas tarp mygtuko paspaudimo ir vykdymo"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Visada naudoti mano Å¡riftÄ…"/> + </node> + <node name="Margins" value="ParaÅ¡tÄ—s"> + <node name="left" value="Kairioji paraÅ¡tÄ—"/> + <node name="right" value="DeÅ¡inioji paraÅ¡tÄ—"/> + <node name="top" value="VirÅ¡utinÄ— paraÅ¡tÄ—"/> + <node name="bottom" value="ApatinÄ— paraÅ¡tÄ—"/> + </node> + <node name="Format" value="Formatas"> + <node name="optionsFor" value="Nustatymai"/> + <node name="lineSpacing" value="Atstumas tarp eiluÄių"> + <node name="unchanged" value="<nekeistas>"/> + </node> + <node name="firstLineIndent" value="Pirmos eilutÄ—s atstumas nuo kraÅ¡to"/> + <node name="alignment" value="Lygiavimas"> + <node name="left" value="KairÄ—n"/> + <node name="right" value="DeÅ¡inÄ—n"/> + <node name="center" value="Per vidurį"/> + <node name="justify" value="IÅ¡lyginti"/> + <node name="unchanged" value="<nekeistas>"/> + </node> + <node name="spaceBefore" value="Atstumas prieÅ¡"/> + <node name="spaceAfter" value="Atstumas po"/> + <node name="startIndent" value="EilutÄ—s pradžia"/> + <node name="endIndent" value="EilutÄ—s pabaiga"/> + </node> + <node name="Styles" value="Stiliai"> + <node name="optionsFor" value="Nustatymai"/> + <node name="fontFamily" value="Å riftų Å¡eima"> + <node name="unchanged" value="<nekeistas>"/> + </node> + <node name="fontSize" value="Dydis"/> + <node name="fontSizeDifference" value="Dydžių skirtumai"/> + <node name="bold" value="Pastorintas"/> + <node name="italic" value="Kursyvas"/> + <node name="allowHyphenations" value="Skiemenų perkÄ—limas"/> + <node name="autoHyphenations" value="Automatinis skiemenų perkÄ—limas"/> + </node> + <node name="Colors" value="Spalvos"> + <node name="colorFor" value="Spalva"> + <node name="background" value="Fonas"/> + <node name="selectionBackground" value="Teksto žymÄ—jimo spalva"/> + <node name="text" value="Tekstas"/> + <node name="internalLink" value="VidinÄ— nuoroda"/> + <node name="externalLink" value="Nuoroda į įšorinį objektÄ…"/> + <node name="bookLink" value="Nuoroda į kitÄ… knygÄ…"/> + <node name="highlighted" value="IÅ¡skirtas tekstas"/> + <node name="treeLines" value="HierarchinÄ—s struktÅ«ros linijos"/> + <node name="indicator" value="Indikatorius"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informacija apie knygÄ…"/> + <node name="tab"> + <node name="Common" value="Bendrai"> + <node name="file" value="Failas"/> + <node name="title" value="Pavadinimas"/> + <node name="language" value="Kalba"/> + <node name="encodingSet" value="KoduotÄ—s aibÄ—"/> + <node name="encoding" value="Kodavimas"/> + </node> + <node name="Authors" value="Autoriai"> + <node name="authorDisplayName" value="Autorius"/> + </node> + <node name="Series" value="Serijos"> + <node name="seriesTitle" value="Serijos pavadinimas"/> + <node name="bookIndex" value="Knygų sÄ…raÅ¡as"/> + </node> + <node name="Tags" value="ŽymÄ—s"> + <node name="tags" value="ŽymÄ—s pavadinimas"/> + </node> + <node name="Text" value="Tekstas"> + <node name="breakType" value="Skelti pastraipÄ… prie"/> + <node name="ignoreIndent" value="Ignoruoti atstumÄ… mažesnį nei"/> + <node name="buildTOC" value="Sukurti turinį"/> + <node name="emptyLines" value="TuÅ¡Äios eilutÄ—s prieÅ¡ naujÄ… pastraipÄ…"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Skelti pastraipÄ… prie"/> + <node name="ignoreIndent" value="Ignoruoti atstumÄ… mažesnį nei"/> + <node name="buildTOC" value="Sukurti turinį"/> + <node name="emptyLines" value="TuÅ¡Äios eilutÄ—s prieÅ¡ naujÄ… skyrių"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informacija apie autorių"/> + <node name="name" value="Autoriaus vardas"/> + <node name="sortKey" value="Rūšiuoti autorius"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - PridÄ—ti knygÄ… į bibliotekÄ…"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="PaieÅ¡ka tekste"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignoruoti"/> + <node name="wholeText" value="&Visame tekste"/> + <node name="backward" value="&Atgal"/> + <node name="currentSection" value="&Tik Å¡iame skirsnyjÄ™"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="PaieÅ¡ka tinkle"/> + <node name="titleAndSeries" value="Pavadinimas/Serija"/> + <node name="author" value="Autorius"/> + <node name="category" value="Kategorija"/> + <node name="description" value="ApraÅ¡ymas"/> + <node name="annotation" value="IeÅ¡koti rezultatus apie: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Atversti puslapį"/> + <node name="pageNumber" value="Atversti puslapį numeris:"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Redaguoti žymes"/> + <node name="name" value="ŽymÄ—s pavadinimas"/> + <node name="includeSubtags" value="įtraukti požymes"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Klonuoti žymÄ™"/> + <node name="name" value="ŽymÄ—s pavadinimas"/> + <node name="includeSubtags" value="Ä®traukti požymes"/> + </node> + <node name="removeBookBox"> + <node name="title" value="IÅ¡trinti knygÄ…"/> + <node name="message" value="IÅ¡trinti knygÄ… “%s†iÅ¡ bibliotekos?"/> + <node name="deleteFile" value="IÅ¡ tiesų norite iÅ¡trinti “%s†iÅ¡ kompiuterio?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Nuimti žymÄ™"/> + <node name="message" value="Nuimti žymÄ™ “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Klaida"/> + <node name="message" value="Nepavyksta atidaryti %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Klaida"/> + <node name="message" value="Nepavyksta iÅ¡trinti failo %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Klaida"/> + <node name="message" value="Pagalbos failas nerastas"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Bibliotekų sÄ…raÅ¡as tuÅ¡Äias"/> + <node name="authenticationFailed" value="TapatybÄ—s nustatymas nepavyko"/> + <node name="internalError" value="VidinÄ— serverio klaida"/> + <node name="purchaseNotEnoughMoney" value="Nepakanka vidinÄ—s atminties"/> + <node name="purchaseMissingBook" value="NÄ—ra knygos"/> + <node name="purchaseAlreadyPurchased" value="Jau nupirkote"/> + <node name="bookNotPurchased" value="Knyga nenupirkta"/> + <node name="downloadLimitExceeded" value="VirÅ¡ijote leidžiamų atsisiuntimų kiekį"/> + <node name="unsupportedOperation" value="Nepalaikomas veiksmas"/> + <node name="loginAlreadyTaken" value="Vartotojo vardas jau naudojamas"/> + <node name="loginNotSpecified" value="PraÅ¡ome įvesti vartotojo vardÄ…"/> + <node name="passwordNotSpecified" value="PraÅ¡ome įvesti bent jau kelių ženklų slapatažodį "/> + <node name="emailNotSpecified" value="PraÅ¡ome įvesti el. paÅ¡to adresÄ…"/> + <node name="invalidEMail" value="Neteisingas el. paÅ¡to adresas"/> + <node name="tooManyRegistrations" value="Per daug registruotasi iÅ¡ jusų IP; bandykite vÄ—l po kelių minuÄių"/> + <node name="noUserEmail" value="Neturime registruoto vartotojo su nurodytu el. paÅ¡to adresu"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Siuntimosi klaida"/> + <node name="message" value="Å iuo metu nepavyksta atsisiųsti Å¡ios knygos"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Palaukite, knyga įkraunoma..."/> + <node name="loadingBookList" value="Palaukite, biblioteka įkraunoma..."/> + <node name="migrate" value="Versijos atnaujinimas. Palaukite..."/> + <node name="downloadBookList" value="AtsisiunÄiam knygų sÄ…rašą. Palaukite..."/> + <node name="downloadBook" value="AtsisiunÄiam knygÄ…. Palaukite..."/> + <node name="downloadImages" value="AtsisiunÄiam vaizdus. Palaukite..."/> + <node name="authentication" value="TapatybÄ—s nustatymas. Palaukite..."/> + <node name="purchaseBook" value="Perkame knygÄ…. Palaukite..."/> + <node name="initializeAuthenticationManager" value="AtsisiunÄiam paskyros (account) informacijÄ…. Palaukite..."/> + <node name="loadSubCatalog" value="Ä®krauname katalogÄ…. Palaukite..."/> + <node name="registerUser" value="Registruojame naujo vartotojo įrašą. Palaukite..."/> + <node name="passwordRecovery" value="Atstatome slaptažodį. Palaukite..."/> + <node name="authenticationCheck" value="Paskyros patvirtinimas. Palaukite..."/> + <node name="signOut" value="Atjungiame. Palaukite..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Pirkti knygÄ…"/> + <node name="message" value="Pirkti?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="TapatybÄ—s nustatymas"/> + <node name="login" value="Vardas"/> + <node name="password" value="Slaptažodis"/> + <node name="skipIP" value="Nesusieti su IP adresu"/> + <node name="loginIsEmpty" value="Vardo laukas negali bÅ«ti tuÅ¡Äias"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informacija"/> + <node name="message" value="Katalogas tuÅ¡Äias"/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Nerodyti katalogo"/> + <node name="message" value="Neberodyti “%s†katalogo? Katalogo rodymÄ… galima bus įjungti Nustatymuose, kortelÄ—je "Interneto bibliotekos""/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="IÅ¡trinti knygÄ…"/> + <node name="message" value="Trinti “%s†knygÄ… iÅ¡ kompiuterio?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Registruoti vartotojÄ…"/> + <node name="login" value="Vartotojo vardas"/> + <node name="password" value="Slaptažodis"/> + <node name="confirmPassword" value="Pakartokite slaptažodį"/> + <node name="email" value="El. paÅ¡tas"/> + <node name="differentPasswords" value="Slaptažodis turi bÅ«ti tas pats abiejuose laukeliuose"/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Slaptažodžio atstatymas"/> + <node name="email" value="El. paÅ¡tas"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Slaptažodžio atstatymas"/> + <node name="message" value="El. laiÅ¡kas su tolesniais nurodymais iÅ¡siųstas į %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Ä®krovimo klaida"/> + <node name="message" value="Nepavyksta atidaryti failo %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Pagrindiniai"/> + <node name="Regular Paragraph" value="Paprasta pastraipa"/> + <node name="Title" value="AntraÅ¡tÄ—"/> + <node name="Section Title" value="Skirsnio antraÅ¡tÄ—"/> + <node name="Poem Title" value="EilÄ—raÅ¡Äio antraÅ¡tÄ—"/> + <node name="Subtitle" value="PaantraÅ¡tÄ—"/> + <node name="Annotation" value="Anotacija"/> + <node name="Epigraph" value="Epigrafas"/> + <node name="Stanza" value="Posmas"/> + <node name="Verse" value="EilÄ—raÅ¡tis"/> + <node name="Preformatted text" value="Preformatuotas tekstas"/> + <node name="Image" value="Vaizdas"/> + <node name="Cite" value="Citata"/> + <node name="Author" value="Autorius"/> + <node name="Date" value="Data"/> + <node name="Internal Hyperlink" value="VidinÄ— nuoroda"/> + <node name="Footnote" value="Pastaba"/> + <node name="Emphasis" value="Pabrėžimas"/> + <node name="Strong" value="IÅ¡ryÅ¡kinti"/> + <node name="Subscript" value="Apatinis indeksas"/> + <node name="Superscript" value="VirÅ¡utinis indeksas"/> + <node name="Code" value="Kodas"/> + <node name="StrikeThrough" value="Perbraukti"/> + <node name="Contents Table" value="Turinys"/> + <node name="Library Entry" value="Bibliotekos įraÅ¡as"/> + <node name="Recent Book List" value="Neseniai skaitytų knygų saraÅ¡as"/> + <node name="Italic" value="Kursyvas"/> + <node name="Bold" value="Pastorintas"/> + <node name="Definition" value="Apibrėžimas"/> + <node name="Definition Description" value="Apibrėžimo apraÅ¡ymas"/> + <node name="Header 1" value="AntraÅ¡tÄ— 1"/> + <node name="Header 2" value="AntraÅ¡tÄ— 2"/> + <node name="Header 3" value="AntraÅ¡tÄ— 3"/> + <node name="Header 4" value="AntraÅ¡tÄ— 4"/> + <node name="Header 5" value="AntraÅ¡tÄ— 5"/> + <node name="Header 6" value="AntraÅ¡tÄ— 6"/> + <node name="External Hyperlink" value="Nuoroda į iÅ¡orinį objektÄ…"/> + <node name="Link to Another Book" value="Nuoroda į kitÄ… knygÄ…"/> + </node> + <node name="external"> + <node name="browser" value="NarÅ¡yklÄ—"/> + <node name="defaultBrowser" value="NarÅ¡yklÄ—"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Nežinoma klaida"/> + <node name="unsupportedCompressionMethod" value="Nepalaikomas suspaudimo bÅ«das"/> + <node name="encryptedFile" value="Skaitmeninių teisių valdymo technologijomis apsaugotas failas"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="InternetinÄ— biblioteka"/> + </node> + <node name="library"> + <node name="caption" value="Biblioteka"/> + </node> +</resources> diff --git a/reader/data/resources/nl.xml b/reader/data/resources/nl.xml new file mode 100644 index 0000000..65f7c53 --- /dev/null +++ b/reader/data/resources/nl.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Dutch TDE-Ebook-Reader resources, by Bosel --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Boeken tonen"/> + <node name="collapseTree" value="Boeken verbergen"/> + <node name="edit" value="Informatie wijzigen"/> + <node name="unknownAuthor" value="Onbekende auteur"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Boeken tonen"/> + <node name="collapseTree" value="Boeken verbergen"/> + <node name="edit" value="Tag wijzigen"/> + <node name="clone" value="Tag kopiëren"/> + <node name="delete" value="Tag verwijderen"/> + <node name="noTags" value="Boeken zonder tags"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Boeken tonen"/> + <node name="collapseTree" value="Boeken verbergen"/> + </node> + <node name="bookNode"> + <node name="read" value="Boek lezen"/> + <node name="edit" value="Informatie wijzigen"/> + <node name="delete" value="Boek verwijderen"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Auteurs"> + <node name="summary" value="Boeken gesorteerd op auteur"/> + </node> + <node name="byTitle" value="Titel"> + <node name="summary" value="Boeken gesorteerd op titel"/> + </node> + <node name="byDate" value="Datum"> + <node name="summary" value="Boeken gesorteerd op aankoopdatum"/> + </node> + <node name="bySeries" value="Series"> + <node name="summary" value="Boeken gesorteerd op series"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Vergroten"/> + <node name="collapseTree" value="Verkleinen"/> + <node name="reload" value="Opnieuw laden"/> + <node name="openInBrowser" value="Openen in browser"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Catalogus openen"/> + <node name="collapseTree" value="Catalogus sluiten"/> + <node name="login" value="Aanmelden"/> + <node name="logout" value="Afmelden (%s)"/> + <node name="reload" value="Opnieuw laden"/> + <node name="dontShow" value="Deze catalogus niet tonen"/> + <node name="topupAccount" value="Account opladen (nu: %s)"/> + <node name="register" value="Registreren"/> + <node name="passwordRecovery" value="Wachtwoord herstellen"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Zoekresultaten"/> + <node name="expandTree" value="Resultaten tonen"/> + <node name="collapseTree" value="Resultaten verbergen"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Boeken tonen"/> + <node name="collapseTree" value="Boeken verbergen"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Boeken tonen"/> + <node name="collapseTree" value="Boeken verbergen"/> + </node> + <node name="bookNode"> + <node name="read" value="Locale kopie lezen"/> + <node name="delete" value="Locale kopie verwijderen"/> + <node name="download" value="Download"/> + <node name="readDemo" value="Lees demo"/> + <node name="downloadDemo" value="Download demo"/> + <node name="demo" value="demo"/> + <node name="buy" value="Koop (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Boek Info..."/> + <node name="toc" value="Inhoudsopgave"/> + <node name="showLibrary" value="Open bibliotheek"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Bibliotheek"> + <node name="showLibrary" value="Open"/> + <node name="previousBook" value="Vorig boek"/> + <node name="showRecent" value="Recent"/> + <node name="addBook" value="Boek toevoegen..."/> + <node name="showHelp" value="Over TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Ga naar het begin van het document"/> + <node name="gotoPageNumber" value="Ga naar pagina..."/> + <node name="gotoSectionStart" value="Ga naar het begin van deze sectie"/> + <node name="gotoSectionEnd" value="Ga naar het einde van deze sectie"/> + <node name="nextTOCSection" value="Ga naar het volgende hoofdstuk"/> + <node name="previousTOCSection" value="Ga naar het vorige hoofdstuk"/> + <node name="navigate" value="Navigatie"> + <node name="gotoHome" value="Ga naar het begin van het document"/> + <node name="gotoPageNumber" value="Ga naar pagina..."/> + <node name="gotoSectionStart" value="Ga naar het begin van deze sectie"/> + <node name="gotoSectionEnd" value="Ga naar het einde van deze sectie"/> + <node name="nextTOCSection" value="Ga naar het volgende hoofdstuk"/> + <node name="previousTOCSection" value="Ga naar het vorige hoofdstuk"/> + <node name="undo" value="Terug"/> + <node name="redo" value="Vooruit"/> + </node> + <node name="selection" value="Selection"> + <node name="copyToClipboard" value="Kopieer naar het Clipboard"/> + <node name="openInDictionary" value="In het woordenboek openen"/> + <node name="clearSelection" value="Wissen"/> + </node> + <node name="search" value="Zoeken"> + <node name="search" value="Zoek Tekst..."/> + <node name="findNext" value="Zoek Volgende"/> + <node name="findPrevious" value="Zoek Vorige"/> + </node> + <node name="view" value="Beeld"> + <node name="rotate" value="Scherm draaien"/> + <node name="toggleFullscreen" value="Beeldvullend"/> + <node name="toggleIndicator" value="Indicator Aan/Uit"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Sluiten"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Boek lezen"/> + <node name="tooltip" value="Leesmodus tonen"/> + </node> + <node name="showLibrary"> + <node name="label" value="Bibliotheek"/> + <node name="tooltip" value="Bibliotheek tonen"/> + <node name="popup" value="Recente boekenlijst tonen"/> + </node> + <node name="showRecent"> + <node name="label" value="Recente Boeken"/> + <node name="tooltip" value="Recente boeken tonen"/> + </node> + <node name="byAuthor"> + <node name="label" value="Per auteur"/> + <node name="tooltip" value="Boeken per auteur ordenen"/> + </node> + <node name="byTag"> + <node name="label" value="Per Tag"/> + <node name="tooltip" value="Boeken per tag ordenen"/> + </node> + <node name="addBook"> + <node name="label" value="Bestand toevoegen"/> + <node name="tooltip" value="Bestand aan de bibliotheek toevoegen"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Netwerk"/> + <node name="tooltip" value="Zoeken in netwerk bibliotheken"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Zoeken"/> + <node name="tooltip" value="Netwerk doorzoeken"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Uitgebreid zoeken"/> + <node name="tooltip" value="Netwerk uitgebreid doorzoeken"/> + </node> + <node name="gotoHome"> + <node name="label" value="Naar begin"/> + <node name="tooltip" value="Ga naar het begin van de tekst"/> + </node> + <node name="undo"> + <node name="label" value="Terug"/> + <node name="tooltip" value="Ga terug"/> + </node> + <node name="redo"> + <node name="label" value="Vooruit"/> + <node name="tooltip" value="Ga vooruit"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Ga naar pagina"/> + <node name="tooltip" value="Ga naar pagina"/> + </node> + <node name="toc"> + <node name="label" value="Index"/> + <node name="tooltip" value="Inhoudsopgave"/> + </node> + <node name="search"> + <node name="label" value="Zoeken"/> + <node name="tooltip" value="Doorzoek tekst"/> + </node> + <node name="findNext"> + <node name="label" value="Volgende"/> + <node name="tooltip" value="Zoek volgende"/> + </node> + <node name="findPrevious"> + <node name="label" value="Vorige"/> + <node name="tooltip" value="Zoek vorige"/> + </node> + <node name="rotate"> + <node name="label" value="Draaien"/> + <node name="tooltip" value="Text draaien"/> + </node> + <node name="showHelp"> + <node name="label" value="Over"/> + <node name="tooltip" value="Over TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Boek Info"/> + <node name="tooltip" value="Toon boek informatie"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Go!"/> + <node name="thisOnly" value="Alleen deze"/> + <node name="withSubtags" value="Met subtags"/> + <node name="removeLink" value="Verwijder van bibliotheek"/> + <node name="removeFile" value="Volledig verwijderen"/> + <node name="yesToAll" value="Ja op &alles"/> + <node name="buy" value="&Koop"/> + <node name="buyAndDownload" value="Koop en &download"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Bibliotheek"> + <node name="bookPath" value="Boek Locaties"/> + <node name="lookInSubdirectories" value="Zoek naar boeken in Submappen"/> + <node name="collectBooksWithoutMetaInfo" value="Voeg boeken toe zonder MetaInfo"/> + <node name="downloadDirectory" value="Locatie voor Downloads"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="online bibliotheken"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Gebruik Proxy"/> + <node name="proxyHost" value="Proxy Host"/> + <node name="proxyPort" value="Proxy Poort"/> + <node name="timeout" value="Netwerk Timeout, in seconden"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Externe links in %s openen"/> + <node name="defaultText" value="Externe links in Browser openen"/> + <node name="choice" value="Gebruik Browser"/> + <node name="command" value="Commando uitvoeren"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Taal"> + <node name="autoDetect" value="Taal en Codering automatisch detecteren"/> + <node name="defaultLanguage" value="Standaard Taal"/> + <node name="defaultEncodingSet" value="Standaard Codering Type"/> + <node name="defaultEncoding" value="Standaard Codering"/> + <node name="useWindows1252Hack" value="Gebruik windows-1252 in plaats van iso-8859-1"/> + </node> + <node name="Config" value="Configuratie"> + <node name="autoSave" value="Automatisch staat opslaan"/> + <node name="timeout" value="Tijd tussen automatisch oplaan, in seconden"/> + </node> + <node name="Dictionary" value="Dictionary"> + <node name="enableIntegration" value="Integratie met %s toestaan"/> + <node name="defaultText" value="Integratie met woordenboek toestaan"/> + <node name="choice" value="Integreren met"/> + <node name="singleClickOpen" value="Openen met enkele klik"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Activeren bij loslaten toets, niet bij toetsaanslag"/> + <node name="minStylusPressure" value="Minimale Stylus Druk"/> + <node name="maxStylusPressure" value="Maximale Stylus Druk"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Scrolling"> + <node name="keyScrollDelay" value="Vertraging tussen Toets Scrollings, msecs"/> + <node name="keyLinesToScroll" value="Aantal regels Scrollen bij Regel Scrolling"/> + <node name="keyLinesToKeep" value="Te bewaren regels bij Pagina Scrolling"/> + <node name="enableTapScrolling" value="Tap Scrolling gebruiken"/> + <node name="fingerOnly" value="Alleen door Vinger Tap scrollen"/> + </node> + <node name="Selection" value="Selectie"> + <node name="enableSelection" value="Tekst selectie gebruiken"/> + </node> + <node name="Indicator" value="Indicator"> + <node name="type" value="Toon als"> + <node name="osScrollbar" value="Standaard Scrollbar"/> + <node name="fbIndicator" value="Uitgebreide Indicator"/> + <node name="none" value="Niet Tonen"/> + </node> + <node name="height" value="Indicator Hoogte"/> + <node name="offset" value="Afstand van Tekst"/> + <node name="pageNumber" value="Toon Positie als cijfer"/> + <node name="time" value="Toon Tijd"/> + <node name="fontSize" value="Font grootte"/> + <node name="tocMarks" value="Toon Hoofdstukken"/> + <node name="navigation" value="Gebruiken voor Navigatie"/> + </node> + <node name="Rotation" value="Oriëntatie"> + <node name="direction" value="Soort Rotatie"> + <node name="disabled" value="Geen"/> + <node name="clockwise" value="90 Graden Rechtsom"/> + <node name="counterclockwise" value="90 Graden Linksom"/> + <node name="180" value="180 Graden"/> + <node name="cycle" value="Rondgang door de vier standen"/> + </node> + </node> + <node name="Keys" value="Toetsen"> + <node name="grabSystemKeys" value="Systeem toetsen detecteren"/> + <node name="separate" value="Toetsbindingen afhankelijk van Oriëntatie"/> + <node name="orientation" value="Oriëntatie"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Geen"/> + <node name="showLibrary" value="Toon bibliotheek"/> + <node name="showNetLibrary" value="Toon netwerk bibliotheek"/> + <node name="showRecent" value="Toon recente boeken"/> + <node name="previousBook" value="Toon vorig boek"/> + <node name="toc" value="Toon inhoudsopgave"/> + <node name="gotoHome" value="Ga naar begin"/> + <node name="gotoSectionStart" value="Ga naar het begin van deze sectie"/> + <node name="gotoSectionEnd" value="Ga naar het einde van deze sectie"/> + <node name="nextTOCSection" value="Ga naar het volgende hoofdstuk"/> + <node name="previousTOCSection" value="Ga naar het vorige hoofdstuk"/> + <node name="pageForward" value="Scroll pagina vooruit"/> + <node name="pageBackward" value="Scroll pagina achteruit"/> + <node name="lineForward" value="Scroll regel vooruit"/> + <node name="lineBackward" value="Scroll regel achteruit"/> + <node name="undo" value="Terug"/> + <node name="redo" value="Vooruit"/> + <node name="copyToClipboard" value="Kopieer naar het Clipboard"/> + <node name="openInDictionary" value="In het woordenboek openen"/> + <node name="clearSelection" value="Wissen"/> + <node name="search" value="Zoeken"/> + <node name="findPrevious" value="Zoek Vorige"/> + <node name="findNext" value="Zoek volgende"/> + <node name="increaseFont" value="Vergroot font"/> + <node name="decreaseFont" value="Verklein font"/> + <node name="toggleIndicator" value="Indicator Aan/Uit"/> + <node name="toggleFullscreen" value="Volledig scherm"/> + <node name="rotate" value="Scherm draaien"/> + <node name="addBook" value="Boek toevoegen"/> + <node name="cancel" value="Annuleren"/> + <node name="quit" value="Afsluiten"/> + <node name="bookInfo" value="Toon Boek Info scherm"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Programma afsluiten bij annuleren"/> + <node name="keyDelay" value="Vertraging tussen geaccepteerde toetsaanslagen"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Altijd mijn eigen Fonts gebruiken"/> + </node> + <node name="Margins" value="Marges"> + <node name="left" value="Linker Marge"/> + <node name="right" value="Rechter Marge"/> + <node name="top" value="Boven Marge"/> + <node name="bottom" value="Onder Marge"/> + </node> + <node name="Format" value="Opmaak"> + <node name="optionsFor" value="Opties voor"/> + <node name="lineSpacing" value="Regelafstand"> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="firstLineIndent" value="Inspringen eerste regel"/> + <node name="alignment" value="Uitlijning"> + <node name="left" value="Links"/> + <node name="right" value="Rechts"/> + <node name="center" value="Centreren"/> + <node name="justify" value="Uitvullen"/> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="spaceBefore" value="Ruimte Voor"/> + <node name="spaceAfter" value="Ruimte Na"/> + <node name="startIndent" value="Inspringen aan begin regel"/> + <node name="endIndent" value="Inspringen aan einde regel"/> + </node> + <node name="Styles" value="Lettertype"> + <node name="optionsFor" value="Opties voor"/> + <node name="fontFamily" value="Font Familie"> + <node name="unchanged" value="<unchanged>"/> + </node> + <node name="fontSize" value="Afmeting"/> + <node name="fontSizeDifference" value="Verschil Font Afmetingen"/> + <node name="bold" value="Vet"/> + <node name="italic" value="Cursief"/> + <node name="allowHyphenations" value="Woordafbreking Toestaan"/> + <node name="autoHyphenations" value="Automatische Woordafbreking"/> + </node> + <node name="Colors" value="Kleuren"> + <node name="colorFor" value="Kleur voor"> + <node name="background" value="Achtergrond"/> + <node name="selectionBackground" value="Actergrond Selecties"/> + <node name="text" value="Reguliere Tekst"/> + <node name="internalLink" value="Interne Hyperlink Tekst"/> + <node name="externalLink" value="Externe Hyperlink Tekst"/> + <node name="bookLink" value="Link naar een Ander Boek"/> + <node name="highlighted" value="Gemarkeerde Tekst"/> + <node name="treeLines" value="Tree Lines"/> + <node name="indicator" value="Positie Indicator"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Boek Info"/> + <node name="tab"> + <node name="Common" value="Standaard"> + <node name="file" value="Bestand"/> + <node name="title" value="Titel"/> + <node name="language" value="Taal"/> + <node name="encodingSet" value="Type Codering"/> + <node name="encoding" value="Codering"/> + </node> + <node name="Authors" value="Auteurs"> + <node name="authorDisplayName" value="Naam Auteur"/> + </node> + <node name="Series" value="Series"> + <node name="seriesTitle" value="Serie Titel"/> + <node name="bookIndex" value="Boek Index"/> + </node> + <node name="Tags" value="Tags"> + <node name="tags" value="Tag Naam"/> + </node> + <node name="Text" value="Tekst"> + <node name="breakType" value="Paragraaf afbreken bij"/> + <node name="ignoreIndent" value="Negeer inspringingen minder dan"/> + <node name="buildTOC" value="Inhoudsopgave Samenstellen"/> + <node name="emptyLines" value="Blanke regel voor een Nieuwe Paragraaf"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Paragraaf afbreken bij"/> + <node name="ignoreIndent" value="Negeer inspringingen minder dan"/> + <node name="buildTOC" value="Inhoudsopgave Samenstellen"/> + <node name="emptyLines" value="Blanke regel voor een Nieuwe Paragraaf"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Auteur Info"/> + <node name="name" value="Naam Auteur"/> + <node name="sortKey" value="Sorteer Sleutel Auteur"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Boek aan de Bibliotheek Toevoegen"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Tekst Zoeken"/> + <node name="text" value=""/> + <node name="ignoreCase" value="Hoofdletters negeren"/> + <node name="wholeText" value="In volledige tekst"/> + <node name="backward" value="Terug"/> + <node name="currentSection" value="Alleen in deze paragraaf"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Netwerk Doorzoeken"/> + <node name="titleAndSeries" value="Titel/Serie"/> + <node name="author" value="Auteur"/> + <node name="category" value="Categorie"/> + <node name="description" value="Beschrijving"/> + <node name="annotation" value="Zoekresultaten voor: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Ga naar Pagina"/> + <node name="pageNumber" value="Ga naar Paginanummer"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Bewerk Tag"/> + <node name="name" value="Tag Naam"/> + <node name="includeSubtags" value="Subtags Toevoegen"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Tag Klonen"/> + <node name="name" value="Tag Naam"/> + <node name="includeSubtags" value="Subtags Toevoegen"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Boek Verwijderen"/> + <node name="message" value="Verwijder het Boek “%s†?"/> + <node name="deleteFile" value="Wilt U het bestand “%s†volledig verwijderen?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Tag Verwijderen"/> + <node name="message" value="Tag “%sâ€verwijderen?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Fout"/> + <node name="message" value="Kan : %s niet openen"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Fout"/> + <node name="message" value="Kan %s niet verwijderen"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Fout"/> + <node name="message" value="Help bestand niet gevonden"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Bibliotheeklijst leeg"/> + <node name="authenticationFailed" value="Aanmelden mislukt"/> + <node name="internalError" value="Interne server fout"/> + <node name="purchaseNotEnoughMoney" value="Onvoldoende krediet"/> + <node name="purchaseMissingBook" value="Boek bestaat niet"/> + <node name="purchaseAlreadyPurchased" value="Al eerder aangekocht"/> + <node name="bookNotPurchased" value="Boek is niet gekocht"/> + <node name="downloadLimitExceeded" value="Download limiet overschreden"/> + <node name="unsupportedOperation" value="Operatie niet ondersteund"/> + <node name="loginAlreadyTaken" value="Gebruikersnaam is al in gebruik"/> + <node name="loginNotSpecified" value="Gebruikersnaam kiezen"/> + <node name="passwordNotSpecified" value="Kies een wachtwoord"/> + <node name="emailNotSpecified" value="Kies een e-mail adres"/> + <node name="invalidEMail" value="Ongeldig e-mail adres"/> + <node name="tooManyRegistrations" value="Teveel registraties van dit IP; probeer het over enkele minuten opnieuw"/> + <node name="noUserEmail" value="De gebruiker met het gespecificeerde e-mail adres is niet bekend"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Fout tijden het downloaden"/> + <node name="message" value="Kan het boek op dit moment niet downloaden"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Boek wordt geopend..."/> + <node name="loadingBookList" value="Bibliotheek wordt geopend..."/> + <node name="migrate" value="Nieuwe versie gevonden, moment a.u.b..."/> + <node name="downloadBookList" value="Boekenlijst wordt geopend..."/> + <node name="downloadBook" value="Boek wordt gedownload..."/> + <node name="downloadImages" value="Beelden worden gedownload…"/> + <node name="authentication" value="Aanmelden..."/> + <node name="purchaseBook" value="Boek wordt gekocht…"/> + <node name="initializeAuthenticationManager" value="Account informatie wordt opgehaald..."/> + <node name="loadSubCatalog" value="Catalogus wordt geladen..."/> + <node name="registerUser" value="Nieuwe account wordt aangemaakt..."/> + <node name="passwordRecovery" value="Het wachtwoord wordt hersteld..."/> + <node name="authenticationCheck" value="Account wordt gecontroleerd..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Koop Boek"/> + <node name="message" value="Wilt U zeker dat U het boek “%s†wilt kopen?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Authenticatie"/> + <node name="login" value="Gebruikersnaam"/> + <node name="password" value="Wachtwoord"/> + <node name="skipIP" value="Niet aan ip-adres binden"/> + <node name="loginIsEmpty" value="Gebruikersnaam kan niet leeg zijn"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informatie"/> + <node name="message" value="Catalogus is leeg."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Catalogus uitschakelen"/> + <node name="message" value="Weet U zeker dan U de “%s†catalogus wilt uitschakelen? U kunt deze catalogus weer activeren in de “Netwerk Zoeken†pagina van de instellingen."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Boek Verwijderen"/> + <node name="message" value="Weet U zeker dat U het boek “%sâ€volledig wilt verwijderen?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Gebruiker Registreren"/> + <node name="login" value="Gebruikersnaam"/> + <node name="password" value="Wachtwoord"/> + <node name="confirmPassword" value="Wachtwoord bevestigen"/> + <node name="email" value="E-mail" tooltip="E-mail wordt gebruikt om verloren wachtwoorden te herstellen Als U geen email-adres specificeerd kunt U Uw wachtwoord niet herstellen."/> + <node name="differentPasswords" value="Wachtwoorden zijn niet gelijk."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Wachtwoord Herstel"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Wachtwoord Herstel"/> + <node name="message" value="Een email met verdere instructies is naar %s gestuurd"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Download Fout"/> + <node name="message" value="Kan de downloaded %s niet openen."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Base"/> + <node name="Regular Paragraph" value="Reguliere Paragraaf"/> + <node name="Title" value="Titel"/> + <node name="Section Title" value="Sectie Titel"/> + <node name="Poem Title" value="Poëzie Titel"/> + <node name="Subtitle" value="Subtitel"/> + <node name="Annotation" value="Annotatie"/> + <node name="Epigraph" value="Epigraaf"/> + <node name="Stanza" value="Couplet"/> + <node name="Verse" value="Vers"/> + <node name="Preformatted text" value="Geformatteerde Tekst"/> + <node name="Image" value="Afbeelding"/> + <node name="Cite" value="Citaat"/> + <node name="Author" value="Auteur"/> + <node name="Date" value="Datum"/> + <node name="Internal Hyperlink" value="Interne Hyperlink"/> + <node name="Footnote" value="Voetnoot"/> + <node name="Emphasis" value="Nadruk"/> + <node name="Strong" value="Strong"/> + <node name="Subscript" value="Subscript"/> + <node name="Superscript" value="Superscript"/> + <node name="Code" value="Code"/> + <node name="StrikeThrough" value="Doorhalen"/> + <node name="Contents Table" value="Inhoudstabel"/> + <node name="Library Entry" value="Bibliotheek Inschrijving"/> + <node name="Recent Book List" value="Recente Boekenlijst"/> + <node name="Italic" value="Cursief"/> + <node name="Bold" value="Vet"/> + <node name="Definition" value="Definitie"/> + <node name="Definition Description" value="Definitie Beschrijving"/> + <node name="Header 1" value="Kopttekst 1"/> + <node name="Header 2" value="Kopttekst 2"/> + <node name="Header 3" value="Kopttekst 3"/> + <node name="Header 4" value="Kopttekst 4"/> + <node name="Header 5" value="Kopttekst 5"/> + <node name="Header 6" value="Kopttekst 6"/> + <node name="External Hyperlink" value="Externe Hyperlink"/> + <node name="Link to Another Book" value="Link naar een Ander Boek"/> + </node> + <node name="external"> + <node name="browser" value="Browser"/> + <node name="defaultBrowser" value="Standaard Browser"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Onbekende Fout"/> + <node name="unsupportedCompressionMethod" value="Onbekende Compressie Methode"/> + <node name="encryptedFile" value="DRM-protected Bestand"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Netwerk Bibliotheek"/> + </node> + <node name="library"> + <node name="caption" value="Bibliotheek"/> + </node> +</resources> diff --git a/reader/data/resources/pl.xml b/reader/data/resources/pl.xml new file mode 100644 index 0000000..c47405f --- /dev/null +++ b/reader/data/resources/pl.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Polish TDE-Ebook-Reader resources, by RafaÅ‚ BakuÅ‚a --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Pokaż książki"/> + <node name="collapseTree" value="Ukryj książki"/> + <node name="edit" value="Edytuj"/> + <node name="unknownAuthor" value="Nieznany autor"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Pokaż książki"/> + <node name="collapseTree" value="Ukryj książki"/> + <node name="edit" value="Edytuj etykietÄ™"/> + <node name="clone" value="Powiel etykietÄ™"/> + <node name="delete" value="UsuÅ„ etykietÄ™"/> + <node name="noTags" value="Książki bez etykiety"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Pokaż książki"/> + <node name="collapseTree" value="Ukryj książki"/> + </node> + <node name="bookNode"> + <node name="read" value="Czytaj książkÄ™"/> + <node name="edit" value="Edytuj informacje"/> + <node name="delete" value="UsuÅ„ książkÄ™"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Po autorze"> + <node name="summary" value="Książki posortowane po autorze"/> + </node> + <node name="byTitle" value="Po tytule"> + <node name="summary" value="Książki posortowane po tytule"/> + </node> + <node name="byDate" value="Po dacie"> + <node name="summary" value="Książki posortowane po dacie zakupu"/> + </node> + <node name="bySeries" value="Seriami"> + <node name="summary" value="Książki posortowane seriami"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="RozwiÅ„"/> + <node name="collapseTree" value="ZwiÅ„"/> + <node name="reload" value="PrzeÅ‚aduj"/> + <node name="openInBrowser" value="Otwórz w przeglÄ…darce"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Otwórz katalog"/> + <node name="collapseTree" value="Zamknij katalog"/> + <node name="login" value="Zaloguj"/> + <node name="logout" value="Wyloguj (%s)"/> + <node name="reload" value="PrzeÅ‚aduj"/> + <node name="dontShow" value="Nie pokazuj tego katalogu"/> + <node name="topupAccount" value="DoÅ‚aduj konto (aktualnie: %s)"/> + <node name="register" value="Zapisz siÄ™"/> + <node name="passwordRecovery" value="Odzyskaj hasÅ‚o"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Szukaj"/> + <node name="expandTree" value="Pokaż wyniki"/> + <node name="collapseTree" value="Ukryj wyniki"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Pokaż książki"/> + <node name="collapseTree" value="Ukryj książki"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Pokaż książki"/> + <node name="collapseTree" value="Ukryj książki"/> + </node> + <node name="bookNode"> + <node name="read" value="Czytaj kopiÄ™ lokalnÄ…"/> + <node name="delete" value="UsuÅ„ kopiÄ™ lokalnÄ…"/> + <node name="download" value="Pobierz"/> + <node name="readDemo" value="Czytaj próbkÄ™"/> + <node name="downloadDemo" value="Pobierz próbkÄ™"/> + <node name="demo" value="Próbka"/> + <node name="buy" value="Kup (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Informacje o książce..."/> + <node name="toc" value="Spis zawartoÅ›ci"/> + <node name="showLibrary" value="Otwórz bibliotekÄ™"/> + <node name="showNetLibrary" value="Biblioteka sieciowa"/> + <node name="addBook" value="Otwórz plik..."/> + <node name="showRecent" value="Ostatnio czytane"/> + <node name="library" value="Biblioteka"> + <node name="showLibrary" value="Otwórz"/> + <node name="previousBook" value="Poprzednia książka"/> + <node name="showRecent" value="Poprzednia"/> + <node name="addBook" value="Dodaj książkÄ™..."/> + <node name="showHelp" value="O TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Idź na poczÄ…tek dokumentu"/> + <node name="gotoPageNumber" value="Idź na stronÄ™..."/> + <node name="gotoSectionStart" value="Idź na poczÄ…tek sekcji tekstu"/> + <node name="gotoSectionEnd" value="Idź na koniec sekcji tekstu"/> + <node name="nextTOCSection" value="Idź do nastÄ™pnej pozycji spisu"/> + <node name="previousTOCSection" value="Idź do poprzedniej pozycji spisu"/> + <node name="navigate" value="Nawigacja"> + <node name="gotoHome" value="Idź na poczÄ…tek dokumentu"/> + <node name="gotoPageNumber" value="Idź do strony..."/> + <node name="gotoSectionStart" value="Idź na poczÄ…tek sekcji tekstu"/> + <node name="gotoSectionEnd" value="Idź na koniec sekcji tekstu"/> + <node name="nextTOCSection" value="Idź do nastÄ™pnej pozycji spisu"/> + <node name="previousTOCSection" value="Idź do poprzedniej pozycji spisu"/> + <node name="undo" value="Powrót"/> + <node name="redo" value="Naprzód"/> + </node> + <node name="selection" value="Zaznaczenie"> + <node name="copyToClipboard" value="Kopiuj do schowka"/> + <node name="openInDictionary" value="Otwórz w sÅ‚owniku"/> + <node name="clearSelection" value="Wyczyść"/> + </node> + <node name="search" value="Znajdź"> + <node name="search" value=" Znajdź tekst..."/> + <node name="findNext" value="Znajdź nastÄ™pne"/> + <node name="findPrevious" value="Znajdź poprzednie"/> + </node> + <node name="view" value="Widok"> + <node name="rotate" value="Obróć ekran"/> + <node name="toggleFullscreen" value="PeÅ‚ny ekran"/> + <node name="toggleIndicator" value="ZmieÅ„ wskaźnik"/> + </node> + <node name="preferences" value="Ostatnie okno preferencji..."/> + <node name="quit" value="Zamknij"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Czytaj książkÄ™"/> + <node name="tooltip" value="Czytaj"/> + </node> + <node name="showLibrary"> + <node name="label" value="Biblioteka"/> + <node name="tooltip" value="Pokaż książki"/> + <node name="popup" value="Pokaż ostatnio otwierane książki"/> + </node> + <node name="showRecent"> + <node name="label" value="Ostatnie książki"/> + <node name="tooltip" value="Pokaż ostatnio otwierane książki"/> + </node> + <node name="byAuthor"> + <node name="label" value="WedÅ‚ug autora"/> + <node name="tooltip" value="Segreguj książki wedÅ‚ug autora"/> + </node> + <node name="byTag"> + <node name="label" value="WedÅ‚ug opisu"/> + <node name="tooltip" value="Segreguj książki wedÅ‚ug opisu"/> + </node> + <node name="addBook"> + <node name="label" value="Dodaj plik"/> + <node name="tooltip" value="Dodaj plik do biblioteki"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Sieć"/> + <node name="tooltip" value="Szukaj w bibliotece sieciowej"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Proste szukanie"/> + <node name="tooltip" value="Szukaj w sieci"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Szukaj"/> + <node name="tooltip" value="Zaawansowane szukanie w sieci"/> + </node> + <node name="gotoHome"> + <node name="label" value="Idź na poczÄ…tek"/> + <node name="tooltip" value="Idź na poczÄ…tek tekstu"/> + </node> + <node name="undo"> + <node name="label" value="Powrót"/> + <node name="tooltip" value="Powrót"/> + </node> + <node name="redo"> + <node name="label" value="Naprzód"/> + <node name="tooltip" value="Naprzód"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Idź do strony"/> + <node name="tooltip" value="Idź do strony"/> + </node> + <node name="toc"> + <node name="label" value="Spis"/> + <node name="tooltip" value="Spis treÅ›ci"/> + </node> + <node name="search"> + <node name="label" value="Szukaj"/> + <node name="tooltip" value="Szukaj tekstu"/> + </node> + <node name="findNext"> + <node name="label" value="NastÄ™pny"/> + <node name="tooltip" value="Znajdź nastÄ™pny"/> + </node> + <node name="findPrevious"> + <node name="label" value="Poprzedni"/> + <node name="tooltip" value="Znajdź poprzedni"/> + </node> + <node name="rotate"> + <node name="label" value="Obrót"/> + <node name="tooltip" value="Obróć tekst"/> + </node> + <node name="showHelp"> + <node name="label" value="Informacje"/> + <node name="tooltip" value="O TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Filtr"/> + <node name="tooltip" value="Filtr"/> + </node> + <node name="preferences"> + <node name="label" value="Ostanie okno preferencji"/> + <node name="tooltip" value="Pokaż ostatnio otwierane okno preferencji"/> + </node> + <node name="bookInfo"> + <node name="label" value="Informacje o książce"/> + <node name="tooltip" value="Pokaż informacje o książce"/> + </node> + <node name="libraryOptions"> + <node name="label" value="Preferencje biblioteki"/> + <node name="tooltip" value="Pokaż okno preferencji biblioteki"/> + </node> + <node name="networkOptions"> + <node name="label" value="Preferencje sieci"/> + <node name="tooltip" value="Pokaż okno preferencji sieci"/> + </node> + <node name="systemOptions"> + <node name="label" value="Preferencje systemu"/> + <node name="tooltip" value="Pokaż okno preferencji systemu"/> + </node> + <node name="readingOptions"> + <node name="label" value="Preferencje Czytania"/> + <node name="tooltip" value="Pokaż okno preferencji czytania"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" value="Preferencje wyglÄ…du i dziaÅ‚ania"/> + <node name="tooltip" value="Pokaż okno preferencji wyglÄ…du i dziaÅ‚ania"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&DziaÅ‚aj!"/> + <node name="thisOnly" value="Tylko ten"/> + <node name="withSubtags" value="Dodatkowe etykiety"/> + <node name="removeLink" value="UsuÅ„ z biblioteki"/> + <node name="removeFile" value="UsuÅ„ z dysku"/> + <node name="yesToAll" value="Tak na &wszystkie"/> + <node name="buy" value="&Kup"/> + <node name="buyAndDownload" value="Kup i &pobierz"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Opcje biblioteki"/> + <node name="tab"> + <node name="Library" value="Biblioteka"> + <node name="bookPath" value="Katalog z książkami"/> + <node name="lookInSubdirectories" value="Szukaj książek w podkatalogach"/> + <node name="collectBooksWithoutMetaInfo" value="Dodaj książki bez opisu"/> + <node name="downloadDirectory" value="Pobieraj książki do katalogu"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Opcje sieci"/> + <node name="tab"> + <node name="NetworkLibrary" value="Szukanie w sieci"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Użyj proxy"/> + <node name="proxyHost" value="Host proxy"/> + <node name="proxyPort" value="Port proxy"/> + <node name="timeout" value="Przekroczony czas operacji sieciowej, sekundy"/> + </node> + <node name="Web" value="Internet"> + <node name="enableIntegration" value="Otwórz zewnÄ™trzne linki w %s"/> + <node name="defaultText" value="Otwórz zewnÄ™trzne linki w przeglÄ…darce"/> + <node name="choice" value="Użyj przeglÄ…darki"/> + <node name="command" value="Polecenie do wykonania"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Opcje systemu"/> + <node name="tab"> + <node name="Language" value="JÄ™zyk"> + <node name="autoDetect" value="Automatycznie wykryj jÄ™zyk i kodowanie"/> + <node name="defaultLanguage" value="DomyÅ›lny jÄ™zyk"/> + <node name="defaultEncodingSet" value="DomyÅ›lny zestaw znaków"/> + <node name="defaultEncoding" value="DomyÅ›lne kodowanie"/> + <node name="useWindows1252Hack" value="Użyj windows-1252 zamiast iso-8859-1"/> + </node> + <node name="Config" value="Konfiguracja"> + <node name="autoSave" value="Automatyczny zapis stanu"/> + <node name="timeout" value="OdstÄ™p miÄ™dzy zapisami, w sekundach"/> + </node> + <node name="Dictionary" value="SÅ‚ownik"> + <node name="enableIntegration" value="Włącz integracjÄ™ z %s"/> + <node name="defaultText" value="Włącz integracjÄ™ ze sÅ‚ownikiem"/> + <node name="choice" value="Integruj z"/> + <node name="singleClickOpen" value="Otwórz pojedynczym klikniÄ™ciem"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Wykonaj przy zwolnieniu klawisza, nie przy naciÅ›niÄ™ciu"/> + <node name="minStylusPressure" value="Minimalny nacisk rysika"/> + <node name="maxStylusPressure" value="Maksymalny nacisk rysika"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Opcje dziaÅ‚ania"/> + <node name="tab"> + <node name="Scrolling" value="Przewijanie"> + <node name="keyScrollDelay" value="Opóźnienie powtarzania klawisza, ms"/> + <node name="keyLinesToScroll" value="Liczba przewijanych wierszy na wciÅ›niÄ™cie klawisza"/> + <node name="keyLinesToKeep" value="Liczba powtarzanych wierszy przy przewijaniu stron"/> + <node name="enableTapScrolling" value="Włącz przewijanie dotykiem"/> + <node name="fingerOnly" value="Przewijaj tylko dotykiem palca"/> + </node> + <node name="Selection" value="Zaznaczanie"> + <node name="enableSelection" value="Włącz zaznaczanie tekstu"/> + </node> + <node name="Indicator" value="Pasek postÄ™pu"> + <node name="type" value="Pokaż jako"> + <node name="osScrollbar" value="Pasek systemowy"/> + <node name="fbIndicator" value="Wskaźnik w starym stylu"/> + <node name="none" value="Nie pokazuj"/> + </node> + <node name="height" value="Wysokość paska"/> + <node name="offset" value="OdstÄ™p od tekstu"/> + <node name="pageNumber" value="Pokaż pozycjÄ™ liczbowo"/> + <node name="time" value="Pokaż zegar"/> + <node name="fontSize" value="Rozmiar czcionki"/> + <node name="tocMarks" value="Pokaż znaczniki spisu"/> + <node name="navigation" value="Włącz nawigacjÄ™"/> + </node> + <node name="Rotation" value="Obrót"> + <node name="direction" value="Rodzaj obrotu"> + <node name="disabled" value="Wyłączony"/> + <node name="clockwise" value="90 stopni w prawo"/> + <node name="counterclockwise" value="90 stopni w lewo"/> + <node name="180" value="180 stopni"/> + <node name="cycle" value="Wszystkie 4 kierunki po kolei"/> + </node> + </node> + <node name="Keys" value="Klawisze"> + <node name="grabSystemKeys" value="Przechwyć klawisze systemowe"/> + <node name="separate" value="Funkcja zależna od obrotu ekranu"/> + <node name="orientation" value="Obrót"> + <node name="degrees0" value="0 stopni"/> + <node name="degrees90ccw" value="90 stopni w prawo"/> + <node name="degrees180" value="180 stopni"/> + <node name="degrees90cw" value="90 stopni w prawo"/> + </node> + <node name="action"> + <node name="none" value="Nic"/> + <node name="showLibrary" value="Pokaż bibliotekÄ™"/> + <node name="showNetLibrary" value="Pokaż bibliotekÄ™ sieciowÄ…"/> + <node name="showRecent" value="Pokaż ostatnie książki"/> + <node name="previousBook" value="Otwórz poprzedniÄ… książkÄ™"/> + <node name="toc" value="Pokaż spis zawartoÅ›ci"/> + <node name="gotoHome" value="Idź na poczÄ…tek"/> + <node name="gotoSectionStart" value="Idź na poczÄ…tek sekcji"/> + <node name="gotoSectionEnd" value="Idź na koniec sekcji"/> + <node name="nextTOCSection" value="Idź do nastÄ™pnej sekcji spisu"/> + <node name="previousTOCSection" value="Idź do poprzedniej sekcji spisu"/> + <node name="pageForward" value="PrzewiÅ„ stronÄ™ do przodu"/> + <node name="pageBackward" value="PrzewiÅ„ stronÄ™ do tyÅ‚u"/> + <node name="lineForward" value="PrzewiÅ„ wiersz do przodu"/> + <node name="lineBackward" value="PrzewiÅ„ wiersz do tyÅ‚u"/> + <node name="undo" value="Cofnij"/> + <node name="redo" value="Ponów"/> + <node name="copyToClipboard" value="Kopiuj zaznaczony tekst do schowka"/> + <node name="openInDictionary" value="Otwórz zaznaczony tekst w sÅ‚owniku"/> + <node name="clearSelection" value="Wyczyść zaznaczenie"/> + <node name="search" value="Szukaj"/> + <node name="findPrevious" value="Znajdź poprzedni"/> + <node name="findNext" value="Znajdź nastÄ™pny"/> + <node name="increaseFont" value="ZwiÄ™ksz rozmiar czcionki"/> + <node name="decreaseFont" value="Zmniejsz rozmiar czcionki"/> + <node name="toggleIndicator" value="Przełącz wskaźnik pozycji"/> + <node name="toggleFullscreen" value="Przełącz na peÅ‚ny ekran"/> + <node name="rotate" value="Obróć ekran"/> + <node name="addBook" value="Dodaj książkÄ™"/> + <node name="cancel" value="Anuluj"/> + <node name="quit" value="ZakoÅ„cz"/> + <node name="bookInfo" value="Pokaż informacje o książce"/> + <node name="preferences" value="Pokaż ostatnio otwarte okno preferencji"/> + </node> + <node name="quitOnCancel" value="ZakoÅ„cz program gdy anuluj"/> + <node name="keyDelay" value="OdstÄ™p pomiÄ™dzy ponownym wciÅ›niÄ™ciem klawisza"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Opcje wyglÄ…du i dziaÅ‚ania"/> + <node name="tab"> + <node name="CSS" value="Personalizacja wyÅ›wietlania (CSS)"> + <node name="overrideSpecifiedFonts" value="Zawsze używaj moje czcionki"/> + </node> + <node name="Margins" value="Marginesy"> + <node name="left" value="Lewy margines"/> + <node name="right" value="Prawy margines"/> + <node name="top" value="Górny margines"/> + <node name="bottom" value="Dolny margines"/> + </node> + <node name="Format" value="Formatowanie"> + <node name="optionsFor" value="Opcja dotyczy"/> + <node name="lineSpacing" value="OdstÄ™p miÄ™dzy wierszami"> + <node name="unchanged" value="<bez zmian>"/> + </node> + <node name="firstLineIndent" value="WciÄ™cie pierwszego wiersza"/> + <node name="alignment" value="Wyrównanie"> + <node name="left" value="Do lewej"/> + <node name="right" value="Do prawej"/> + <node name="center" value="Do Å›rodka"/> + <node name="justify" value="Do lewej i prawej"/> + <node name="unchanged" value="<bez zmian>"/> + </node> + <node name="spaceBefore" value="OdstÄ™p przed"/> + <node name="spaceAfter" value="OdstÄ™p po"/> + <node name="startIndent" value="WciÄ™cie na poczÄ…tku wiersza"/> + <node name="endIndent" value="WciÄ™cie na koÅ„cu wiersza"/> + </node> + <node name="Styles" value="Style"> + <node name="optionsFor" value="Opcja dotyczy"/> + <node name="fontFamily" value="Czcionka"> + <node name="unchanged" value="<bez zmiand>"/> + </node> + <node name="fontSize" value="Rozmiar"/> + <node name="fontSizeDifference" value="Różnica wielkoÅ›ci"/> + <node name="bold" value="Pogrubiona"/> + <node name="italic" value="Kursywa"/> + <node name="allowHyphenations" value="Zezwól na dzielenie wyrazów"/> + <node name="autoHyphenations" value="Automatyczne dzielenie wyrazów"/> + </node> + <node name="Colors" value="Kolory"> + <node name="colorFor" value="Kolor dla"> + <node name="background" value="TÅ‚o"/> + <node name="selectionBackground" value="TÅ‚o zaznaczenia"/> + <node name="text" value="ZwykÅ‚y tekst"/> + <node name="internalLink" value="WewnÄ™trzny hiperlink"/> + <node name="externalLink" value="ZewnÄ™trzny hiperlink"/> + <node name="bookLink" value="Link do innej książki"/> + <node name="highlighted" value="Zaznaczony tekst"/> + <node name="treeLines" value="Linie drzewa"/> + <node name="indicator" value="Pasek postÄ™pu"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informacje o książce"/> + <node name="tab"> + <node name="Common" value="Podstawowe"> + <node name="file" value="Plik"/> + <node name="title" value="TytuÅ‚"/> + <node name="language" value="JÄ™zyk"/> + <node name="encodingSet" value="Zestaw znaków"/> + <node name="encoding" value="Kodowanie"/> + </node> + <node name="Authors" value="Autorzy"> + <node name="authorDisplayName" value="Autor"/> + </node> + <node name="Series" value="Serie"> + <node name="seriesTitle" value="Seria"/> + <node name="bookIndex" value="Tom"/> + </node> + <node name="Tags" value="Etykiety"> + <node name="tags" value="Etykieta"/> + </node> + <node name="Text" value="Tekst"> + <node name="breakType" value="Åam akapit w"/> + <node name="ignoreIndent" value="Ignoruj wciÄ™cie mniejsze niż"/> + <node name="buildTOC" value="Stwórz spis treÅ›ci"/> + <node name="emptyLines" value="Pusty wiersz przed nowÄ… sekcjÄ…"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Åam akapit w"/> + <node name="ignoreIndent" value="Ignoruj wciÄ™cie mniejsze niż"/> + <node name="buildTOC" value="Stwórz spis treÅ›ci"/> + <node name="emptyLines" value="Pusty wiersz przed nowÄ… sekcjÄ…"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Informacje o autorze"/> + <node name="name" value="Autor"/> + <node name="sortKey" value="Sortuj wedÅ‚ug"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Dodaj książkÄ™ do biblioteki"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Szukaj tekstu"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignoruj wielkość liter"/> + <node name="wholeText" value="W w&caÅ‚ym tekÅ›cie"/> + <node name="backward" value="&Do tyÅ‚u"/> + <node name="currentSection" value="&Tylko ta sekcja"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Szukaj w sieci"/> + <node name="titleAndSeries" value="TytuÅ‚/Seria"/> + <node name="author" value="Autor"/> + <node name="category" value="Kategoria"/> + <node name="description" value="Opis"/> + <node name="annotation" value="Wyniki szukania dla: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Idź do strony"/> + <node name="pageNumber" value="Idź do strony numer"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Edytuj etykietÄ™"/> + <node name="name" value="Nazwa etykiety"/> + <node name="includeSubtags" value="Dołącz dodatkowe etykiety"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Powiel etykietÄ™"/> + <node name="name" value="Nazwa etykiety"/> + <node name="includeSubtags" value="Dołącz dodatkowe etykiety"/> + </node> + <node name="removeBookBox"> + <node name="title" value="UsuÅ„ książkÄ™"/> + <node name="message" value="Usunąć książkÄ™ “%s†z biblioteki?"/> + <node name="deleteFile" value="Czy na pewno chcesz usunąć plik “%s†z dysku?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="UsuÅ„ etykietÄ™"/> + <node name="message" value="UsuÅ„ etykietÄ™ “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Błąd"/> + <node name="message" value="Nie można otworzyć: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Błąd"/> + <node name="message" value="Nie można usunąć pliku %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Błąd"/> + <node name="message" value="Nie można znaleźć pliku pomocy"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Biblioteka jest pusta"/> + <node name="authenticationFailed" value="Uwierzytelnienie nieudane"/> + <node name="internalError" value="WewnÄ™trzny błąd serwera"/> + <node name="purchaseNotEnoughMoney" value="Za maÅ‚o pieniÄ™dzy"/> + <node name="purchaseMissingBook" value="BrakujÄ…ce książki"/> + <node name="purchaseAlreadyPurchased" value="Już kupiona"/> + <node name="bookNotPurchased" value="Książka nie zostaÅ‚a kupiona"/> + <node name="downloadLimitExceeded" value="limit pobierania przekroczony"/> + <node name="unsupportedOperation" value="NieobsÅ‚ugiwana operacja"/> + <node name="loginAlreadyTaken" value="Nazwa użytkownika w użyciu"/> + <node name="loginNotSpecified" value="Podaj nazwÄ™ użytkownika"/> + <node name="passwordNotSpecified" value="podaj niepuste hasÅ‚o"/> + <node name="emailNotSpecified" value="Podaj adres e-mail"/> + <node name="invalidEMail" value="Błędny adres e-mail"/> + <node name="tooManyRegistrations" value="Za dużo połączeÅ„ z twojego adresu IP; spróbuj znowu za kilka minut"/> + <node name="noUserEmail" value="Brak zarejestrowanych użytkowników z podanym adresem e-mail"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Błąd pobierania"/> + <node name="message" value="Chwilowo nie można pobrać tej książki"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Åadowanie książki. ProszÄ™ czekać..."/> + <node name="loadingBookList" value="Åadowanie biblioteki. ProszÄ™ czekać..."/> + <node name="migrate" value="Aktualizacja do nowej wersji. ProszÄ™ czekać..."/> + <node name="downloadBookList" value="Pobieranie listy książek. ProszÄ™ czekać..."/> + <node name="downloadBook" value="Pobieranie książki. ProszÄ™ czekać..."/> + <node name="downloadImages" value="Pobieranie obrazów. ProszÄ™ czekać..."/> + <node name="authentication" value="Uwierzytelnianie. ProszÄ™ czekać..."/> + <node name="purchaseBook" value="Zakup książki. ProszÄ™ czekać..."/> + <node name="initializeAuthenticationManager" value="Pobieranie informacji o koncie. ProszÄ™ czekać..."/> + <node name="loadSubCatalog" value="Åadowanie katalogu. ProszÄ™ czekać..."/> + <node name="registerUser" value="Rejestracja nowego konta. ProszÄ™ czekać..."/> + <node name="passwordRecovery" value="Odzyskiwanie hasÅ‚a. ProszÄ™ czekać..."/> + <node name="authenticationCheck" value="Weryfikacja konta. ProszÄ™ czekać..."/> + <node name="signOut" value="Wylogowywanie. ProszÄ™ czekać..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Zakup książki"/> + <node name="message" value="Czy na pewno chcesz kupić książkÄ™ “%s†?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Uwierzytelnianie"/> + <node name="login" value="Nazwa użytkownika"/> + <node name="password" value="HasÅ‚o"/> + <node name="skipIP" value="Nie wiąż z adresem IP"/> + <node name="loginIsEmpty" value="Nazwa użytkownika nie może być pusta"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Informacje"/> + <node name="message" value="Katalog jest pusty."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Zablokuj Katalog"/> + <node name="message" value="Czy na pewno chcesz zablokować katalog “%s†? Możesz odblokować ten katalog w zakÅ‚adce “Szukanie w Sieci†w opcjach."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="UsuÅ„ książkÄ™"/> + <node name="message" value="Czy na pewno chcesz usunąć książkÄ™ “%s†z dysku?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Zarejestruj użytkownika"/> + <node name="login" value="Nazwa użytkownika"/> + <node name="password" value="HasÅ‚o"/> + <node name="confirmPassword" value="Potwierdzenie hasÅ‚a"/> + <node name="email" value="E-mail" tooltip="E-mail jest używany do odzyskania hasÅ‚a w przypadku utraty. JeÅ›li nie okreÅ›lono e-maila nie można odzyskać hasÅ‚a."/> + <node name="differentPasswords" value="HasÅ‚o i potwierdzenie hasÅ‚a musi być identyczne."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Odzyskiwanie hasÅ‚a"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Odzyskiwanie hasÅ‚a"/> + <node name="message" value="Wiadomość z dalszymi instrukcjami zostaÅ‚a wysÅ‚ana do %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Błąd pobierania"/> + <node name="message" value="Nie można otworzyć pobranego pliku %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Główny tekst"/> + <node name="Regular Paragraph" value="StaÅ‚y akapit"/> + <node name="Title" value="TytuÅ‚"/> + <node name="Section Title" value="TytuÅ‚ sekcji"/> + <node name="Poem Title" value="TytuÅ‚ wiersza"/> + <node name="Subtitle" value="Lista dialogowa"/> + <node name="Annotation" value="Komentarz"/> + <node name="Epigraph" value="Epigraf"/> + <node name="Stanza" value="Strofa"/> + <node name="Verse" value="Wers"/> + <node name="Preformatted text" value="Tekst preformatowany"/> + <node name="Image" value="Obraz"/> + <node name="Cite" value="Cytat"/> + <node name="Author" value="Autor"/> + <node name="Date" value="Data"/> + <node name="Internal Hyperlink" value="WewnÄ™trzny hiperlink"/> + <node name="Footnote" value="Przypis"/> + <node name="Emphasis" value="PodkreÅ›lenie"/> + <node name="Strong" value="WytÅ‚uszczenie"/> + <node name="Subscript" value="Indeks dolny"/> + <node name="Superscript" value="Indeks górny"/> + <node name="Code" value="Kod"/> + <node name="StrikeThrough" value="PrzekreÅ›lenie"/> + <node name="Contents Table" value="Spis treÅ›ci"/> + <node name="Library Entry" value="Wpis w bibliotece"/> + <node name="Recent Book List" value="Ostatnio czytane książki"/> + <node name="Italic" value="Kursywa"/> + <node name="Bold" value="Pogrubienie"/> + <node name="Definition" value="Definicja"/> + <node name="Definition Description" value="Opis definicji"/> + <node name="Header 1" value="Nagłówek 1"/> + <node name="Header 2" value="Nagłówek 2"/> + <node name="Header 3" value="Nagłówek 3"/> + <node name="Header 4" value="Nagłówek 4"/> + <node name="Header 5" value="Nagłówek 5"/> + <node name="Header 6" value="Nagłówek 6"/> + <node name="External Hyperlink" value="ZewnÄ™trzny hiperlink"/> + <node name="Link to Another Book" value="Link do innej książki"/> + </node> + <node name="external"> + <node name="browser" value="PrzeglÄ…darka"/> + <node name="defaultBrowser" value="DomyÅ›lna przeglÄ…darka"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Nieznany błąd"/> + <node name="unsupportedCompressionMethod" value="NieobsÅ‚ugiwana metoda kompresji"/> + <node name="encryptedFile" value="Plik zabezpieczony DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Biblioteka sieciowa"/> + </node> + <node name="library"> + <node name="caption" value="Biblioteka"/> + </node> +</resources> diff --git a/reader/data/resources/ru.xml b/reader/data/resources/ru.xml new file mode 100644 index 0000000..113bfca --- /dev/null +++ b/reader/data/resources/ru.xml @@ -0,0 +1,719 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Показать книги"/> + <node name="collapseTree" value="Скрыть книги"/> + <node name="edit" value="ИнформациÑ"/> + <node name="unknownAuthor" value="Ðвтор не указан"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Показать книги"/> + <node name="collapseTree" value="Скрыть книги"/> + <node name="edit" value="Переименовать"/> + <node name="clone" value="Клонировать"/> + <node name="delete" value="Удалить"/> + <node name="noTags" value="Книги без категорий"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показать книги"/> + <node name="collapseTree" value="Скрыть книги"/> + </node> + <node name="bookNode"> + <node name="read" value="Читать"/> + <node name="edit" value="ИнформациÑ"/> + <node name="delete" value="Удалить"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="По авторам"> + <node name="summary" value="Книги, разложенные по авторам"/> + </node> + <node name="byTitle" value="По названиÑм"> + <node name="summary" value="Книги, отÑортированные по названиÑм"/> + </node> + <node name="byDate" value="По дате"> + <node name="summary" value="Книги, отÑортированные по дате покупки"/> + </node> + <node name="bySeries" value="По ÑериÑм"> + <node name="summary" value="Книги, разложенные по ÑериÑм"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Развернуть"/> + <node name="collapseTree" value="Свернуть"/> + <node name="reload" value="Обновить"/> + <node name="openInBrowser" value="Показать в браузере"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Открыть каталог"/> + <node name="collapseTree" value="Закрыть каталог"/> + <node name="login" value="Войти"/> + <node name="logout" value="Выйти (%s)"/> + <node name="reload" value="Обновить"/> + <node name="dontShow" value="Скрыть Ñтот каталог"/> + <node name="topupAccount" value="Пополнить Ñчёт (текущий Ñчёт: %s)"/> + <node name="topupAccountUndefined" value="Пополнить Ñчёт"/> + <node name="register" value="ЗарегиÑтрироватьÑÑ"/> + <node name="passwordRecovery" value="Забыли пароль?"/> + </node> + <node name="searchResultNode"> + <node name="searchfield" value="Введите запроÑ..."/> + <node name="title" value="Результаты поиÑка"/> + <node name="expandTree" value="Показать результаты"/> + <node name="collapseTree" value="Скрыть результаты"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Показать книги"/> + <node name="collapseTree" value="Скрыть книги"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показать книги"/> + <node name="collapseTree" value="Скрыть книги"/> + <node name="booksCount" value="%s книг"> + <node condition="modrange 11 19 100" value="%s книг"/> + <node condition="mod 1 10" value="%s книгa"/> + <node condition="modrange 2 4 10" value="%s книги"/> + </node> + </node> + <node name="bookNode"> + <node name="read" value="Читать локальную копию"/> + <node name="delete" value="Удалить локальную копию"/> + <node name="download" value="Скачать"/> + <node name="readDemo" value="Читать фрагмент"/> + <node name="downloadDemo" value="Скачать фрагмент"/> + <node name="demo" value="фрагмент"/> + <node name="buy" value="Купить (%s)"/> + <node name="alsoRead" value="ВмеÑте Ñ Ñтой книгой читают"/> + <node name="sameAuthor" value="Ð’Ñе книги автора %s"/> + </node> + </node> + <node name="bookInfo"> + <node name="bookInfo" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ книге"/> + <node name="fileInfo" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ файле"/> + <node name="description" value="ОпиÑание"/> + <node name="noDescription" value="ОпиÑание отÑутÑтвует."/> + <node name="annotation" value="ÐннотациÑ"/> + <node name="title" value="Ðазвание:"/> + <node name="authors" value="Ðвторы:"> + <node condition="value 1" value="Ðвтор:"/> + </node> + <node name="series" value="СериÑ:"/> + <node name="indexInSeries" value="Ðомер в Ñерии:"/> + <node name="tags" value="Категории:"> + <node condition="value 1" value="КатегориÑ:"/> + </node> + <node name="language" value="Язык:"/> + <node name="name" value="Ðазвание:"/> + <node name="type" value="Тип:"/> + <node name="size" value="Размер:"/> + <node name="time" value="ПоÑледнее изменение:"/> + <node name="sizeInBytes" value="%s байт"> + <node condition="modrange 11 19 100" value="%0 байт"/> + <node condition="modrange 2 4 10" value="%0 байта"/> + </node> + <node name="sizeInKiloBytes" value="%s кБ"/> + <node name="catalog" value="Каталог:"/> + <node name="extraLinks" value="СÑылки"/> + </node> + <node name="menu"> + <node name="bookInfo" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ книге..."/> + <node name="toc" value="Содержание"/> + <node name="showLibrary" value="Открыть библиотеку"/> + <node name="showNetLibrary" value="Ð¡ÐµÑ‚ÐµÐ²Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñ‚ÐµÐºÐ°"/> + <node name="addBook" value="Открыть файл..."/> + <node name="showRecent" value="Ðедавние книги"/> + <node name="library" value="Библиотека"> + <node name="showLibrary" value="Открыть"/> + <node name="previousBook" value="ÐŸÑ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ½Ð¸Ð³Ð°"/> + <node name="showRecent" value="Прочитанные книги"/> + <node name="addBook" value="Добавить файл..."/> + <node name="showHelp" value="О программе TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Ð’ начало книги"/> + <node name="gotoPageNumber" value="Ðа Ñтраницу..."/> + <node name="gotoSectionStart" value="Ð’ начало раздела"/> + <node name="gotoSectionEnd" value="Ð’ конец раздела"/> + <node name="nextTOCSection" value="К Ñледующей главе"/> + <node name="previousTOCSection" value="К предыдущей главе"/> + <node name="navigate" value="Переход"> + <node name="gotoHome" value="Ð’ начало книги"/> + <node name="gotoPageNumber" value="Ðа Ñтраницу..."/> + <node name="gotoSectionStart" value="Ð’ начало раздела"/> + <node name="gotoSectionEnd" value="Ð’ конец раздела"/> + <node name="nextTOCSection" value="К Ñледующей главе"/> + <node name="previousTOCSection" value="К предыдущей главе"/> + <node name="undo" value="Ðазад"/> + <node name="redo" value="Вперед"/> + </node> + <node name="selection" value="Пометка"> + <node name="copyToClipboard" value="Скопировать в буфер"/> + <node name="openInDictionary" value="ПоÑмотреть в Ñловаре"/> + <node name="clearSelection" value="Убрать пометку"/> + </node> + <node name="search" value="ПоиÑк"> + <node name="search" value="ИÑкать..."/> + <node name="findNext" value="ИÑкать дальше"/> + <node name="findPrevious" value="ИÑкать раньше"/> + </node> + <node name="view" value="Изображение"> + <node name="rotate" value="Повернуть"/> + <node name="toggleFullscreen" value="Ðа веÑÑŒ Ñкран"/> + <node name="toggleIndicator" value="Индикатор позиции"/> + </node> + <node name="preferences" value="ПоÑледние наÑтройки..."/> + <node name="quit" value="Закрыть"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Читать книгу"/> + <node name="tooltip" value="ВернутьÑÑ Ðº чтению"/> + </node> + <node name="showLibrary"> + <node name="label" value="Библиотека"/> + <node name="tooltip" value="Библиотека"/> + <node name="popup" value="Ðедавно прочитанные книги"/> + </node> + <node name="showRecent"> + <node name="label" value="ИÑториÑ"/> + <node name="tooltip" value="Ðедавно прочитанные книги"/> + </node> + <node name="byAuthor"> + <node name="label" value="По авторам"/> + <node name="tooltip" value="По авторам"/> + </node> + <node name="byTag"> + <node name="label" value="По категориÑм"/> + <node name="tooltip" value="По категориÑм"/> + </node> + <node name="addBook"> + <node name="label" value="Добавить"/> + <node name="tooltip" value="Добавить файл в библиотеку"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Сеть"/> + <node name="tooltip" value="ДоÑтуп к Ñетевым библиотекам"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="БыÑтрый поиÑк"/> + <node name="tooltip" value="БыÑтрый поиÑк в Ñети"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="ПоиÑк"/> + <node name="tooltip" value="ПоиÑк в Ñети"/> + </node> + <node name="gotoHome"> + <node name="label" value="Ð’ начало"/> + <node name="tooltip" value="Ð’ начало книги"/> + </node> + <node name="undo"> + <node name="label" value="Ðазад"/> + <node name="tooltip" value="Ðазад"/> + </node> + <node name="redo"> + <node name="label" value="Вперед"/> + <node name="tooltip" value="Вперед"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Перейти на"/> + <node name="tooltip" value="Перейти на Ñтраницу"/> + </node> + <node name="toc"> + <node name="label" value="Оглавление"/> + <node name="tooltip" value="Оглавление"/> + </node> + <node name="search"> + <node name="label" value="ПоиÑк"/> + <node name="tooltip" value="ПоиÑк"/> + </node> + <node name="findNext"> + <node name="label" value="Следующий"/> + <node name="tooltip" value="Ðайти Ñледующий"/> + </node> + <node name="findPrevious"> + <node name="label" value="Предыдущий"/> + <node name="tooltip" value="Ðайти предыдущий"/> + </node> + <node name="rotate"> + <node name="label" value="Поворот"/> + <node name="tooltip" value="Поворот текÑта"/> + </node> + <node name="showHelp"> + <node name="label" value="О программе"/> + <node name="tooltip" value="О программе"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Фильтровать"/> + <node name="tooltip" value="Фильтровать"/> + </node> + <node name="preferences"> + <node name="label" value="ПоÑледний открытый диалог наÑтроек"/> + <node name="tooltip" value="ПоÑледний открытый диалог наÑтроек"/> + </node> + <node name="bookInfo"> + <node name="label" value="О книге"/> + <node name="tooltip" value="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ книге"/> + </node> + <node name="libraryOptions"> + <node name="label" value="ÐаÑтройки библиотеки"/> + <node name="tooltip" value="Показать диалог наÑтроек библиотеки"/> + </node> + <node name="networkOptions"> + <node name="label" value="Сетевые наÑтройки"/> + <node name="tooltip" value="Показать диалог Ñетевых наÑтроек"/> + </node> + <node name="systemOptions"> + <node name="label" value="СиÑтемные наÑтройки"/> + <node name="tooltip" value="Показать диалог ÑиÑтемных наÑтроек"/> + </node> + <node name="readingOptions"> + <node name="label" value="ÐаÑтройки чтениÑ"/> + <node name="tooltip" value="Показать диалог наÑтроек чтениÑ"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" value="ÐаÑтройки внешнего вида"/> + <node name="tooltip" value="Показать диалог наÑтроек внешнего вида"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&ИÑкать"/> + <node name="thisOnly" value="Только Ñту"/> + <node name="withSubtags" value="С подкатегориÑми"/> + <node name="removeLink" value="Удалить из библиотеки"/> + <node name="removeFile" value="Удалить Ñ Ð´Ð¸Ñка"/> + <node name="yesToAll" value="Да Ð´Ð»Ñ &вÑех"/> + <node name="buy" value="&Купить"/> + <node name="buyAndDownload" value="Купить и &Ñкачать"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - ÐаÑтройки библиотеки"/> + <node name="tab"> + <node name="Library" value="Библиотека"> + <node name="bookPath" value="Каталоги Ñ ÐºÐ½Ð¸Ð³Ð°Ð¼Ð¸"/> + <node name="lookInSubdirectories" value="ИÑкать книги в подкаталогах"/> + <node name="collectBooksWithoutMetaInfo" value="Сканировать книги без метаинформации"/> + <node name="downloadDirectory" value="Каталог Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ¶Ð°ÐµÐ¼Ñ‹Ñ… книг"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - Сетевые наÑтройки"/> + <node name="tab"> + <node name="NetworkLibrary" value="ПоиÑк в Ñети"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="ИÑпользовать прокÑи-Ñервер"/> + <node name="proxyHost" value="ÐÐ´Ñ€ÐµÑ Ð¿Ñ€Ð¾ÐºÑи-Ñервера"/> + <node name="proxyPort" value="Порт прокÑи-Ñервера"/> + <node name="timeout" value="МакÑимальное Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸, Ñекунды"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Открывать внешние ÑÑылки в %s"/> + <node name="defaultText" value="Открывать внешние ÑÑылки в браузере"/> + <node name="choice" value="Браузер"/> + <node name="command" value="ВыполнÑть команду"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - СиÑтемные наÑтройки"/> + <node name="tab"> + <node name="Language" value="Язык"> + <node name="autoDetect" value="ÐвтоматичеÑки определÑть Ñзык и кодировку"/> + <node name="defaultLanguage" value="Язык по умолчанию"/> + <node name="defaultEncodingSet" value="Ðабор кодировок по умолчанию"/> + <node name="defaultEncoding" value="Кодировка по умолчанию"/> + <node name="useWindows1252Hack" value="ИÑпользовать windows-1252 вмеÑто iso-8859-1"/> + </node> + <node name="Config" value="ÐаÑтройки"> + <node name="autoSave" value="ÐвтоматичеÑки ÑохранÑть ÑоÑтоÑние"/> + <node name="timeout" value="Ð’Ñ€ÐµÐ¼Ñ Ð¼ÐµÐ¶Ð´Ñƒ ÑохранениÑми, Ñекунды"/> + </node> + <node name="Dictionary" value="Словари"> + <node name="enableIntegration" value="Включить интеграцию Ñ %s"/> + <node name="defaultText" value="Включить интеграцию Ñо Ñловарем"/> + <node name="choice" value="ИÑпользовать"/> + <node name="singleClickOpen" value="Открывать Ñловарь по нажатию на Ñлово"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Реагировать на отпуÑкание клавиши, а не на нажатие"/> + <node name="minStylusPressure" value="Минимальное давление ÑтилуÑа"/> + <node name="maxStylusPressure" value="МакÑимальное давление ÑтилуÑа"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - ÐаÑтройки чтениÑ"/> + <node name="tab"> + <node name="Scrolling" value="ПерелиÑтывание"> + <node name="keyScrollDelay" value="Задержка между лиÑтаниÑми клавишами"/> + <node name="keyLinesToScroll" value="Сколько Ñтрок пролиÑтывать за 1 раз"/> + <node name="keyLinesToKeep" value="Сколько Ñтрок оÑтавлÑть Ñ Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰ÐµÐ¹ Ñтраницы"/> + <node name="enableTapScrolling" value="Включить прокрутку нажатием на Ñкран"/> + <node name="fingerOnly" value="Только при нажатии пальцем"/> + </node> + <node name="Selection" value="Выделение"> + <node name="enableSelection" value="Разрешить выделение текÑта"/> + </node> + <node name="Indicator" value="Индикатор"> + <node name="type" value="Внешний вид"> + <node name="osScrollbar" value="полоÑа прокрутки"/> + <node name="fbIndicator" value="индикатор внизу"/> + <node name="none" value="не показывать"/> + </node> + <node name="height" value="Ð’Ñ‹Ñота индикатора"/> + <node name="offset" value="ОтÑтуп от текÑта"/> + <node name="pageNumber" value="Показывать номера Ñтраниц"/> + <node name="time" value="Показывать текущее времÑ"/> + <node name="fontSize" value="Размер шрифта"/> + <node name="tocMarks" value="Показывать пометки начала глав"/> + <node name="navigation" value="Реагировать на нажатиÑ"/> + </node> + <node name="Rotation" value="Поворот"> + <node name="direction" value="Как поворачивать"> + <node name="disabled" value="Ðе поворачивать вообще"/> + <node name="clockwise" value="Ðа 90 градуÑов по чаÑовой Ñтрелке"/> + <node name="counterclockwise" value="Ðа 90 градуÑов против чаÑовой Ñтрелки"/> + <node name="180" value="Ðа 180 градуÑов"/> + <node name="cycle" value="ПереключатьÑÑ Ð¼ÐµÐ¶Ð´Ñƒ 4 ориентациÑми"/> + </node> + </node> + <node name="Keys" value="Клавиши"> + <node name="grabSystemKeys" value="Перехватывать ÑиÑтемные клавиши"/> + <node name="separate" value="Свои наÑтройки Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ориентации текÑта"/> + <node name="orientation" value="При повороте на:"> + <node name="degrees0" value="0 градуÑов"/> + <node name="degrees90ccw" value="90 градуÑов против чаÑовой Ñтрелки"/> + <node name="degrees180" value="180 градуÑов"/> + <node name="degrees90cw" value="90 градуÑов по чаÑовой Ñтрелке"/> + </node> + <node name="action"> + <node name="none" value="Ðикакого дейÑтвиÑ"/> + <node name="showLibrary" value="Показать библиотеку"/> + <node name="showNetLibrary" value="Сетевые библиотеки"/> + <node name="showRecent" value="Показать прочитанные книги"/> + <node name="previousBook" value="Открыть предыдущую книгу"/> + <node name="toc" value="Показать оглавление"/> + <node name="gotoHome" value="Перейти в начало текÑта"/> + <node name="gotoSectionStart" value="Перейти в начало раздела"/> + <node name="gotoSectionEnd" value="Перейти в конец раздела"/> + <node name="nextTOCSection" value="Перейти к Ñледующей главе"/> + <node name="previousTOCSection" value="Перейти к предыдущей главе"/> + <node name="pageForward" value="ПролиÑтнуть Ñтраницу вперед"/> + <node name="pageBackward" value="ПролиÑтнуть Ñтраницу назад"/> + <node name="lineForward" value="ПролиÑтнуть Ñтроку вперед"/> + <node name="lineBackward" value="ПролиÑтнуть Ñтроку назад"/> + <node name="undo" value="Отменить переход"/> + <node name="redo" value="Повторить переход"/> + <node name="copyToClipboard" value="Скопировать помеченный текÑÑ‚ в буфер"/> + <node name="openInDictionary" value="Открыть помеченный текÑÑ‚ в Ñловаре"/> + <node name="clearSelection" value="Убрать пометку"/> + <node name="search" value="Показать диалог поиÑка"/> + <node name="findPrevious" value="ИÑкать назад"/> + <node name="findNext" value="ИÑкать вперед"/> + <node name="increaseFont" value="Увеличить размер шрифта"/> + <node name="decreaseFont" value="Уменьшить размер шрифта"/> + <node name="toggleIndicator" value="Показать/ÑпрÑтать индикатор"/> + <node name="toggleFullscreen" value="Включить/выключить полноÑкранный режим"/> + <node name="rotate" value="Повернуть текÑÑ‚"/> + <node name="addBook" value="Добавить файл в библиотеку"/> + <node name="cancel" value="Отменить текущий режим"/> + <node name="quit" value="Выйти из программы"/> + <node name="bookInfo" value="Показать информацию о книге"/> + <node name="preferences" value="Показать поÑледний открытый диалог наÑтроек"/> + </node> + <node name="quitOnCancel" value="Выходить из программы"/> + <node name="keyDelay" value="Задержка между нажатиÑми на клавиши"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" value="TDE-Ebook-Reader - ÐаÑтройки внешнего вида"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Ð’Ñегда иÑпользовать ÑобÑтвенные шрифты"/> + </node> + <node name="Margins" value="ОтÑтупы"> + <node name="left" value="ОтÑтуп Ñлева"/> + <node name="right" value="ОтÑтуп Ñправа"/> + <node name="top" value="ОтÑтуп Ñверху"/> + <node name="bottom" value="ОтÑтуп Ñнизу"/> + </node> + <node name="Format" value="Форматирование"> + <node name="optionsFor" value="ÐаÑтройки длÑ"/> + <node name="lineSpacing" value="Интервал"> + <node name="unchanged" value="<не менÑть>"/> + </node> + <node name="firstLineIndent" value="КраÑÐ½Ð°Ñ Ñтрока"/> + <node name="alignment" value="Выравнивание"> + <node name="left" value="левое"/> + <node name="right" value="правое"/> + <node name="center" value="по центру"/> + <node name="justify" value="по краÑм"/> + <node name="unchanged" value="<не менÑть>"/> + </node> + <node name="spaceBefore" value="ПропуÑк перед"/> + <node name="spaceAfter" value="ПропуÑк поÑле"/> + <node name="startIndent" value="ОтÑтуп в начале Ñтроки"/> + <node name="endIndent" value="ОтÑтуп в конце Ñтроки"/> + </node> + <node name="Styles" value="Стили"> + <node name="optionsFor" value="ÐаÑтройки длÑ"/> + <node name="fontFamily" value="Шрифт"> + <node name="unchanged" value="<не менÑть>"/> + </node> + <node name="fontSize" value="Размер"/> + <node name="fontSizeDifference" value="Размер"/> + <node name="bold" value="Жирный"/> + <node name="italic" value="КурÑив"/> + <node name="allowHyphenations" value="ПереноÑÑ‹"/> + <node name="autoHyphenations" value="ПереноÑÑ‹"/> + </node> + <node name="Colors" value="Цвета"> + <node name="colorFor" value="Цвет"> + <node name="background" value="фона"/> + <node name="selectionBackground" value="фона пометки"/> + <node name="text" value="обычного текÑта"/> + <node name="internalLink" value="ÑÑылки"/> + <node name="externalLink" value="внешней ÑÑылки"/> + <node name="bookLink" value="ÑÑылки на книгу"/> + <node name="highlighted" value="подÑвеченного текÑта"/> + <node name="treeLines" value="линий"/> + <node name="indicator" value="индикатора"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ книге"/> + <node name="tab"> + <node name="Common" value="ОÑÐ½Ð¾Ð²Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"> + <node name="file" value="Файл"/> + <node name="title" value="Ðазвание"/> + <node name="language" value="Язык"/> + <node name="encodingSet" value="Ðабор кодировок"/> + <node name="encoding" value="Кодировка"/> + </node> + <node name="Authors" value="Ðвторы"> + <node name="authorDisplayName" value="Ð˜Ð¼Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð°"/> + </node> + <node name="Series" value="СериÑ"> + <node name="seriesTitle" value="Ðазвание Ñерии"/> + <node name="bookIndex" value="Ðомер книги в Ñерии"/> + </node> + <node name="Tags" value="Категории"> + <node name="tags" value="Ðазвание категории"/> + </node> + <node name="Text" value="ТекÑÑ‚"> + <node name="breakType" value="Ðовый параграф по"/> + <node name="ignoreIndent" value="Игнорировать отÑтупы меньше"/> + <node name="buildTOC" value="Строить оглавление"/> + <node name="emptyLines" value="ПуÑтых Ñтрок между главами"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Ðовый параграф по"/> + <node name="ignoreIndent" value="Игнорировать отÑтупы меньше"/> + <node name="buildTOC" value="Строить оглавление"/> + <node name="emptyLines" value="ПуÑтых Ñтрок между главами"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± авторе"/> + <node name="name" value="ИмÑ"/> + <node name="sortKey" value="Сортировать по"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Добавление книги в библиотеку"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="ПоиÑк по текÑту"/> + <node name="text" value=""/> + <node name="ignoreCase" value="Игнорировать региÑтр букв"/> + <node name="wholeText" value="С начала текÑта"/> + <node name="backward" value="Ðазад"/> + <node name="currentSection" value="Только в Ñтом разделе"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="ПоиÑк в Ñети"/> + <node name="titleAndSeries" value="Ðазвание книги/СериÑ"/> + <node name="author" value="Ðвтор"/> + <node name="category" value="КатегориÑ"/> + <node name="description" value="ОпиÑание"/> + <node name="annotation" value="Результаты поиÑка длÑ: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Перейти на Ñтраницу"/> + <node name="pageNumber" value="Ðомер Ñтраницы"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Переименование категории"/> + <node name="name" value="Ðазвание"/> + <node name="includeSubtags" value="Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ð¾Ð´ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ð¸"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Клонирование категории"/> + <node name="name" value="Ðазвание"/> + <node name="includeSubtags" value="Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ð¾Ð´ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ð¸"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Удаление книги"/> + <node name="message" value="Удалить книгу «%s» из библиотеки?"/> + <node name="deleteFile" value="Ð’Ñ‹ дейÑтвительно хотите удалить Ñ Ð´Ð¸Ñка файл «%s»?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Удаление категории"/> + <node name="message" value="Удалить категорию «%s»?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Ошибка"/> + <node name="message" value="Ðе могу открыть: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Ошибка"/> + <node name="message" value="Ðе могу удалить файл %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Ошибка"/> + <node name="message" value="Извините, нет файла Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸ÐµÐ¹"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Ðе указаны библиотеки Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка"/> + <node name="authenticationFailed" value="Ошибка авторизации"/> + <node name="internalError" value="ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ° Ñервера"/> + <node name="purchaseNotEnoughMoney" value="Ðе доÑтаточно ÑредÑтв на Ñчету"/> + <node name="purchaseMissingBook" value="Книга отÑутÑтвует в продаже"/> + <node name="purchaseAlreadyPurchased" value="Книга уже была куплена"/> + <node name="bookNotPurchased" value="Книга не была куплена"/> + <node name="downloadLimitExceeded" value="ИÑчерпан лимит загрузок"/> + <node name="unsupportedOperation" value="ÐÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ"/> + <node name="loginAlreadyTaken" value="Ðто Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð·Ð°Ð½Ñто"/> + <node name="loginNotSpecified" value="Введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"/> + <node name="passwordNotSpecified" value="Введите пароль"/> + <node name="emailNotSpecified" value="Введите почтовый адреÑ"/> + <node name="invalidEMail" value="Ðекорректный почтовый адреÑ"/> + <node name="tooManyRegistrations" value="Слишком много региÑтраций Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ IP; попробуйте еще раз через пару минут"/> + <node name="noUserEmail" value="Ðет Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом"/> + <node name="librariesListDownloadingFailed" value="Ðе удалоÑÑŒ загрузить ÑпиÑок Ñетевых библиотек"/> + </node> + <node name="downloadError"> + <node name="title" value="Ошибка при загрузке"/> + <node name="message" value="Ðе удалоÑÑŒ загрузить книгу из Ñети"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Загрузка книги. Подождите, пожалуйÑта..."/> + <node name="loadingBookList" value="Загрузка ÑпиÑка книг. Подождите, пожалуйÑта..."/> + <node name="migrate" value="Переход на новую верÑию. Подождите, пожалуйÑта..."/> + <node name="downloadBookList" value="Загрузка ÑпиÑка книг. Подождите, пожалуйÑта..."/> + <node name="downloadBook" value="Загрузка книги. Подождите, пожалуйÑта..."/> + <node name="downloadImages" value="Загрузка изображений. Подождите, пожалуйÑта..."/> + <node name="authentication" value="Идет авторизациÑ. Подождите, пожалуйÑта..."/> + <node name="purchaseBook" value="Идет покупка книги. Подождите, пожалуйÑта..."/> + <node name="initializeAuthenticationManager" value="Загрузка пользовательÑкой информации. Подождите, пожалуйÑта..."/> + <node name="loadSubCatalog" value="Загрузка каталога. Подождите, пожалуйÑта..."/> + <node name="registerUser" value="РегиÑтрируем пользователÑ. Подождите, пожалуйÑта..."/> + <node name="passwordRecovery" value="ПроÑим воÑÑтановить пароль. Подождите, пожалуйÑта..."/> + <node name="authenticationCheck" value="Проверка учетной запиÑи. Подождите, пожалуйÑта..."/> + <node name="signOut" value="Выход из ÑиÑтемы. Подождите, пожалуйÑта..."/> + <node name="loadingNetworkLibraryList" value="Загрузка ÑпиÑка Ñетевых библиотек. Подождите, пожалуйÑта..."/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Покупка книги"/> + <node name="message" value="Ð’Ñ‹ уверены, что хотите приобреÑти книгу «%s»?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="ÐвторизациÑ"/> + <node name="login" value="Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"/> + <node name="password" value="Пароль"/> + <node name="skipIP" value="Ðе привÑзыватьÑÑ Ðº ip-адреÑу"/> + <node name="loginIsEmpty" value="Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ может быть пуÑтым"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="ИнформациÑ"/> + <node name="message" value="Каталог пуÑÑ‚."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Отключение каталога"/> + <node name="message" value="Ð’Ñ‹ уверены, что хотите отключить каталог «%s»? Ð’Ñ‹ Ñможете включить его обратно на вкладке «ПоиÑк в Ñети» в диалоге «ÐаÑтройки»."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Удалить книгу"/> + <node name="message" value="Ð’Ñ‹ уверены, что хотите удалить Ñ Ð´Ð¸Ñка книгу «%s»?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ пользователÑ"/> + <node name="login" value="Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"/> + <node name="password" value="Пароль"/> + <node name="confirmPassword" value="Еще раз пароль"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="Ð’Ñ‹ ввели 2 разных паролÑ."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="ВоÑÑтановление паролÑ"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="ВоÑÑтановление паролÑ"/> + <node name="message" value="ИнÑÑ‚Ñ€ÑƒÐºÑ†Ð¸Ñ Ð¿Ð¾ воÑÑтановлению выÑлана на Ð°Ð´Ñ€ÐµÑ %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Ошибка"/> + <node name="message" value="Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ загруженный файл %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="текÑта по умолчанию"/> + <node name="Regular Paragraph" value="обычного текÑта"/> + <node name="Title" value="заголовка"/> + <node name="Section Title" value="Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð³Ð»Ð°Ð²Ñ‹"/> + <node name="Poem Title" value="Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ ÑтихотворениÑ"/> + <node name="Subtitle" value="подзаголовка"/> + <node name="Annotation" value="аннотации"/> + <node name="Epigraph" value="Ñпиграфа"/> + <node name="Stanza" value="Ñтрофы"/> + <node name="Verse" value="Ñтихов"/> + <node name="Preformatted text" value="текÑта внутри <pre>"/> + <node name="Image" value="риÑунка"/> + <node name="Cite" value="цитаты"/> + <node name="Author" value="имени автора"/> + <node name="Date" value="даты"/> + <node name="Internal Hyperlink" value="ÑÑылки"/> + <node name="Footnote" value="ÑноÑки"/> + <node name="Emphasis" value="Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ (emphasis)"/> + <node name="Strong" value="Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ (strong)"/> + <node name="Subscript" value="нижнего индекÑа"/> + <node name="Superscript" value="верхнего индекÑа"/> + <node name="Code" value="текÑта программы"/> + <node name="StrikeThrough" value="зачеркнутого текÑта"/> + <node name="Contents Table" value="оглавлениÑ"/> + <node name="Library Entry" value="библиотеки"/> + <node name="Recent Book List" value="ÑпиÑка книг"/> + <node name="Italic" value="курÑива"/> + <node name="Bold" value="жирного текÑта"/> + <node name="Definition" value="определениÑ"/> + <node name="Definition Description" value="текÑта определениÑ"/> + <node name="Header 1" value="текÑта внутри <h1>"/> + <node name="Header 2" value="текÑта внутри <h2>"/> + <node name="Header 3" value="текÑта внутри <h3>"/> + <node name="Header 4" value="текÑта внутри <h4>"/> + <node name="Header 5" value="текÑта внутри <h5>"/> + <node name="Header 6" value="текÑта внутри <h6>"/> + <node name="External Hyperlink" value="внешней ÑÑылки"/> + <node name="Link to Another Book" value="ÑÑылки на книгу"/> + </node> + <node name="external"> + <node name="browser" value="браузере"/> + <node name="defaultBrowser" value="браузере"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°"/> + <node name="unsupportedCompressionMethod" value="неподдерживаемый метод ÑжатиÑ"/> + <node name="encryptedFile" value="файл защищен DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="ПоиÑк в Ñетевых библиотеках"/> + </node> + <node name="library"> + <node name="caption" value="Библиотека"/> + </node> +</resources> diff --git a/reader/data/resources/sv.xml b/reader/data/resources/sv.xml new file mode 100644 index 0000000..59ad7bf --- /dev/null +++ b/reader/data/resources/sv.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Swedish TDE-Ebook-Reader resources, by Daniel Nylander --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + <node name="edit" toBeTranslated="true" value="Edit information"/> + <node name="unknownAuthor" toBeTranslated="true" value="Unknown Author"/> + </node> + <node name="tagNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + <node name="edit" toBeTranslated="true" value="Edit tag"/> + <node name="clone" toBeTranslated="true" value="Clone tag"/> + <node name="delete" toBeTranslated="true" value="Remove tag"/> + <node name="noTags" toBeTranslated="true" value="Books with no tags"/> + </node> + <node name="seriesNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="bookNode"> + <node name="read" toBeTranslated="true" value="Read book"/> + <node name="edit" toBeTranslated="true" value="Edit information"/> + <node name="delete" toBeTranslated="true" value="Remove book"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="By author" toBeTranslated="true"> + <node name="summary" value="Books sorted by author" toBeTranslated="true"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" toBeTranslated="true" value="Expand"/> + <node name="collapseTree" toBeTranslated="true" value="Collapse"/> + <node name="reload" toBeTranslated="true" value="Reload"/> + <node name="openInBrowser" toBeTranslated="true" value="Open in browser"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" toBeTranslated="true" value="Open catalog"/> + <node name="collapseTree" toBeTranslated="true" value="Close catalog"/> + <node name="login" toBeTranslated="true" value="Sign in"/> + <node name="logout" toBeTranslated="true" value="Sign out (%s)"/> + <node name="reload" toBeTranslated="true" value="Reload"/> + <node name="dontShow" toBeTranslated="true" value="Don't show this catalog"/> + <node name="topupAccount" toBeTranslated="true" value="Top up account (currently: %s)"/> + <node name="register" toBeTranslated="true" value="Sign up"/> + <node name="passwordRecovery" toBeTranslated="true" value="Recover password"/> + </node> + <node name="searchResultNode"> + <node name="title" toBeTranslated="true" value="Search results"/> + <node name="expandTree" toBeTranslated="true" value="Show results"/> + <node name="collapseTree" toBeTranslated="true" value="Hide results"/> + </node> + <node name="authorNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="seriesNode"> + <node name="expandTree" toBeTranslated="true" value="Show books"/> + <node name="collapseTree" toBeTranslated="true" value="Hide books"/> + </node> + <node name="bookNode"> + <node name="read" toBeTranslated="true" value="Read local copy"/> + <node name="delete" toBeTranslated="true" value="Delete local copy"/> + <node name="download" toBeTranslated="true" value="Download"/> + <node name="readDemo" toBeTranslated="true" value="Read sample"/> + <node name="downloadDemo" toBeTranslated="true" value="Download sample"/> + <node name="demo" toBeTranslated="true" value="demo"/> + <node name="buy" toBeTranslated="true" value="Buy (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Bokinformation..."/> + <node name="toc" value="InnehÃ¥llsförteckning"/> + <node name="showLibrary" toBeTranslated="true" value="Open library"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Bibliotek"> + <node name="showLibrary" value="Öppna"/> + <node name="previousBook" value="FöregÃ¥ende bok"/> + <node name="showRecent" value="Tidigare"/> + <node name="addBook" value="Lägg till bok..."/> + <node name="showHelp" value="Om TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="GÃ¥ till början av dokumentet"/> + <node name="gotoPageNumber" toBeTranslated="true" value="Go to Page..."/> + <node name="gotoSectionStart" value="GÃ¥ till början av textavsnitt"/> + <node name="gotoSectionEnd" value="GÃ¥ till slutet av textavsnitt"/> + <node name="nextTOCSection" value="GÃ¥ till nästa post i innehÃ¥llsförteckning"/> + <node name="previousTOCSection" value="GÃ¥ till föregÃ¥ende post i innehÃ¥llsförteckning"/> + <node name="navigate" value="Navigation"> + <node name="gotoHome" value="GÃ¥ till början av dokumentet"/> + <node name="gotoPageNumber" toBeTranslated="true" value="Go to Page..."/> + <node name="gotoSectionStart" value="GÃ¥ till början av textavsnitt"/> + <node name="gotoSectionEnd" value="GÃ¥ till slutet av textavsnitt"/> + <node name="nextTOCSection" value="GÃ¥ till nästa post i innehÃ¥llsförteckning"/> + <node name="previousTOCSection" value="GÃ¥ till föregÃ¥ende post i innehÃ¥llsförteckning"/> + <node name="undo" value="GÃ¥ bakÃ¥t"/> + <node name="redo" value="GÃ¥ framÃ¥t"/> + </node> + <node name="selection" value="Markering"> + <node name="copyToClipboard" value="Kopiera till urklipp"/> + <node name="openInDictionary" value="Öppna i ordbok"/> + <node name="clearSelection" value="Töm"/> + </node> + <node name="search" value="Sök"> + <node name="search" value="Sök text..."/> + <node name="findNext" value="Sök nästa"/> + <node name="findPrevious" value="Sök föregÃ¥ende"/> + </node> + <node name="view" value="Visa"> + <node name="rotate" value="Rotera skärm"/> + <node name="toggleFullscreen" value="Helskärm"/> + <node name="toggleIndicator" value="Växla indikator"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Stäng"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" toBeTranslated="true" value="Read Book"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Mode"/> + </node> + <node name="showLibrary"> + <node name="label" toBeTranslated="true" value="Library"/> + <node name="tooltip" value="Visa biblioteksträd"/> + <node name="popup" toBeTranslated="true" value="Show Recent Books List"/> + </node> + <node name="showRecent"> + <node name="label" toBeTranslated="true" value="Recent Books"/> + <node name="tooltip" value="Visa tidigare bokhistorik"/> + </node> + <node name="byAuthor"> + <node name="label" toBeTranslated="true" value="By Author"/> + <node name="tooltip" toBeTranslated="true" value="Organize Books by Author"/> + </node> + <node name="byTag"> + <node name="label" toBeTranslated="true" value="By Tag"/> + <node name="tooltip" toBeTranslated="true" value="Organize Books by Tag"/> + </node> + <node name="addBook"> + <node name="label" toBeTranslated="true" value="Add File"/> + <node name="tooltip" value="Lägg till fil till bibliotek"/> + </node> + <node name="showNetLibrary"> + <node name="label" toBeTranslated="true" value="Network"/> + <node name="tooltip" toBeTranslated="true" value="Search in Network Libraries"/> + </node> + <node name="searchOnNetwork"> + <node name="label" toBeTranslated="true" value="Simple Search"/> + <node name="tooltip" toBeTranslated="true" value="Network Search"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" toBeTranslated="true" value="Advanced Network Search"/> + </node> + <node name="gotoHome"> + <node name="label" toBeTranslated="true" value="Go to Start"/> + <node name="tooltip" value="GÃ¥ till början av text"/> + </node> + <node name="undo"> + <node name="label" toBeTranslated="true" value="Go Back"/> + <node name="tooltip" value="GÃ¥ bakÃ¥t"/> + </node> + <node name="redo"> + <node name="label" toBeTranslated="true" value="Go Forward"/> + <node name="tooltip" value="GÃ¥ framÃ¥t"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" toBeTranslated="true" value="Go to Page"/> + <node name="tooltip" toBeTranslated="true" value="Go to Page"/> + </node> + <node name="toc"> + <node name="label" toBeTranslated="true" value="TOC"/> + <node name="tooltip" value="InnehÃ¥llsförteckning"/> + </node> + <node name="search"> + <node name="label" toBeTranslated="true" value="Search"/> + <node name="tooltip" value="Textsökning"/> + </node> + <node name="findNext"> + <node name="label" toBeTranslated="true" value="Next"/> + <node name="tooltip" value="Sök nästa"/> + </node> + <node name="findPrevious"> + <node name="label" toBeTranslated="true" value="Previous"/> + <node name="tooltip" value="Sök föregÃ¥ende"/> + </node> + <node name="rotate"> + <node name="label" toBeTranslated="true" value="Rotate"/> + <node name="tooltip" value="Rotera text"/> + </node> + <node name="showHelp"> + <node name="label" toBeTranslated="true" value="About"/> + <node name="tooltip" value="Om TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" toBeTranslated="true" value="Book Info"/> + <node name="tooltip" value="Visa bokinformation"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&GÃ¥!"/> + <node name="thisOnly" toBeTranslated="true" value="This only"/> + <node name="withSubtags" toBeTranslated="true" value="With subtags"/> + <node name="removeLink" toBeTranslated="true" value="Remove from library"/> + <node name="removeFile" toBeTranslated="true" value="Remove from disk"/> + <node name="yesToAll" toBeTranslated="true" value="Yes to &all"/> + <node name="buy" toBeTranslated="true" value="&Buy"/> + <node name="buyAndDownload" toBeTranslated="true" value="Buy and &download"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Bibliotek"> + <node name="bookPath" value="Boksökväg"/> + <node name="lookInSubdirectories" value="Leta efter böcker i underkataloger"/> + <node name="collectBooksWithoutMetaInfo" toBeTranslated="true" value="Collect Books without MetaInfo"/> + <node name="downloadDirectory" toBeTranslated="true" value="Directory for Downloaded Books"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" toBeTranslated="true" value="Network Search"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" toBeTranslated="true" value="Use Proxy"/> + <node name="proxyHost" toBeTranslated="true" value="Proxy Host"/> + <node name="proxyPort" toBeTranslated="true" value="Proxy Port"/> + <node name="timeout" toBeTranslated="true" value="Network Operations Timeout, seconds"/> + </node> + <node name="Web" value="Webb"> + <node name="enableIntegration" value="Öppna externa länkar med %s"/> + <node name="defaultText" value="Öppna externa länkar i webbläsare"/> + <node name="choice" value="Använd webbläsare"/> + <node name="command" value="Kommando att köra"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="SprÃ¥k"> + <node name="autoDetect" value="Upptäck automatiskt sprÃ¥k och kodning"/> + <node name="defaultLanguage" value="StandardsprÃ¥k"/> + <node name="defaultEncodingSet" value="Standardteckenuppsättning"/> + <node name="defaultEncoding" value="Standardkodning"/> + <node name="useWindows1252Hack" value="Använd windows-1252 istället för iso-8859-1"/> + </node> + <node name="Config" value="Konfiguration"> + <node name="autoSave" value="Spara tillstÃ¥nd automatiskt"/> + <node name="timeout" value="Tidsgräns mellan sparningar, sekunder"/> + </node> + <node name="Dictionary" value="Ordbok"> + <node name="enableIntegration" value="Aktivera integration med %s"/> + <node name="defaultText" value="Aktivera integration med ordbok"/> + <node name="choice" value="Integrera med"/> + <node name="singleClickOpen" value="Öppna med ett klick"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Ã…tgärd vid tangentsläpp, inte tangenttryck"/> + <node name="minStylusPressure" value="Minimalt pentryck"/> + <node name="maxStylusPressure" value="Maximalt pentryck"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Rullning"> + <node name="keyScrollDelay" toBeTranslated="true" value="Delay between Key Scrollings, msecs"/> + <node name="keyLinesToScroll" toBeTranslated="true" value="Lines to Scroll per Line Scrolling"/> + <node name="keyLinesToKeep" toBeTranslated="true" value="Lines to Keep per Page Scrolling"/> + <node name="enableTapScrolling" toBeTranslated="true" value="Enable Tap Scrolling"/> + <node name="fingerOnly" toBeTranslated="true" value="Scroll on Finger Tap Only"/> + </node> + <node name="Selection" value="Markering"> + <node name="enableSelection" value="Aktivera textmarkering"/> + </node> + <node name="Indicator" value="Indikator"> + <node name="type" toBeTranslated="true" value="Show as"> + <node name="osScrollbar" toBeTranslated="true" value="OS Scrollbar"/> + <node name="fbIndicator" toBeTranslated="true" value="Old Style Indicator"/> + <node name="none" toBeTranslated="true" value="Don't Show"/> + </node> + <node name="height" value="Indikatorns höjd"/> + <node name="offset" value="Offset frÃ¥n text"/> + <node name="pageNumber" value="Visa position som siffror"/> + <node name="time" value="Visa tid"/> + <node name="fontSize" value="Typsnittsstorlek"/> + <node name="tocMarks" value="Visa förteckningsmarkeringar"/> + <node name="navigation" value="Aktivera navigering"/> + </node> + <node name="Rotation" value="Rotering"> + <node name="direction" value="Roteringstyp"> + <node name="disabled" value="Inaktiverad"/> + <node name="clockwise" value="90 grader medsols"/> + <node name="counterclockwise" value="90 grader motsols"/> + <node name="180" value="180 grader"/> + <node name="cycle" value="Växla genom alla fyra riktningar"/> + </node> + </node> + <node name="Keys" value="Tangenter"> + <node name="grabSystemKeys" value="FÃ¥nga systemtangenter"/> + <node name="separate" value="Tangentbindningar beroende av orientering"/> + <node name="orientation" value="Orientering"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Ingen"/> + <node name="showLibrary" value="Visa bibliotek"/> + <node name="showNetLibrary" toBeTranslated="true" value="Show network library"/> + <node name="showRecent" value="Visa tidigare böcker"/> + <node name="previousBook" value="Öppna föregÃ¥ende bok"/> + <node name="toc" value="Visa innehÃ¥llsförteckning"/> + <node name="gotoHome" value="GÃ¥ hem"/> + <node name="gotoSectionStart" value="GÃ¥ till början av avsnitt"/> + <node name="gotoSectionEnd" value="GÃ¥ till slutet av avsnitt"/> + <node name="nextTOCSection" value="GÃ¥ till nästa avsnitt i förteckning"/> + <node name="previousTOCSection" value="GÃ¥ till föregÃ¥ende avsnitt i förteckning"/> + <node name="pageForward" toBeTranslated="true" value="Scroll page forward"/> + <node name="pageBackward" toBeTranslated="true" value="Scroll page backward"/> + <node name="lineForward" toBeTranslated="true" value="Scroll line forward"/> + <node name="lineBackward" toBeTranslated="true" value="Scroll line backward"/> + <node name="undo" value="Ã…ngra"/> + <node name="redo" value="Gör om"/> + <node name="copyToClipboard" value="Kopiera markerad text till urklipp"/> + <node name="openInDictionary" value="Öppna markerad text i ordbok"/> + <node name="clearSelection" value="Töm markering"/> + <node name="search" value="Sök"/> + <node name="findPrevious" value="Sök föregÃ¥ende"/> + <node name="findNext" value="Sök nästa"/> + <node name="increaseFont" value="Öka typsnittsstorlek"/> + <node name="decreaseFont" value="Minska typsnittsstorlek"/> + <node name="toggleIndicator" value="Växla positionsindikator"/> + <node name="toggleFullscreen" value="Växla helskärmsläge"/> + <node name="rotate" value="Rotera skärm"/> + <node name="addBook" value="Lägg till bok"/> + <node name="cancel" value="Avbryt"/> + <node name="quit" value="Avsluta"/> + <node name="bookInfo" value="Visa bokinformation"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Avsluta programmet vid avbryt"/> + <node name="keyDelay" toBeTranslated="true" value="Delay Between Accepted Key Pressings"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" toBeTranslated="true" value="CSS"> + <node name="overrideSpecifiedFonts" toBeTranslated="true" value="Always Use My Own Fonts"/> + </node> + <node name="Margins" value="Marginaler"> + <node name="left" value="Vänstermarginal"/> + <node name="right" value="Högermarginal"/> + <node name="top" value="Övermarginal"/> + <node name="bottom" value="Nedermarginal"/> + </node> + <node name="Format" value="Formatering"> + <node name="optionsFor" value="Alternativ för"/> + <node name="lineSpacing" value="Radmellanrum"> + <node name="unchanged" value="<oförändrad>"/> + </node> + <node name="firstLineIndent" value="Indentera första raden"/> + <node name="alignment" value="Justering"> + <node name="left" value="Vänster"/> + <node name="right" value="Höger"/> + <node name="center" value="Centrera"/> + <node name="justify" value="Justera"/> + <node name="unchanged" value="<oförändrad>"/> + </node> + <node name="spaceBefore" value="Blanksteg före"/> + <node name="spaceAfter" value="Blanksteg efter"/> + <node name="startIndent" toBeTranslated="true" value="Line Start Indent"/> + <node name="endIndent" toBeTranslated="true" value="Line End Indent"/> + </node> + <node name="Styles" value="Stilar"> + <node name="optionsFor" value="Alternativ för"/> + <node name="fontFamily" value="Familj"> + <node name="unchanged" value="<oförändrad>"/> + </node> + <node name="fontSize" value="Storlek"/> + <node name="fontSizeDifference" value="Storleksskillnad"/> + <node name="bold" value="Fet"/> + <node name="italic" value="Kursiv"/> + <node name="allowHyphenations" value="TillÃ¥t avstavningar"/> + <node name="autoHyphenations" value="Automatiska avstavningar"/> + </node> + <node name="Colors" value="Färger"> + <node name="colorFor" value="Färg för"> + <node name="background" value="Bakgrund"/> + <node name="selectionBackground" value="Markeringsbakgrund"/> + <node name="text" value="Vanlig text"/> + <node name="internalLink" value="Text för intern hyperlänk"/> + <node name="externalLink" value="Text för extern hyperlänk"/> + <node name="bookLink" toBeTranslated="true" value="Link to Another Book"/> + <node name="highlighted" value="Färgmarkerad text"/> + <node name="treeLines" value="Trädrader"/> + <node name="indicator" value="Positionsindikator"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Bokinformation"/> + <node name="tab"> + <node name="Common" value="Allmänt"> + <node name="file" value="Fil"/> + <node name="title" value="Titel"/> + <node name="language" value="SprÃ¥k"/> + <node name="encodingSet" value="Teckenuppsättning"/> + <node name="encoding" value="Kodning"/> + </node> + <node name="Authors" toBeTranslated="true" value="Authors"> + <node name="authorDisplayName" toBeTranslated="true" value="Author Name"/> + </node> + <node name="Series" value="Serier"> + <node name="seriesTitle" value="Serietitel"/> + <node name="bookIndex" value="Boknummer"/> + </node> + <node name="Tags" toBeTranslated="true" value="Tags"> + <node name="tags" toBeTranslated="true" value="Tag Name"/> + </node> + <node name="Text" value="Text"> + <node name="breakType" value="Bryt stycke vid"/> + <node name="ignoreIndent" value="Ignorera indentering mindre än"/> + <node name="buildTOC" value="Bygg innehÃ¥llsförteckning"/> + <node name="emptyLines" value="Tomma rader innan nytt avsnitt"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Bryt stycke vid"/> + <node name="ignoreIndent" value="Ignorera indentering mindre än"/> + <node name="buildTOC" value="Bygg innehÃ¥llsförteckning"/> + <node name="emptyLines" value="Tomma rader innan nytt avsnitt"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Author Info"/> + <node name="name" toBeTranslated="true" value="Author Name"/> + <node name="sortKey" toBeTranslated="true" value="Author Sort Key"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Lägg till bok till biblioteket"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Textsökning"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Ignorera skiftläge"/> + <node name="wholeText" value="I h&ela texten"/> + <node name="backward" value="&BakÃ¥t"/> + <node name="currentSection" value="Endast i &detta avsnitt"/> + </node> + <node name="networkSearchDialog"> + <node name="title" toBeTranslated="true" value="Network Search"/> + <node name="titleAndSeries" toBeTranslated="true" value="Title/Series"/> + <node name="author" toBeTranslated="true" value="Author"/> + <node name="category" toBeTranslated="true" value="Category"/> + <node name="description" toBeTranslated="true" value="Description"/> + <node name="annotation" toBeTranslated="true" value="Search results for: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" toBeTranslated="true" value="Go To Page"/> + <node name="pageNumber" toBeTranslated="true" value="Go to Page Number"/> + </node> + <node name="editTagDialog"> + <node name="title" toBeTranslated="true" value="Edit Tag"/> + <node name="name" toBeTranslated="true" value="Tag Name"/> + <node name="includeSubtags" toBeTranslated="true" value="Include Subtags"/> + </node> + <node name="cloneTagDialog"> + <node name="title" toBeTranslated="true" value="Clone Tag"/> + <node name="name" toBeTranslated="true" value="Tag Name"/> + <node name="includeSubtags" toBeTranslated="true" value="Include Subtags"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Ta bort bok"/> + <node name="message" value="Ta bort boken "%s" frÃ¥n biblioteket?"/> + <node name="deleteFile" toBeTranslated="true" value="Are you sure you want to remove file “%s†from the disk?"/> + </node> + <node name="removeTagBox"> + <node name="title" toBeTranslated="true" value="Remove Tag"/> + <node name="message" toBeTranslated="true" value="Remove Tag “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Fel"/> + <node name="message" value="Kunde inte öppna: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" toBeTranslated="true" value="Error"/> + <node name="message" toBeTranslated="true" value="Couldn't remove file %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Fel"/> + <node name="message" value="Tyvärr, hjälpfilen hittades inte"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" toBeTranslated="true" value="Empty libraries list"/> + <node name="authenticationFailed" toBeTranslated="true" value="Authentication failed"/> + <node name="internalError" toBeTranslated="true" value="Internal server error"/> + <node name="purchaseNotEnoughMoney" toBeTranslated="true" value="Not enough money"/> + <node name="purchaseMissingBook" toBeTranslated="true" value="Missing book"/> + <node name="purchaseAlreadyPurchased" toBeTranslated="true" value="Already purchased"/> + <node name="bookNotPurchased" toBeTranslated="true" value="Book was not purchased"/> + <node name="downloadLimitExceeded" toBeTranslated="true" value="Download limit exceeded"/> + <node name="unsupportedOperation" toBeTranslated="true" value="Unsupported operation"/> + <node name="loginAlreadyTaken" toBeTranslated="true" value="Username is already in use"/> + <node name="loginNotSpecified" toBeTranslated="true" value="Please, enter a username"/> + <node name="passwordNotSpecified" toBeTranslated="true" value="Please, enter a non-empty password"/> + <node name="emailNotSpecified" toBeTranslated="true" value="Please, enter an e-mail address"/> + <node name="invalidEMail" toBeTranslated="true" value="Invalid e-mail address"/> + <node name="tooManyRegistrations" toBeTranslated="true" value="Too many registrations from your IP; try again in a few minutes"/> + <node name="noUserEmail" toBeTranslated="true" value="No user was registered with specified e-mail address"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" toBeTranslated="true" value="Error while downloading"/> + <node name="message" toBeTranslated="true" value="Can't download this book at the moment"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Läser in bok. Var god vänta..."/> + <node name="loadingBookList" value="Läser in boklista. Var god vänta..."/> + <node name="migrate" toBeTranslated="true" value="Upgrading to the new version. Please, wait..."/> + <node name="downloadBookList" toBeTranslated="true" value="Downloading book list. Please, wait..."/> + <node name="downloadBook" toBeTranslated="true" value="Downloading book. Please, wait..."/> + <node name="downloadImages" toBeTranslated="true" value="Downloading images. Please, wait..."/> + <node name="authentication" toBeTranslated="true" value="Authentication. Please, wait..."/> + <node name="purchaseBook" toBeTranslated="true" value="Purchase book. Please, wait..."/> + <node name="initializeAuthenticationManager" toBeTranslated="true" value="Downloading account information. Please, wait..."/> + <node name="loadSubCatalog" toBeTranslated="true" value="Loading catalog. Please, wait..."/> + <node name="registerUser" toBeTranslated="true" value="Registering new account. Please, wait..."/> + <node name="passwordRecovery" toBeTranslated="true" value="Recovering password. Please, wait..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" toBeTranslated="true" value="Purchase book"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to buy “%s†book?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" toBeTranslated="true" value="Authentication"/> + <node name="login" toBeTranslated="true" value="Username"/> + <node name="password" toBeTranslated="true" value="Password"/> + <node name="skipIP" toBeTranslated="true" value="Don't bound to ip-address"/> + <node name="loginIsEmpty" toBeTranslated="true" value="Username should be non-empty"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" toBeTranslated="true" value="Information"/> + <node name="message" toBeTranslated="true" value="Catalog is empty."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" toBeTranslated="true" value="Disable catalog"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to disable “%s†catalog? You can enable it in the future at “Network Search†tab in the Options dialog."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" toBeTranslated="true" value="Delete Book"/> + <node name="message" toBeTranslated="true" value="Are you sure you want to remove “%s†book from the disk?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" toBeTranslated="true" value="Register User"/> + <node name="login" toBeTranslated="true" value="Username"/> + <node name="password" toBeTranslated="true" value="Password"/> + <node name="confirmPassword" toBeTranslated="true" value="Password confirmation"/> + <node name="email" toBeTranslated="true" value="E-mail"/> + <node name="differentPasswords" toBeTranslated="true" value="Password and password confirmation must be the same."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" toBeTranslated="true" value="Password Recovery"/> + <node name="email" toBeTranslated="true" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" toBeTranslated="true" value="Password Recovery"/> + <node name="message" toBeTranslated="true" value="A message with further instructions has been sent to %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" toBeTranslated="true" value="Download Error"/> + <node name="message" toBeTranslated="true" value="Can't open downloaded file %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="Bas"/> + <node name="Regular Paragraph" value="Vanligt stycke"/> + <node name="Title" value="Titel"/> + <node name="Section Title" value="Avsnittstitel"/> + <node name="Poem Title" value="Poem Title"/> + <node name="Subtitle" value="Undertext"/> + <node name="Annotation" value="Notation"/> + <node name="Epigraph" value="Epigram"/> + <node name="Stanza" value="Strof"/> + <node name="Verse" value="Vers"/> + <node name="Preformatted text" value="Förformaterad text"/> + <node name="Image" value="Bild"/> + <node name="Cite" value="Citat"/> + <node name="Author" value="Författare"/> + <node name="Date" value="Datum"/> + <node name="Internal Hyperlink" value="Intern hyperlänk"/> + <node name="Footnote" value="Fotnot"/> + <node name="Emphasis" value="Betoning"/> + <node name="Strong" value="Stark"/> + <node name="Subscript" value="Nedsänkt"/> + <node name="Superscript" value="Upphöjt"/> + <node name="Code" value="Kod"/> + <node name="StrikeThrough" value="Genomstruket"/> + <node name="Contents Table" value="InnehÃ¥llstabell"/> + <node name="Library Entry" toBeTranslated="true" value="Library Entry"/> + <node name="Recent Book List" value="Lista över tidigare böcker"/> + <node name="Italic" value="Kursiv"/> + <node name="Bold" value="Fet"/> + <node name="Definition" value="Definition"/> + <node name="Definition Description" value="Definitionsbeskrivning"/> + <node name="Header 1" value="Rubrik 1"/> + <node name="Header 2" value="Rubrik 2"/> + <node name="Header 3" value="Rubrik 3"/> + <node name="Header 4" value="Rubrik 4"/> + <node name="Header 5" value="Rubrik 5"/> + <node name="Header 6" value="Rubrik 6"/> + <node name="External Hyperlink" value="Extern hyperlänk"/> + <node name="Link to Another Book" toBeTranslated="true" value="Link to Another Book"/> + </node> + <node name="external"> + <node name="browser" value="Webbläsare"/> + <node name="defaultBrowser" value="Standardwebbläsare"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Okänt fel"/> + <node name="unsupportedCompressionMethod" value="Komprimeringsmetoden stöds inte"/> + <node name="encryptedFile" value="DRM-skyddad fil"/> + </node> + <node name="networkLibrary"> + <node name="caption" toBeTranslated="true" value="Network Library"/> + </node> + <node name="library"> + <node name="caption" value="Bibliotek"/> + </node> +</resources> diff --git a/reader/data/resources/uk.xml b/reader/data/resources/uk.xml new file mode 100644 index 0000000..019ca78 --- /dev/null +++ b/reader/data/resources/uk.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Ukrainian TDE-Ebook-Reader resources, by Valentina Kanevska --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Показати книги"/> + <node name="collapseTree" value="Скрити книги"/> + <node name="edit" value="Редагувати інформацію"/> + <node name="unknownAuthor" value="Ðевідомий автор"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Показати книги"/> + <node name="collapseTree" value="Скрити книги"/> + <node name="edit" value="Редагувати тег"/> + <node name="clone" value="Клонувати тег"/> + <node name="delete" value="Видалити тег"/> + <node name="noTags" value="Книги без тегів"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показати книги"/> + <node name="collapseTree" value="Скрити книги"/> + </node> + <node name="bookNode"> + <node name="read" value="Читати книгу"/> + <node name="edit" value="Редагувати інформацію"/> + <node name="delete" value="Вилучити книгу"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="За автором"> + <node name="summary" value="Книги відÑортовані за автором"/> + </node> + <node name="byTitle" value="За назвою"> + <node name="summary" value="Книги відÑортовані за назвою"/> + </node> + <node name="byDate" value="За датою"> + <node name="summary" value="Книги відÑортовані за датою придбаннÑ"/> + </node> + <node name="bySeries" value="За Ñерією"> + <node name="summary" value="Книги відÑортовані за Ñерією"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Розгорнути"/> + <node name="collapseTree" value="Сгорнути"/> + <node name="reload" value="Відновити"/> + <node name="openInBrowser" value="Відкрити в браузері"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Відкрити каталог"/> + <node name="collapseTree" value="Закрити каталог"/> + <node name="login" value="Увійти"/> + <node name="logout" value="Вийти (%s)"/> + <node name="reload" value="Відновити"/> + <node name="dontShow" value="Ðе показувати каталог"/> + <node name="topupAccount" value="Поповнити рахунок (currently: %s)"/> + <node name="register" value="Увійти"/> + <node name="passwordRecovery" value="Recover password"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Результати пошуку"/> + <node name="expandTree" value="Показати результати пошуку"/> + <node name="collapseTree" value="Скрити результати пошуку"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Show books"/> + <node name="collapseTree" value="Скрити книги"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Показати книги"/> + <node name="collapseTree" value="Скрити книги"/> + </node> + <node name="bookNode"> + <node name="read" value="Читати локальну копію"/> + <node name="delete" value="Видалити локальну копію"/> + <node name="download" value="Завантажити"/> + <node name="readDemo" value="Читати фрагмент"/> + <node name="downloadDemo" value="Завантажити фрагмент"/> + <node name="demo" value="фрагмент"/> + <node name="buy" value="Buy (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ книгу..."/> + <node name="toc" value="ЗміÑÑ‚"/> + <node name="showLibrary" value="Відкрити бібліотеку"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Бібліотека"> + <node name="showLibrary" value="Відкрити бібліотеку"/> + <node name="previousBook" value="ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ ÐºÐ½Ð¸Ð³Ð°"/> + <node name="showRecent" value="Прочитані книги"/> + <node name="addBook" value="Додати файл..."/> + <node name="showHelp" value="Про програму TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="Ðа початок книги"/> + <node name="gotoPageNumber" value="До Ñторінки..."/> + <node name="gotoSectionStart" value="Ðа початок розділу"/> + <node name="gotoSectionEnd" value="Ð’ кінець розділу"/> + <node name="nextTOCSection" value="До наÑтупної глави"/> + <node name="previousTOCSection" value="До попередньої глави"/> + <node name="navigate" value="ÐавігаціÑ"> + <node name="gotoHome" value="Ðа початок книги"/> + <node name="gotoPageNumber" value="До Ñторінки ..."/> + <node name="gotoSectionStart" value="Ðа початок розділу"/> + <node name="gotoSectionEnd" value="Ð’ кінець розділу"/> + <node name="nextTOCSection" value="До наÑтупної глави"/> + <node name="previousTOCSection" value="До попередньої глави"/> + <node name="undo" value="Ðазад"/> + <node name="redo" value="Вперед"/> + </node> + <node name="selection" value="Помітка"> + <node name="copyToClipboard" value="Скопіювати до буфера"/> + <node name="openInDictionary" value="ДивитиÑÑ Ñƒ Ñловнику"/> + <node name="clearSelection" value="ЗнÑти помітку"/> + </node> + <node name="search" value="Пошук"> + <node name="search" value="Шукати..."/> + <node name="findNext" value="Шукати далі"/> + <node name="findPrevious" value="Шукати раніше"/> + </node> + <node name="view" value="ЗображеннÑ"> + <node name="rotate" value="Повернути"/> + <node name="toggleFullscreen" value="Ðа веÑÑŒ екран"/> + <node name="toggleIndicator" value="Індикатор позиції"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Закрити"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Читати книгу"/> + <node name="tooltip" value="ПовернутиÑÑ Ð´Ð¾ читаннÑ"/> + </node> + <node name="showLibrary"> + <node name="label" value="Бібліотека"/> + <node name="tooltip" value="Бібліотека"/> + <node name="popup" value="Прочитані книги"/> + </node> + <node name="showRecent"> + <node name="label" value="Прочитані книги"/> + <node name="tooltip" value="Прочитані книги"/> + </node> + <node name="byAuthor"> + <node name="label" value="За авторами"/> + <node name="tooltip" value="За авторами"/> + </node> + <node name="byTag"> + <node name="label" value="За тегами"/> + <node name="tooltip" value="За тегами"/> + </node> + <node name="addBook"> + <node name="label" value="Додати файл"/> + <node name="tooltip" value="Додати файл до бібліотеки"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Мережа"/> + <node name="tooltip" value="Шукати у електронних бібліотеках"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Пошук"/> + <node name="tooltip" value="Шукати у мережі"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Розширений пошук"/> + <node name="tooltip" value="Розширений пошук у мережі"/> + </node> + <node name="gotoHome"> + <node name="label" value="Ðа початок"/> + <node name="tooltip" value="Ðа початок книги"/> + </node> + <node name="undo"> + <node name="label" value="Ðазад"/> + <node name="tooltip" value="Ðазад"/> + </node> + <node name="redo"> + <node name="label" value="Вперед"/> + <node name="tooltip" value="Вперед"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="До Ñторінки"/> + <node name="tooltip" value="До Ñторінки"/> + </node> + <node name="toc"> + <node name="label" value="ЗміÑÑ‚"/> + <node name="tooltip" value="ЗміÑÑ‚"/> + </node> + <node name="search"> + <node name="label" value="Пошук"/> + <node name="tooltip" value="Пошук"/> + </node> + <node name="findNext"> + <node name="label" value="ÐаÑтупний"/> + <node name="tooltip" value="Знайти наÑтупний"/> + </node> + <node name="findPrevious"> + <node name="label" value="Попередній"/> + <node name="tooltip" value="Знайти попередній"/> + </node> + <node name="rotate"> + <node name="label" value="Повернути"/> + <node name="tooltip" value="Повернути текÑÑ‚"/> + </node> + <node name="showHelp"> + <node name="label" value="Про програму"/> + <node name="tooltip" value="Про програму"/> + </node> + <node name="filterLibrary"> + <node name="label" toBeTranslated="true" value="Filter"/> + <node name="tooltip" toBeTranslated="true" value="Filter"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Про книгу"/> + <node name="tooltip" value="ІнформацiÑ Ð¿Ñ€Ð¾ книгу"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Шукати"/> + <node name="thisOnly" value="Тільки цю"/> + <node name="withSubtags" value="З підтегами"/> + <node name="removeLink" value="Видалити з бібліотеки"/> + <node name="removeFile" value="Видалити з диÑка"/> + <node name="yesToAll" value="Так Ð´Ð»Ñ &all"/> + <node name="buy" value="&Купити"/> + <node name="buyAndDownload" value="Купити та &завантажити"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Бібліотека"> + <node name="bookPath" value="Каталоги з книгами"/> + <node name="lookInSubdirectories" value="Шукати книги в підтеках"/> + <node name="collectBooksWithoutMetaInfo" value="Показати книжки без метаінформації"/> + <node name="downloadDirectory" value="Каталог Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ¶Ð°ÐµÐ¼Ñ‹Ñ… книг"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Пошук у мережі"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="ВикориÑтовувати прокÑÑ–-Ñервер"/> + <node name="proxyHost" value="ÐдреÑа прокÑÑ–-Ñервера"/> + <node name="proxyPort" value="Порт прокÑÑ–-Ñервера"/> + <node name="timeout" value="МакÑимальний Ñ‡Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸, Ñекунди"/> + </node> + <node name="Web" value="Веб"> + <node name="enableIntegration" value="Відкривати зовнішні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð° допомогою %s"/> + <node name="defaultText" value="Відкривати зовнішні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñƒ переглÑдачі"/> + <node name="choice" value="ПереглÑдач"/> + <node name="command" value="Виконати команду"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Мова"> + <node name="autoDetect" value="Визначити мову та кодувати автоматично"/> + <node name="defaultLanguage" value="Типова мова"/> + <node name="defaultEncodingSet" value="ÐабiÑ€ Ñимволiв"/> + <node name="defaultEncoding" value="Типовий набiÑ€ Ñимволiв"/> + <node name="useWindows1252Hack" value="ВикориÑтати windows-1252 замiÑть iso-8859-1"/> + </node> + <node name="Config" value="ÐалаштуваннÑ"> + <node name="autoSave" value="Ðвтоматично зберігати Ñтан"/> + <node name="timeout" value="Ð§Ð°Ñ Ð¼Ñ–Ð¶ збереженнÑм, Ñекунди"/> + </node> + <node name="Dictionary" value="Словники"> + <node name="enableIntegration" value="Увімкнути інтеграцію з %s"/> + <node name="defaultText" value="Увімкнути інтеграцію зі Ñловником"/> + <node name="choice" value="ВикориÑтати"/> + <node name="singleClickOpen" value="Відкривати Ñловник по натиÑканню на Ñлово"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Виконувати при вiдпуÑканнi клавiши, нe при натиÑненнi"/> + <node name="minStylusPressure" value="Мiнiмальне натиÑÐºÑƒÐ²Ð°Ð½Ð½Ñ ÑÑ‚iлуÑом"/> + <node name="maxStylusPressure" value="МакÑимальне натиÑÐºÑƒÐ²Ð°Ð½Ð½Ñ ÑÑ‚iлуÑом"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="ПерегортаннÑ"> + <node name="keyScrollDelay" value="Затримка між Ð¿ÐµÑ€ÐµÐ³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÐ°Ð¼Ð¸, міліÑекунди"/> + <node name="keyLinesToScroll" value="Скільки Ñ€Ñдків перегортати за 1 раз"/> + <node name="keyLinesToKeep" value="Скільки Ñ€Ñдків залишати з попередньої Ñторінки"/> + <node name="enableTapScrolling" value="Включити Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ñ‚Ð¸ÑненнÑм на екран"/> + <node name="fingerOnly" value="Прокручувати тільки при натиÑканні пальцем"/> + </node> + <node name="Selection" value="Помітка"> + <node name="enableSelection" value="Дозволити помiчати текÑÑ‚"/> + </node> + <node name="Indicator" value="Індикатор"> + <node name="type" value="Показувати Ñк"> + <node name="osScrollbar" value="Лінійка прокручуваннÑ"/> + <node name="fbIndicator" value="Iндикатор внизу"/> + <node name="none" value="Ðе показувати"/> + </node> + <node name="height" value="ВиÑота індикатора"/> + <node name="offset" value="ВідÑтуп від текÑту"/> + <node name="pageNumber" value="Показувати номери Ñторінок"/> + <node name="time" value="Показувати поточний чаÑ"/> + <node name="fontSize" value="Розмір шрифта"/> + <node name="tocMarks" value="Показувати помітки початку"/> + <node name="navigation" value="Реагувати на натиÑканнÑ"/> + </node> + <node name="Rotation" value="Поворот"> + <node name="direction" value="Як повертати"> + <node name="disabled" value="Ðе повертати взагалі"/> + <node name="clockwise" value="Ðа 90 градуÑів за годинниковою Ñтрілкою"/> + <node name="counterclockwise" value="Ðа 90 градуÑів проти годинникової Ñтрілки"/> + <node name="180" value="Ðа 180 градуÑів"/> + <node name="cycle" value="ПеремикатиÑÑ Ð¿Ð¾Ð¼Ñ–Ð¶ 4 орієнтаціÑми"/> + </node> + </node> + <node name="Keys" value="Клавіші"> + <node name="grabSystemKeys" value="Перехоплювати ÑиÑтемні клавиші"/> + <node name="separate" value="Свої Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ñ— орієнтації текÑту"/> + <node name="orientation" value="ОрієнтаціÑ"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="ÐÑ–Ñких дій"/> + <node name="showLibrary" value="Показати бібліотеку"/> + <node name="showNetLibrary" value="Показати електронну бібліотеку"/> + <node name="showRecent" value="Показати прочитані книги"/> + <node name="previousBook" value="Відкрити попередню книгу"/> + <node name="toc" value="Показати зміÑÑ‚"/> + <node name="gotoHome" value="Перейти до початку текÑту"/> + <node name="gotoSectionStart" value="Перейти до початку розділу"/> + <node name="gotoSectionEnd" value="Перейти до ÐºÑ–Ð½Ñ†Ñ Ñ€Ð¾Ð·Ð´Ñ–Ð»Ñƒ"/> + <node name="nextTOCSection" value="Перейти до наÑтупної глави"/> + <node name="previousTOCSection" value="Перейти до попередньої глави"/> + <node name="pageForward" value="Перегорнути на Ñторінку вперед"/> + <node name="pageBackward" value="Перегорнути на Ñторінку назад"/> + <node name="lineForward" value="Перегорнути на Ñ€Ñдок вперед"/> + <node name="lineBackward" value="Перегорнути Ñ€Ñдок назад"/> + <node name="undo" value="СкаÑувати перехід"/> + <node name="redo" value="Повторити перехід"/> + <node name="copyToClipboard" value="Скопіювати позначений текÑÑ‚ до буфера"/> + <node name="openInDictionary" value="Відкрити позначений текÑÑ‚ у Ñловнику"/> + <node name="clearSelection" value="ЗнÑти позначку"/> + <node name="search" value="Показати діалог пошуку"/> + <node name="findPrevious" value="Шукати назад"/> + <node name="findNext" value="Шукати вперед"/> + <node name="increaseFont" value="Збільшити розмір шрифта"/> + <node name="decreaseFont" value="Зменшити розмір шрифта"/> + <node name="toggleIndicator" value="Показати/Ñховати індикатор"/> + <node name="toggleFullscreen" value="Ввімкнути/вимкнути повноекранний режим"/> + <node name="rotate" value="Повернути текÑÑ‚"/> + <node name="addBook" value="Додати файл до бібліотеки"/> + <node name="cancel" value="Відмінити поточний режим"/> + <node name="quit" value="Вийти з програми"/> + <node name="bookInfo" value="Показати інформацію про книгу"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Вийти з програми"/> + <node name="keyDelay" value="Затримка між натиÑканнÑм на клавіші"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Завжди викориÑтовувати влаÑні шрифти"/> + </node> + <node name="Margins" value="ВідÑтупи"> + <node name="left" value="ВідÑтуп зліва"/> + <node name="right" value="ВідÑтуп зправа"/> + <node name="top" value="ВідÑтуп зверху"/> + <node name="bottom" value="ВідÑтуп знизу"/> + </node> + <node name="Format" value="ФорматуваннÑ"> + <node name="optionsFor" value="ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ"/> + <node name="lineSpacing" value="Інтервал"> + <node name="unchanged" value="<не змінювати>"/> + </node> + <node name="firstLineIndent" value="Червоний Ñ€Ñдок"/> + <node name="alignment" value="ВирівнюваннÑ"> + <node name="left" value="ліве"/> + <node name="right" value="праве"/> + <node name="center" value="по центру"/> + <node name="justify" value="по краÑÑ…"/> + <node name="unchanged" value="<не змінювати>"/> + </node> + <node name="spaceBefore" value="ПропуÑк перед"/> + <node name="spaceAfter" value="ПропуÑк піÑлÑ"/> + <node name="startIndent" value="ВідÑтуп на початку Ñ€Ñдка"/> + <node name="endIndent" value="ВідÑтуп на кінці Ñ€Ñдка"/> + </node> + <node name="Styles" value="Стилі"> + <node name="optionsFor" value="ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ"/> + <node name="fontFamily" value="Шрифт"> + <node name="unchanged" value="<не змінювати>"/> + </node> + <node name="fontSize" value="Розмір"/> + <node name="fontSizeDifference" value="Розмір"/> + <node name="bold" value="Жирний"/> + <node name="italic" value="КурÑив"/> + <node name="allowHyphenations" value="ПереноÑи"/> + <node name="autoHyphenations" value="ПереноÑи"/> + </node> + <node name="Colors" value="Кольори"> + <node name="colorFor" value="Колір"> + <node name="background" value="фону"/> + <node name="selectionBackground" value="фону помітки"/> + <node name="text" value="звичайного текÑту"/> + <node name="internalLink" value="поÑиланнÑ"/> + <node name="externalLink" value="зовнішнього поÑиланнÑ"/> + <node name="bookLink" value="ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° іншу книгу"/> + <node name="highlighted" value="підÑвіченого текÑту"/> + <node name="treeLines" value="ліній"/> + <node name="indicator" value="індикатора"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ книгу"/> + <node name="tab"> + <node name="Common" value="ОÑновна інформаціÑ"> + <node name="file" value="Файл"/> + <node name="title" value="Ðазва"/> + <node name="language" value="Мова"/> + <node name="encodingSet" value="Ðабір кодувань"/> + <node name="encoding" value="КодуваннÑ"/> + </node> + <node name="Authors" value="Ðвтори"> + <node name="authorDisplayName" value="Ім'Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð°"/> + </node> + <node name="Series" value="СеріÑ"> + <node name="seriesTitle" value="Ðазва Ñерії"/> + <node name="bookIndex" value="Ðомер книги у Ñерії"/> + </node> + <node name="Tags" value="Теги"> + <node name="tags" value="Ðазва тегу"/> + </node> + <node name="Text" value="ТекÑÑ‚"> + <node name="breakType" value="Ðовий параграф по"/> + <node name="ignoreIndent" value="Ігнорувати відÑтупи менше"/> + <node name="buildTOC" value="Побудувати зміÑÑ‚"/> + <node name="emptyLines" value="Порожніх Ñ€Ñдків між главами"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Ðовий параграф по"/> + <node name="ignoreIndent" value="Ігнорувати відÑтупи менше"/> + <node name="buildTOC" value="Побудувати зміÑÑ‚"/> + <node name="emptyLines" value="Порожніх Ñ€Ñдків між главами"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ автора"/> + <node name="name" value="Ім'Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð°"/> + <node name="sortKey" value="Сортувати за авторами"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ½Ð¸Ð³Ð¸ до бібліотеки"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Пошук по текÑту"/> + <node name="text" value=""/> + <node name="ignoreCase" value="Ігнорувати регіÑтр букв"/> + <node name="wholeText" value="По вÑьому текÑту"/> + <node name="backward" value="Ðазад"/> + <node name="currentSection" value="Тільки у цьому розділі"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Пошук у мережі"/> + <node name="titleAndSeries" value="Ðазва книги/СеріÑ"/> + <node name="author" value="Ðвтор"/> + <node name="category" value="КатегоріÑ"/> + <node name="description" value="ОпиÑ"/> + <node name="annotation" value="Результати пошуку длÑ: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="До Ñторінки"/> + <node name="pageNumber" value="Ðомер Ñторінки"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Редагувати тег"/> + <node name="name" value="Ðазва тега"/> + <node name="includeSubtags" value="Включаючи підтеги"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Клонувати тег"/> + <node name="name" value="Ðазва тегу"/> + <node name="includeSubtags" value="Включаючи підтеги"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ½Ð¸Ð³Ð¸"/> + <node name="message" value="Видалити книгу "%s" з бібліотеки?"/> + <node name="deleteFile" value="Ви дійÑно хочете вилучити з диÑка файл “%sâ€?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Видалити тег"/> + <node name="message" value="Видалити тег “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Помилка"/> + <node name="message" value="Ðе можу відкрити: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Помилка"/> + <node name="message" value="Ðе можу видалити файл %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Помилка"/> + <node name="message" value="Вибачте, немає файлу з інформацією"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Бібліотеки Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ не вказані"/> + <node name="authenticationFailed" value="Помилка авторизації"/> + <node name="internalError" value="Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° Ñервера"/> + <node name="purchaseNotEnoughMoney" value="Ðе доÑтатньо коштів на рахунку"/> + <node name="purchaseMissingBook" value="Книга відÑÑƒÑ‚Ð½Ñ Ð² продажу"/> + <node name="purchaseAlreadyPurchased" value="Книга вже була куплена"/> + <node name="bookNotPurchased" value="Книга не була куплена"/> + <node name="downloadLimitExceeded" value="Ліміт завантажень вичерпано"/> + <node name="unsupportedOperation" value="ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ"/> + <node name="loginAlreadyTaken" value="Це ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача зайнÑто"/> + <node name="loginNotSpecified" value="Введіть ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"/> + <node name="passwordNotSpecified" value="Введіть непорожній пароль"/> + <node name="emailNotSpecified" value="Введіть адреÑу електронної пошти"/> + <node name="invalidEMail" value="Ðевірна адреÑа електронної пошти"/> + <node name="tooManyRegistrations" value="Занадто багато реєÑтрацій з вашого IP; Ñпробуйте ще раз через пару хвилин"/> + <node name="noUserEmail" value="Ðемає кориÑтувача з такою адреÑою електронної пошти"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Помилка при завантаженні"/> + <node name="message" value="Ðеможливо завантажити цю книгу в даний момент"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ½Ð¸Ð³Ð¸. Зачекайте..."/> + <node name="loadingBookList" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÑпиÑку книг. Зачекайте..."/> + <node name="migrate" value="Перехід на нову верÑÑ–ÑŽ. Зачекайте, будь лаÑка..."/> + <node name="downloadBookList" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÑпиÑку книг. Будь лаÑка, зачекайте ..."/> + <node name="downloadBook" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ½Ð¸Ð³Ð¸. Будь лаÑка, зачекайте ..."/> + <node name="downloadImages" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½ÑŒ. Будь лаÑка, зачекайте ..."/> + <node name="authentication" value="ÐвторізаціÑ. Будь лаÑка, зачекайте ..."/> + <node name="purchaseBook" value="Покупка книги. Будь лаÑка, зачекайте ..."/> + <node name="initializeAuthenticationManager" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— кориÑтувача. Будь лаÑка, зачекайте ..."/> + <node name="loadSubCatalog" value="Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ. Будь лаÑка, зачекайте..."/> + <node name="registerUser" value="РеєÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ кориÑтувача. Будь лаÑка, зачекайте..."/> + <node name="passwordRecovery" value="Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ. Будь лаÑка, зачекайте ..."/> + <node name="authenticationCheck" toBeTranslated="true" value="Account validation. Please, wait..."/> + <node name="signOut" toBeTranslated="true" value="Signing out. Please, wait..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Купити книгу"/> + <node name="message" value="Ви впевнені, що хочете придбати книгу “%sâ€?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="ÐвторізаціÑ"/> + <node name="login" value="Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"/> + <node name="password" value="Пароль"/> + <node name="skipIP" value="Ðе прив'ÑзуватиÑÑ Ð´Ð¾ IP-адреÑи"/> + <node name="loginIsEmpty" value="Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача не повинно бути порожнім"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="ІнформаціÑ"/> + <node name="message" value="Каталог порожній"/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Ð’Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð°"/> + <node name="message" value="Ви дійÑно бажаєте відключити каталог “%sâ€? Ви можете включити його во вкладинці “Пошук в мережі†у діалозі ÐалаштуваннÑ."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Видалити книгу"/> + <node name="message" value="Ви дійÑно бажаете видалити книгу “%s†з диÑку?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="РегіÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"/> + <node name="login" value="Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"/> + <node name="password" value="Пароль"/> + <node name="confirmPassword" value="ÐŸÑ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="Пароль та Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ– бути однаковими."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ"/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ"/> + <node name="message" value="ІнÑÑ‚Ñ€ÑƒÐºÑ†Ñ–Ñ Ð· Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ñлана на адреÑу %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Помилка завантаженнÑ"/> + <node name="message" value="Ðе можливо відктири завантаженний файл %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="текÑту типово"/> + <node name="Regular Paragraph" value="звичайного текÑту"/> + <node name="Title" value="заголовку"/> + <node name="Section Title" value="назви розділу"/> + <node name="Poem Title" value="назви вірша"/> + <node name="Subtitle" value="підзаголовку"/> + <node name="Annotation" value="анотації"/> + <node name="Epigraph" value="епіграфу"/> + <node name="Stanza" value="Ñтрофи"/> + <node name="Verse" value="віршів"/> + <node name="Preformatted text" value="текÑту вÑередині <pre>"/> + <node name="Image" value="малюнку"/> + <node name="Cite" value="цитати"/> + <node name="Author" value="імені автора"/> + <node name="Date" value="дати"/> + <node name="Internal Hyperlink" value="поÑиланнÑ"/> + <node name="Footnote" value="зноÑки"/> + <node name="Emphasis" value="Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ (emphasis)"/> + <node name="Strong" value="Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ (strong)"/> + <node name="Subscript" value="нижнього індекÑу"/> + <node name="Superscript" value="верхнього індекÑу"/> + <node name="Code" value="текÑту програми"/> + <node name="StrikeThrough" value="закреÑленого текÑту"/> + <node name="Contents Table" value="зміÑту"/> + <node name="Library Entry" value="бібліотеки"/> + <node name="Recent Book List" value="ÑпиÑку книг"/> + <node name="Italic" value="курÑиву"/> + <node name="Bold" value="жирного текÑту"/> + <node name="Definition" value="визначеннÑ"/> + <node name="Definition Description" value="текÑту визначеннÑ"/> + <node name="Header 1" value="текÑту вÑередині <h1>"/> + <node name="Header 2" value="текÑту вÑередині <h2>"/> + <node name="Header 3" value="текÑту вÑередині <h3>"/> + <node name="Header 4" value="текÑту вÑередині <h4>"/> + <node name="Header 5" value="текÑту вÑередині <h5>"/> + <node name="Header 6" value="текÑту вÑередині <h6>"/> + <node name="External Hyperlink" value="зовнішнього поÑиланнÑ"/> + <node name="Link to Another Book" value="поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° іншу книгу"/> + </node> + <node name="external"> + <node name="browser" value="переглÑдачі"/> + <node name="defaultBrowser" value="переглÑдачі"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="невідома помилка"/> + <node name="unsupportedCompressionMethod" value="метод натиÑканнÑ, що не підтримуєтьÑÑ"/> + <node name="encryptedFile" value="файл захищений DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="електронна бібліотека"/> + </node> + <node name="library"> + <node name="caption" value="Бібліотека"/> + </node> +</resources> diff --git a/reader/data/resources/vi.xml b/reader/data/resources/vi.xml new file mode 100644 index 0000000..dc92878 --- /dev/null +++ b/reader/data/resources/vi.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Vietnamese TDE-Ebook-Reader resources, by Phạm Văn Hùng_Firestork --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="Hiện sách"/> + <node name="collapseTree" value="Ẩn sách"/> + <node name="edit" value="Chỉnh sá»a thông tin"/> + <node name="unknownAuthor" value="Chưa biết tác giả"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="Hiện sách"/> + <node name="collapseTree" value="Ẩn sách"/> + <node name="edit" value="Chỉnh sá»a từ khóa"/> + <node name="clone" value="Thêm 1 từ khóa"/> + <node name="delete" value="Xóa từ khóa"/> + <node name="noTags" value="Sách không có từ khóa"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Hiện sách"/> + <node name="collapseTree" value="Ẩn sách"/> + </node> + <node name="bookNode"> + <node name="read" value="Äá»c sách"/> + <node name="edit" value="Chỉnh sá»a thông tin"/> + <node name="delete" value="Xóa sách"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="Theo tác giả"> + <node name="summary" value="Sách được xếp theo tác giả"/> + </node> + <node name="byTitle" value="By title" toBeTranslated="true"> + <node name="summary" value="Books sorted by title" toBeTranslated="true"/> + </node> + <node name="byDate" value="By date" toBeTranslated="true"> + <node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/> + </node> + <node name="bySeries" value="By series" toBeTranslated="true"> + <node name="summary" value="Books sorted by series" toBeTranslated="true"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="Mở rá»™ng"/> + <node name="collapseTree" value="Thu lại"/> + <node name="reload" value="Tải lại"/> + <node name="openInBrowser" value="Mở trong trình duyệt"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="Mở catalô"/> + <node name="collapseTree" value="Äóng catalô"/> + <node name="login" value="Äăng nháºp"/> + <node name="logout" value="Äăng xuấtt (%s)"/> + <node name="reload" value="Tải lại"/> + <node name="dontShow" value="Không hiện catalô nà y"/> + <node name="topupAccount" value="Là m đầy tà i khoản (hiện tại: %s)"/> + <node name="register" value="Äăng kÃ"/> + <node name="passwordRecovery" value="Phục hồi máºt khẩu"/> + </node> + <node name="searchResultNode"> + <node name="title" value="Kết quả tìm kiếm"/> + <node name="expandTree" value="Hiện kết quả"/> + <node name="collapseTree" value="Ẩn kết quả"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="Hiện sách"/> + <node name="collapseTree" value="Ẩn sách"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="Hiện sách"/> + <node name="collapseTree" value="Ẩn sách"/> + </node> + <node name="bookNode"> + <node name="read" value="Äá»c bản ở máy "/> + <node name="delete" value="Xóa bản ở máy"/> + <node name="download" value="Tải vá»"/> + <node name="readDemo" value="Äá»c thá» bản mẫu"/> + <node name="downloadDemo" value="Tải vá» bản mẫu "/> + <node name="demo" toBeTranslated="true" value="sample"/> + <node name="buy" value="Mua (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="Thông tin sách..."/> + <node name="toc" value="Mục lục"/> + <node name="showLibrary" value="Mở Thư viện"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="Thư viện"> + <node name="showLibrary" value="Mở"/> + <node name="previousBook" value="Quyển trước"/> + <node name="showRecent" value="Vừa xem"/> + <node name="addBook" value="Thêm sách..."/> + <node name="showHelp" value="Nói vá» tde-ebook-reader"/> + </node> + <node name="gotoHome" value="Äến vị trà đầu cá»§a Tà i liệu"/> + <node name="gotoPageNumber" value="Äến trang..."/> + <node name="gotoSectionStart" value="Äến đầu cá»§a má»™t Tiết Ä‘oạn"/> + <node name="gotoSectionEnd" value="Äến cuối cá»§a má»™t Tiết Ä‘oạn "/> + <node name="nextTOCSection" value="Äến khoản ML Tiếp theo"/> + <node name="previousTOCSection" value="Äến khoản ML Trước"/> + <node name="navigate" value="Navigate"> + <node name="gotoHome" value="Äến vị trà đầu cá»§a Tà i liệu"/> + <node name="gotoPageNumber" value="Äến trang..."/> + <node name="gotoSectionStart" value="Äến đầu cá»§a má»™t Tiết Ä‘oạn"/> + <node name="gotoSectionEnd" value="Äến cuối cá»§a má»™t Tiết Ä‘oạn"/> + <node name="nextTOCSection" value="Äến mục ML Tiếp theo"/> + <node name="previousTOCSection" value="Äến mục ML Trước"/> + <node name="undo" value="Quay lại"/> + <node name="redo" value="Äi vá» trước"/> + </node> + <node name="selection" value="Tiết Ä‘oạn"> + <node name="copyToClipboard" value="Chép và o Clipboard"/> + <node name="openInDictionary" value="Mở trong Từ Ä‘iển"/> + <node name="clearSelection" value="Xóa"/> + </node> + <node name="search" value="Tìm kiếm"> + <node name="search" value="Tìm chữ..."/> + <node name="findNext" value="Tìm tiếp phÃa sau"/> + <node name="findPrevious" value="Tìm vá» phÃa trước"/> + </node> + <node name="view" value="Cách xem"> + <node name="rotate" value="Quay mà n hình"/> + <node name="toggleFullscreen" value="Toà n Mà n hình"/> + <node name="toggleIndicator" value="Äảo chiá»u Thanh định hướng"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="Äóng"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="Äá»c Sách"/> + <node name="tooltip" value="Xem Chế độ Äá»c sách"/> + </node> + <node name="showLibrary"> + <node name="label" value="Thư viện"/> + <node name="tooltip" value="Xem Cây tổ chức Thư viện"/> + <node name="popup" value="Xem danh sách vừa Ä‘á»c"/> + </node> + <node name="showRecent"> + <node name="label" value="Sách vừa Ä‘á»c"/> + <node name="tooltip" value="Xem danh sách vừa Ä‘á»c"/> + </node> + <node name="byAuthor"> + <node name="label" value="Theo Tác giả"/> + <node name="tooltip" value="Tổ chức Sách theo tác giả"/> + </node> + <node name="byTag"> + <node name="label" value="Theo Từ khóa"/> + <node name="tooltip" value="Tổ chức Sách theo Từ khóa"/> + </node> + <node name="addBook"> + <node name="label" value="Thêm Táºp tin"/> + <node name="tooltip" value="Thêm Táºp tin và o Thư viện"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="Mạng"/> + <node name="tooltip" value="Tìm kiếm trong các Thư viện trên Mạng"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="Tìm kiếm ÄÆ¡n giản"/> + <node name="tooltip" value="Tìm kiếm trên Mạng"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="Tìm kiếm"/> + <node name="tooltip" value="Tìm kiếm Nâng cao trên Mạng"/> + </node> + <node name="gotoHome"> + <node name="label" value="Äến Vị trà đầu"/> + <node name="tooltip" value="Äến Vị trà đầu cá»§a sách"/> + </node> + <node name="undo"> + <node name="label" value="Quay lại"/> + <node name="tooltip" value="Quay lại"/> + </node> + <node name="redo"> + <node name="label" value="Äi tiếp"/> + <node name="tooltip" value="Äi tiếp"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="Äến Trang"/> + <node name="tooltip" value="Äến Trang"/> + </node> + <node name="toc"> + <node name="label" value="ML"/> + <node name="tooltip" value="Mục Lục"/> + </node> + <node name="search"> + <node name="label" value="Tìm kiếm"/> + <node name="tooltip" value="Tìm kiếm chữ"/> + </node> + <node name="findNext"> + <node name="label" value="Tiếp"/> + <node name="tooltip" value="Tìm tiếp"/> + </node> + <node name="findPrevious"> + <node name="label" value="Trước"/> + <node name="tooltip" value="Tìm PhÃa trước"/> + </node> + <node name="rotate"> + <node name="label" value="Quay"/> + <node name="tooltip" value="Quay Sách"/> + </node> + <node name="showHelp"> + <node name="label" value="Nói vá»"/> + <node name="tooltip" value="Vá» tde-ebook-reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="Bá»™ lá»c"/> + <node name="tooltip" value="Bá»™ lá»c"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="Thông tin Sách"/> + <node name="tooltip" value="Hiện há»™p Thông tin Sách"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&Äi!"/> + <node name="thisOnly" value="Chỉ cái nà y"/> + <node name="withSubtags" value="Vá»›i từ khóa phụ"/> + <node name="removeLink" value="Xóa khá»i thư viện"/> + <node name="removeFile" value="Xóa khá»i ổ cứng"/> + <node name="yesToAll" value="Äồng ý &tất cả"/> + <node name="buy" value="&Mua"/> + <node name="buyAndDownload" value="Mua và &tải vá»"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="Thư viện"> + <node name="bookPath" value="ÄÆ°á»ng dẫn tá»›i Sách"/> + <node name="lookInSubdirectories" value="Tìm Sách trong Thư mục con"/> + <node name="collectBooksWithoutMetaInfo" value="Sưu táºp Sách mà không có Siêu Thông tin"/> + <node name="downloadDirectory" value="Thư mục Sách tải vá»"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="Tìm kiếm trên Mạng"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="Sá» dụng Proxy"/> + <node name="proxyHost" value="Máy chá»§ Proxy"/> + <node name="proxyPort" value="Cổng Proxy"/> + <node name="timeout" value="Hoạt động Mạng hết Thá»i gian chá», giây"/> + </node> + <node name="Web" value="Web"> + <node name="enableIntegration" value="Mở Liên kết Bên ngoà i trong %s"/> + <node name="defaultText" value="Mở Liên kết Bên ngoà i trong Trình duyệt"/> + <node name="choice" value="Dùng Trình duyệt"/> + <node name="command" value="Lệnh để Thá»±c thi"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="Ngôn ngữ"> + <node name="autoDetect" value="Tá»± động Lá»±a chá»n Ngôn ngữ và cách Giải mã"/> + <node name="defaultLanguage" value="Ngôn ngữ Mặc định"/> + <node name="defaultEncodingSet" value="Äặt cách Giải mã Mặc định"/> + <node name="defaultEncoding" value="Cách Giải mã Mặc định"/> + <node name="useWindows1252Hack" value="Sá» dụng windows-1252 thay thế cho iso-8859-1"/> + </node> + <node name="Config" value="Cấu hình"> + <node name="autoSave" value="Lưu Trạng thái má»™t cách Tá»± động"/> + <node name="timeout" value="Thá»i gian chá» Giữa những Lần lưu, giây"/> + </node> + <node name="Dictionary" value="Từ Ä‘iển"> + <node name="enableIntegration" value="Báºt TÃch hợp vá»›i %s"/> + <node name="defaultText" value="Báºt TÃch hợp vá»›i Từ Ä‘iển"/> + <node name="choice" value="TÃch hợp vá»›i"/> + <node name="singleClickOpen" value="Mở bằng Má»™t lần Click"/> + </node> + <node name="Maemo" value="Maemo"> + <node name="keyActionOnRelease" value="Tác dụng ở PhÃm Nhả (Release) , không ở PhÃm Bấm (Press)"/> + <node name="minStylusPressure" value="Ãp lá»±c bút Stylus Tối thiểu"/> + <node name="maxStylusPressure" value="Ãp lá»±c bút Stylus Tối Ä‘a"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="Cuá»™n"> + <node name="keyScrollDelay" value="Thá»i gian giữa 2 lần ấn PhÃm Cuá»™n, mili giây"/> + <node name="keyLinesToScroll" value="Số dòng để Cuá»™n má»—i Dòng Cuá»™n"/> + <node name="keyLinesToKeep" value="Số dòng để Giữ má»—i Trang Cuá»™n"/> + <node name="enableTapScrolling" value="Báºt Cuá»™n Phân nhánh"/> + <node name="fingerOnly" value="Chỉ cuá»™n trong Chốt Phân nhánh"/> + </node> + <node name="Selection" value="Sá»± Chá»n"> + <node name="enableSelection" value="Báºt Chá»n Văn bản"/> + </node> + <node name="Indicator" value="Thanh Äịnh hướng"> + <node name="type" value="Hiện như"> + <node name="osScrollbar" value="Thanh cuá»™n cá»§a HÄH"/> + <node name="fbIndicator" value="Thanh Äịnh hướng kiểu cÅ©"/> + <node name="none" value="Không Hiện"/> + </node> + <node name="height" value="Äá»™ rá»™ng Thanh cuá»™n"/> + <node name="offset" value="Khoảng cách tÃnh từ cuối Văn bản"/> + <node name="pageNumber" value="Hiện Vị trà trang hiện tại"/> + <node name="time" value="Hiện Thá»i gian"/> + <node name="fontSize" value="Cỡ Phông"/> + <node name="tocMarks" value="Hiện các Äánh dấu ML"/> + <node name="navigation" value="Cho phép Äiá»u hướng"/> + </node> + <node name="Rotation" value="Quay"> + <node name="direction" value="Kiểu Quay"> + <node name="disabled" value="Tắt"/> + <node name="clockwise" value="Thuáºn chiá»u kim đồng hồ 90 Äá»™"/> + <node name="counterclockwise" value="Ngược chiá»u kim đồng hồ 90 Äá»™"/> + <node name="180" value="180 Äá»™"/> + <node name="cycle" value="Xoay vòng Cả 4 Hướng"/> + </node> + </node> + <node name="Keys" value="CaÌc phiÌm"> + <node name="grabSystemKeys" value="Bắt PhÃm Hệ thống"/> + <node name="separate" value="PhÃm Gán Phụ thuá»™c và o Äịnh hướng"/> + <node name="orientation" value="Äịnh hướng"> + <node name="degrees0" toBeTranslated="true" value="0 Degrees"/> + <node name="degrees90ccw" toBeTranslated="true" value="90 Degrees Counterclockwise"/> + <node name="degrees180" toBeTranslated="true" value="180 Degrees"/> + <node name="degrees90cw" toBeTranslated="true" value="90 Degrees Clockwise"/> + </node> + <node name="action"> + <node name="none" value="Không"/> + <node name="showLibrary" value="Hiện thư viện"/> + <node name="showNetLibrary" value="Hiện thư viện mạng"/> + <node name="showRecent" value="Hiện những cuốn vừa Ä‘á»c"/> + <node name="previousBook" value="Mở Cuốn trước "/> + <node name="toc" value="Hiện mục lục"/> + <node name="gotoHome" value="Äến trang chá»§"/> + <node name="gotoSectionStart" value="Äến đầu tiết Ä‘oạn"/> + <node name="gotoSectionEnd" value="Äến cuối tiết Ä‘oạn"/> + <node name="nextTOCSection" value="Äến Ä‘oạn ML tiếp theo"/> + <node name="previousTOCSection" value="Äến Ä‘oạn ML trước"/> + <node name="pageForward" value="Cuá»™n trang vá» trước"/> + <node name="pageBackward" value="Cuá»™n trang vá» sau"/> + <node name="lineForward" value="Cuá»™n dòng vá» trước"/> + <node name="lineBackward" value="Cuá»™n dòng vá» sau"/> + <node name="undo" value="Hoà n tác"/> + <node name="redo" value="Quay lại"/> + <node name="copyToClipboard" value="Chép Ä‘oạn văn bản đã chá»n và o clipboard"/> + <node name="openInDictionary" value="Mở Ä‘oạn văn bản đã chá»n trong clipboard"/> + <node name="clearSelection" value="Xóa mục chá»n"/> + <node name="search" value="Tìm kiếm"/> + <node name="findPrevious" value="Tìm trước"/> + <node name="findNext" value="Tìm tiếp"/> + <node name="increaseFont" value="Tăng cỡ phông"/> + <node name="decreaseFont" value="Giảm cỡ phông"/> + <node name="toggleIndicator" value="Äảo chiá»u vị trà thanh định hướng"/> + <node name="toggleFullscreen" value="Äảo chế độ toà n mà n hình"/> + <node name="rotate" value="Xoay mà n hình"/> + <node name="addBook" value="Thêm sách"/> + <node name="cancel" value="Há»§y bá»l"/> + <node name="quit" value="Thoát"/> + <node name="bookInfo" value="Hiện há»™p thông tin"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="Thoát Ứng dụng khi Há»§y bá»"/> + <node name="keyDelay" value="Äá»™ trá»… Giữa các lần Bấm PhÃm được Chấp nháºn"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="Luôn luôn Sá» dụng Phông cá»§a Tôi"/> + </node> + <node name="Margins" value="Canh Lá»"> + <node name="left" value="Lá» Trái"/> + <node name="right" value="Lá» Phải"/> + <node name="top" value="Lá» Trên"/> + <node name="bottom" value="Lá» Dưới"/> + </node> + <node name="Format" value="Äịnh dạng"> + <node name="optionsFor" value="Tùy chá»n cho"/> + <node name="lineSpacing" value="Giãn cách Dòng"> + <node name="unchanged" value="<giữ nguyên>"/> + </node> + <node name="firstLineIndent" value="Thụt Lá» Dòng dầu"/> + <node name="alignment" value="Căn chỉnh"> + <node name="left" value="Trái"/> + <node name="right" value="Phải"/> + <node name="center" value="Giữa"/> + <node name="justify" value="Tá»± căn chỉnh"/> + <node name="unchanged" value="<giữ nguyên>"/> + </node> + <node name="spaceBefore" value="Khoảng cách phÃa Trước"/> + <node name="spaceAfter" value="Khoảng cách phÃa Sau"/> + <node name="startIndent" value="Dòng Bắt đầu Thụt lá»"/> + <node name="endIndent" value="Dòng kết thúc Thụt lá»"/> + </node> + <node name="Styles" value="Kiểu"> + <node name="optionsFor" value="Tùy chá»n cho"/> + <node name="fontFamily" value="Phông Hệ thống"> + <node name="unchanged" value="<giữ nguyên>"/> + </node> + <node name="fontSize" value="Cỡ"/> + <node name="fontSizeDifference" value="Các Cỡ Khác nhau"/> + <node name="bold" value="Äáºm"/> + <node name="italic" value="Nghiêng"/> + <node name="allowHyphenations" value="Cho phép Tách từ"/> + <node name="autoHyphenations" value="Tá»± động Tách từ"/> + </node> + <node name="Colors" value="Mà u sắc"> + <node name="colorFor" value="Mà u cho"> + <node name="background" value="Ná»n"/> + <node name="selectionBackground" value="Chá»n Ná»n"/> + <node name="text" value="Văn bản thưá»ng"/> + <node name="internalLink" value="Văn bản Siêu liên kết Bên ngoà i"/> + <node name="externalLink" value="Văn bản Siêu liên kết Bên trong"/> + <node name="bookLink" value="Liên kết tá»›i Quyển sách khác"/> + <node name="highlighted" value="Là m nổi báºt văn bản"/> + <node name="treeLines" value="Dòng Cây"/> + <node name="indicator" value="Vị trà thanh Äịnh hướng"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Thông tin sách"/> + <node name="tab"> + <node name="Common" value="Tổng quát"> + <node name="file" value="Táºp tin"/> + <node name="title" value="Tên sách"/> + <node name="language" value="Ngôn ngữ"/> + <node name="encodingSet" value="Äặt cách Giải mã"/> + <node name="encoding" value="Cách Giải mã"/> + </node> + <node name="Authors" value="Tác giả"> + <node name="authorDisplayName" value="Tên Tác giả"/> + </node> + <node name="Series" value="Bá»™ sách"> + <node name="seriesTitle" value="Tên Bá»™"/> + <node name="bookIndex" value="Chỉ mục sách"/> + </node> + <node name="Tags" value="Từ khóa"> + <node name="tags" value="Tên Từ khóa"/> + </node> + <node name="Text" value="Văn bản"> + <node name="breakType" value="Ngắt Äoạn tại"/> + <node name="ignoreIndent" value="Bá» qua Thụt lá» ngắn hÆ¡n"/> + <node name="buildTOC" value="Tạo Mục Lục"/> + <node name="emptyLines" value="Là m sạch Dòng Trước Tiết Ä‘oạn Má»›i"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="Ngắt Äoạn tại"/> + <node name="ignoreIndent" value="Bá» qua Thụt lá» ngắn hÆ¡n"/> + <node name="buildTOC" value="Tạo Mục Lục"/> + <node name="emptyLines" value="Là m sạch Dòng Trước Tiết Ä‘oạn Má»›i"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - Thông tin Tác giả"/> + <node name="name" value="Tên Tác giả"/> + <node name="sortKey" value="Khóa Xếp Tác giả"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - Thêm Sách và o Thư viện"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="Tìm Chữ"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&Bá» qua loại chữ"/> + <node name="wholeText" value="Giữ n&guyên chữ"/> + <node name="backward" value="&Quay lại"/> + <node name="currentSection" value="&Chỉ Ä‘oạn nà y"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="Tìm kiếm trên Mạng"/> + <node name="titleAndSeries" value="Tên/Bá»™"/> + <node name="author" value="Tác giả"/> + <node name="category" value="Hạng mục"/> + <node name="description" value="Mô tả"/> + <node name="annotation" value="Tìm kiếm kết quả cho: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="Äến Trang"/> + <node name="pageNumber" value="Äến Trang Số"/> + </node> + <node name="editTagDialog"> + <node name="title" value="Chỉnh sá»a Từ khóa"/> + <node name="name" value="Tên Từ khóa"/> + <node name="includeSubtags" value="Bao gồm Từ khóa phụ"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="Bản sao Từ khóa"/> + <node name="name" value="Tên Từ khóa"/> + <node name="includeSubtags" value="Bao gồm Từ khóa phụ"/> + </node> + <node name="removeBookBox"> + <node name="title" value="Xóa Sách"/> + <node name="message" value="Xóa Sách “%s†khá»i Thư viện?"/> + <node name="deleteFile" value="Bạn thá»±c sá»± muốn xóa táºp tin “%s†khá»i đĩa cứng?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="Xóa Từ khóa"/> + <node name="message" value="Xóa Từ khóa “%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="Lá»—i"/> + <node name="message" value="Không thể mở: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="Lá»—i"/> + <node name="message" value="Không thể xóa táºp tin %s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="Lá»—i"/> + <node name="message" value="Rất tiếc, không tìm thấy táºp tin giúp đỡ"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="Danh sách thư viện rá»—ng"/> + <node name="authenticationFailed" value="Xác thá»±c thất bại"/> + <node name="internalError" value="Lá»—i máy chá»§ ná»™i bá»™"/> + <node name="purchaseNotEnoughMoney" value="Không đủ tiá»n"/> + <node name="purchaseMissingBook" value="Sách bị mất"/> + <node name="purchaseAlreadyPurchased" value="Äã sẵn sà ng mua"/> + <node name="bookNotPurchased" value="Sách không được mua"/> + <node name="downloadLimitExceeded" value="Vượt quá giá»›i hạn tải vá»"/> + <node name="unsupportedOperation" value="Thao tác không được há»— trợ"/> + <node name="loginAlreadyTaken" value="Tên ngưá»i dùng đã sẵn sà ng sá» dụng"/> + <node name="loginNotSpecified" value="Vui lòng nháºp tên ngưá»i dùng"/> + <node name="passwordNotSpecified" value="Là m Æ¡n gõ má»™t máºt khẩu không trống rá»—ng"/> + <node name="emailNotSpecified" value="Là m Æ¡n gõ má»™t địa chỉ thư Ä‘iện tá» (email)"/> + <node name="invalidEMail" value="Äịa chỉ thư Ä‘iện tá» không đúng"/> + <node name="tooManyRegistrations" value="Có quá nhiá»u đăng ký từ địa chỉ IP cá»§a bạn; hãy thá» lại trong Ãt phút nữa"/> + <node name="noUserEmail" value="Chưa có ngưá»i nà o đăng vá»›i địa chỉ thư Ä‘iện tỠđược chỉ định"/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="Có lá»—i khi Ä‘ang tải vá»"/> + <node name="message" value="Không thể tải vá» cuốn sách nà y ngay bây giá»"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="Äang tải saÌch. Vui loÌ€ng đợi..."/> + <node name="loadingBookList" value="Äang tải thu viện. Vui loÌ€ng đợi..."/> + <node name="migrate" value="Äang nâng cấp lên phiên bản má»›i. Vui lòng đợi..."/> + <node name="downloadBookList" value="Äang tải vá» danh sách các cuốn sách. Vui lòng đợi..."/> + <node name="downloadBook" value="Äang tải sách vá». Vui lòng đợi..."/> + <node name="downloadImages" value="Äang tải vá» hình ảnh. Vui lòng đợi..."/> + <node name="authentication" value="Xác thá»±c. Vui lòng đợi..."/> + <node name="purchaseBook" value="Mua sách. Vui lòng đợi..."/> + <node name="initializeAuthenticationManager" value="Äang tải vá» thông tin tà i khoản. Vui lòng đợi..."/> + <node name="loadSubCatalog" value="Äang tải catalô. Vui lòng đợi..."/> + <node name="registerUser" value="Äang đăng ký tà i khoản má»›i. Vui lòng đợi..."/> + <node name="passwordRecovery" value="Äang khôi phục máºt khẩu. Vui lòng đợi..."/> + <node name="authenticationCheck" value="Tà i khoản hợp lệ. Vui lòng đợi..."/> + <node name="signOut" value="Äang đăng xuất. Vui lòng đợi..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="Mua sách"/> + <node name="message" value="Bạn có chắc muốn mua “%s†sách?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="Xác thá»±c"/> + <node name="login" value="Tên ngưá»i dùng"/> + <node name="password" value="Máºt khẩu"/> + <node name="skipIP" value="Äừng giá»›i hạn địa chỉ IP"/> + <node name="loginIsEmpty" value="Tên ngưá»i dùng không được để trống"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="Thông tin"/> + <node name="message" value="Catalô trống rá»—ng."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="Vô hiệu hóa catalô"/> + <node name="message" value="Bạn thá»±c sá»± muốn vô hiệu hóa “%s†catalô? Bạn có thể kÃch hoạt lại catalô nà y tại thẻ “Tìm kiếm trên Mạng†trong há»™p Tùy chỉnh."/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="Xóa Sách"/> + <node name="message" value="Bạn có chắc mình muốn xóa “%s†sách khá»i đĩa cứng?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="Ngưá»i dùng đăng kÃ"/> + <node name="login" value="Tên ngưá»i dùng"/> + <node name="password" value="Máºt khẩu"/> + <node name="confirmPassword" value="Xác nháºn máºt khẩu"/> + <node name="email" value="Thư Ä‘iện tá»" tooltip="Thư Ä‘iện tá» nà y được dùng để khôi phục máºt khẩu cá»§a bạn trong trưá»ng hợp bị mất. Nếu bạn không chỉ rõ má»™t thư Ä‘iện tá» bạn không thể khôi phục máºt khẩu cá»§a mình."/> + <node name="differentPasswords" value="Máºt khẩu và máºt khẩu xác nháºn phải giống nhau."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="Khôi phục máºt khẩu"/> + <node name="email" value="Thư Ä‘iện tá»"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="Khôi phục máºt khẩu"/> + <node name="message" value="Má»™t bức thư vá»›i những hướng dẫn rõ rà ng đã được gá»i tá»›i %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="Lá»—i Tải vá»"/> + <node name="message" value="Không thể mở táºp tin đã tải vá» %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="CÆ¡ sở"/> + <node name="Regular Paragraph" value="Äoạn văn bản Bình thưá»ng"/> + <node name="Title" value="Nhan đỠsách"/> + <node name="Section Title" value="Nhan đỠTiết Ä‘oạn"/> + <node name="Poem Title" value="Nhan đỠBà i thÆ¡"/> + <node name="Subtitle" value="Chú thÃch"/> + <node name="Annotation" value="Ghi chú"/> + <node name="Epigraph" value="Äá» từ"/> + <node name="Stanza" value="Khổ thÆ¡"/> + <node name="Verse" value="Câu thÆ¡"/> + <node name="Preformatted text" value="Äoạn văn bản đã định dạng"/> + <node name="Image" value="Hình ảnh"/> + <node name="Cite" value="TrÃch dẫn"/> + <node name="Author" value="Tác giả"/> + <node name="Date" value="Ngà y tháng"/> + <node name="Internal Hyperlink" value="Siêu liên kết Ná»™i bá»™"/> + <node name="Footnote" value="Chú dẫn cuối trang"/> + <node name="Emphasis" value="Nổi báºt"/> + <node name="Strong" value="Mạnh"/> + <node name="Subscript" value="Chỉ số dưới"/> + <node name="Superscript" value="Chỉ số trên"/> + <node name="Code" value="Mã"/> + <node name="StrikeThrough" value="StrikeThrough"/> + <node name="Contents Table" value="Mục Lục"/> + <node name="Library Entry" value="Mục nháºp Thư viện"/> + <node name="Recent Book List" value="Danh sách những Cuốn vùa Ä‘á»c"/> + <node name="Italic" value="Nghiêng"/> + <node name="Bold" value="Äáºm"/> + <node name="Definition" value="Äịnh nghÄ©a"/> + <node name="Definition Description" value="Mô tả Äịnh nghÄ©a"/> + <node name="Header 1" value="Äầu dòng 1"/> + <node name="Header 2" value="Äầu dòng 2"/> + <node name="Header 3" value="Äầu dòng 3"/> + <node name="Header 4" value="Äầu dòng 4"/> + <node name="Header 5" value="Äầu dòng 5"/> + <node name="Header 6" value="Äầu dòng 6"/> + <node name="External Hyperlink" value="Siêu liên kết Bên ngoà i"/> + <node name="Link to Another Book" value="Liên kế tá»›i Cuốn sách Khác"/> + </node> + <node name="external"> + <node name="browser" value="Trình duyệt"/> + <node name="defaultBrowser" value="Trình duyệt Mặc định"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="Lá»—i Chưa biết"/> + <node name="unsupportedCompressionMethod" value="Phương thức Nén Chưa được há»— trợ"/> + <node name="encryptedFile" value="Táºp tin được bảo vệ bằng DRM"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="Thư viện trên Mạng"/> + </node> + <node name="library"> + <node name="caption" value="Thư viện"/> + </node> +</resources> diff --git a/reader/data/resources/zh.xml b/reader/data/resources/zh.xml new file mode 100644 index 0000000..4ba293d --- /dev/null +++ b/reader/data/resources/zh.xml @@ -0,0 +1,683 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Chinese TDE-Ebook-Reader resources, by http://shucang.com/ --> +<resources> + <node name="libraryView"> + <node name="authorNode"> + <node name="expandTree" value="显示书ç±"/> + <node name="collapseTree" value="éšè—书ç±"/> + <node name="edit" value="编辑信æ¯"/> + <node name="unknownAuthor" value="佚å"/> + </node> + <node name="tagNode"> + <node name="expandTree" value="显示书ç±"/> + <node name="collapseTree" value="éšè—书ç±"/> + <node name="edit" value="ç¼–è¾‘æ ‡ç¾"/> + <node name="clone" value="å¤åˆ¶æ ‡ç¾"/> + <node name="delete" value="åˆ é™¤æ ‡ç¾"/> + <node name="noTags" value="æ— æ ‡ç¾ä¹¦ç±"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="显示书ç±"/> + <node name="collapseTree" value="éšè—书ç±"/> + </node> + <node name="bookNode"> + <node name="read" value="阅读书ç±"/> + <node name="edit" value="编辑信æ¯"/> + <node name="delete" value="åˆ é™¤ä¹¦ç±"/> + </node> + </node> + <node name="networkView"> + <node name="byAuthor" value="作者"> + <node name="summary" value="以作者排åº"/> + </node> + <node name="byTitle" value="書å"> + <node name="summary" value="ä»¥æ›¸åæŽ’åº"/> + </node> + <node name="byDate" value="日期"> + <node name="summary" value="以購書日期排åº"/> + </node> + <node name="bySeries" value="系列"> + <node name="summary" value="以系列排åº"/> + </node> + <node name="libraryItemNode"> + <node name="expandTree" value="展开"/> + <node name="collapseTree" value="折å "/> + <node name="reload" value="釿–°åŠ è½½"/> + <node name="openInBrowser" value="打开æµè§ˆå™¨"/> + </node> + <node name="libraryItemRootNode"> + <node name="expandTree" value="打开目录"/> + <node name="collapseTree" value="å…³é—目录"/> + <node name="login" value="登录"/> + <node name="logout" value="退出 (%s)"/> + <node name="reload" value="釿–°åŠ è½½"/> + <node name="dontShow" value="䏿˜¾ç¤ºè¯¥ç›®å½•"/> + <node name="topupAccount" value="釿–°è¾“入账å·(ç›®å‰: %s)"/> + <node name="register" value="注册"/> + <node name="passwordRecovery" value="找回密ç "/> + </node> + <node name="searchResultNode"> + <node name="title" value="æœç´¢ç»“æžœ"/> + <node name="expandTree" value="显示结果"/> + <node name="collapseTree" value="éšè—结果"/> + </node> + <node name="authorNode"> + <node name="expandTree" value="显示书ç±"/> + <node name="collapseTree" value="éšè—书ç±"/> + </node> + <node name="seriesNode"> + <node name="expandTree" value="显示书ç±"/> + <node name="collapseTree" value="éšè—书ç±"/> + </node> + <node name="bookNode"> + <node name="read" value="阅读本地å˜ä¹¦"/> + <node name="delete" value="åˆ é™¤æœ¬åœ°å˜ä¹¦"/> + <node name="download" value="下载"/> + <node name="readDemo" value="è¯•è¯»ç« èŠ‚"/> + <node name="downloadDemo" value="试读下载"/> + <node name="demo" value="demo"/> + <node name="buy" value="è´ä¹° (%s)"/> + </node> + </node> + <node name="menu"> + <node name="bookInfo" value="书ç±ä¿¡æ¯..."/> + <node name="toc" value="目录"/> + <node name="showLibrary" value="打开书库"/> + <node name="showNetLibrary" toBeTranslated="true" value="Network library"/> + <node name="addBook" toBeTranslated="true" value="Open file..."/> + <node name="showRecent" toBeTranslated="true" value="Recent books"/> + <node name="library" value="书库"> + <node name="showLibrary" value="打开"/> + <node name="previousBook" value="上一本书"/> + <node name="showRecent" value="最近阅读"/> + <node name="addBook" value="æ·»åŠ ä¹¦ç±..."/> + <node name="showHelp" value="关于 TDE-Ebook-Reader"/> + </node> + <node name="gotoHome" value="跳转到文档开始"/> + <node name="gotoPageNumber" value="跳转到æŸé¡µ..."/> + <node name="gotoSectionStart" value="è·³è½¬åˆ°æ–‡ç« å¼€å§‹"/> + <node name="gotoSectionEnd" value="è·³è½¬åˆ°æ–‡ç« ç»“æŸ"/> + <node name="nextTOCSection" value="跳转到下一个目录"/> + <node name="previousTOCSection" value="跳转到上一个目录"/> + <node name="navigate" value="导航"> + <node name="gotoHome" value="跳转到文档开始"/> + <node name="gotoPageNumber" value="跳转到æŸé¡µ..."/> + <node name="gotoSectionStart" value="è·³è½¬åˆ°ç« èŠ‚å¼€å§‹"/> + <node name="gotoSectionEnd" value="è·³è½¬åˆ°ç« èŠ‚ç»“æŸ"/> + <node name="nextTOCSection" value="跳转到下一个目录项 "/> + <node name="previousTOCSection" value="回到上一个目录项"/> + <node name="undo" value="åŽé€€"/> + <node name="redo" value="å‰è¿›"/> + </node> + <node name="selection" value="选择"> + <node name="copyToClipboard" value="å¤åˆ¶åˆ°å‰ªè´´æ¿"/> + <node name="openInDictionary" value="从书库里打开"/> + <node name="clearSelection" value="清除"/> + </node> + <node name="search" value="查找"> + <node name="search" value="查找内容..."/> + <node name="findNext" value="查找下一个"/> + <node name="findPrevious" value="查找上一个"/> + </node> + <node name="view" value="视图"> + <node name="rotate" value="旋转å±å¹•"/> + <node name="toggleFullscreen" value="å…¨å±"/> + <node name="toggleIndicator" value="åˆ‡æ¢æŒ‡ç¤º"/> + </node> + <node name="preferences" toBeTranslated="true" value="Last Preferences Dialog..."/> + <node name="quit" value="å…³é—"/> + </node> + <node name="toolbar"> + <node name="showReading"> + <node name="label" value="显示阅读模å¼"/> + <node name="tooltip" value="显示阅读模å¼"/> + </node> + <node name="showLibrary"> + <node name="label" value="显示书库目录"/> + <node name="tooltip" value="显示书库目录"/> + <node name="popup" value="显示最新书ç±åˆ—表"/> + </node> + <node name="showRecent"> + <node name="label" value="显示最新的书ç±åˆ—表"/> + <node name="tooltip" value="显示最新的书ç±åˆ—表"/> + </node> + <node name="byAuthor"> + <node name="label" value="按作者显示书ç±"/> + <node name="tooltip" value="按作者显示书ç±"/> + </node> + <node name="byTag"> + <node name="label" value="æŒ‰æ ‡ç¾æ˜¾ç¤ºä¹¦ç±"/> + <node name="tooltip" value="æŒ‰æ ‡ç¾æ˜¾ç¤ºä¹¦ç±"/> + </node> + <node name="addBook"> + <node name="label" value="æ·»åŠ ä¹¦ç±åˆ°ä¹¦åº“"/> + <node name="tooltip" value="æ·»åŠ ä¹¦ç±åˆ°ä¹¦åº“"/> + </node> + <node name="showNetLibrary"> + <node name="label" value="åœ¨ç½‘ç»œä¹¦åº“ä¸æœç´¢"/> + <node name="tooltip" value="åœ¨ç½‘ç»œä¹¦åº“ä¸æœç´¢"/> + </node> + <node name="searchOnNetwork"> + <node name="label" value="网络æœç´¢"/> + <node name="tooltip" value="网络æœç´¢"/> + </node> + <node name="advancedSearchOnNetwork"> + <node name="label" value="高级网络æœç´¢"/> + <node name="tooltip" value="高级网络æœç´¢"/> + </node> + <node name="gotoHome"> + <node name="label" value="åˆ°æ£æ–‡èµ·å§‹å¤„"/> + <node name="tooltip" value="åˆ°æ£æ–‡èµ·å§‹å¤„"/> + </node> + <node name="undo"> + <node name="label" value="åŽé€€"/> + <node name="tooltip" value="åŽé€€"/> + </node> + <node name="redo"> + <node name="label" value="å‰è¿›"/> + <node name="tooltip" value="å‰è¿›"/> + </node> + <node name="gotoPageNumberWithParameter"> + <node name="label" value="跳转到指定页"/> + <node name="tooltip" value="跳转到指定页"/> + </node> + <node name="toc"> + <node name="label" value="目录"/> + <node name="tooltip" value="目录"/> + </node> + <node name="search"> + <node name="label" value="全文æœç´¢"/> + <node name="tooltip" value="全文æœç´¢"/> + </node> + <node name="findNext"> + <node name="label" value="查找下一个"/> + <node name="tooltip" value="查找下一个"/> + </node> + <node name="findPrevious"> + <node name="label" value="查找上一个"/> + <node name="tooltip" value="查找上一个"/> + </node> + <node name="rotate"> + <node name="label" value="旋转"/> + <node name="tooltip" value="旋转"/> + </node> + <node name="showHelp"> + <node name="label" value="关于 TDE-Ebook-Reader"/> + <node name="tooltip" value="关于 TDE-Ebook-Reader"/> + </node> + <node name="filterLibrary"> + <node name="label" value="ç›é€‰"/> + <node name="tooltip" value="ç›é€‰"/> + </node> + <node name="preferences"> + <node name="label" toBeTranslated="true" value="Last Preferences Dialog"/> + <node name="tooltip" toBeTranslated="true" value="Show Last Opened Preferences Dialog"/> + </node> + <node name="bookInfo"> + <node name="label" value="书ç±ä¿¡æ¯"/> + <node name="tooltip" value="书ç±ä¿¡æ¯"/> + </node> + <node name="libraryOptions"> + <node name="label" toBeTranslated="true" value="Library Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Library Preferences Dialog"/> + </node> + <node name="networkOptions"> + <node name="label" toBeTranslated="true" value="Network Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Network Preferences Dialog"/> + </node> + <node name="systemOptions"> + <node name="label" toBeTranslated="true" value="System Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show System Preferences Dialog"/> + </node> + <node name="readingOptions"> + <node name="label" toBeTranslated="true" value="Reading Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Reading Preferences Dialog"/> + </node> + <node name="lookAndFeelOptions"> + <node name="label" toBeTranslated="true" value="Look & Feel Preferences"/> + <node name="tooltip" toBeTranslated="true" value="Show Look & Feel Preferences Dialog"/> + </node> + </node> + <node name="dialog"> + <node name="button"> + <node name="go" value="&开始"/> + <node name="thisOnly" value="这仅仅"/> + <node name="withSubtags" value="å¸¦æœ‰åæ ‡ç¾"/> + <node name="removeLink" value="从书库ä¸åˆ 除"/> + <node name="removeFile" value="从ç£ç›˜ä¸åˆ 除"/> + <node name="yesToAll" value="å…¨éƒ¨åˆ é™¤"/> + <node name="buy" value="&è´ä¹°"/> + <node name="buyAndDownload" value="è´ä¹° &下载"/> + </node> + <node name="LibraryOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Library Options"/> + <node name="tab"> + <node name="Library" value="书库"> + <node name="bookPath" value="书ç±è·¯å¾„"/> + <node name="lookInSubdirectories" value="在åç›®å½•ä¸æŸ¥æ‰¾ä¹¦ç±"/> + <node name="collectBooksWithoutMetaInfo" value="è—ä¹¦æ— ç›¸å…³æè¿°"/> + <node name="downloadDirectory" value="书ç±ä¸‹è½½å˜æ”¾ç›®å½•"/> + </node> + </node> + </node> + <node name="NetworkOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Network Options"/> + <node name="tab"> + <node name="NetworkLibrary" value="网络æœç´¢"> + </node> + <node name="Connection" value="Connection"> + <node name="useProxy" value="ä½¿ç”¨ä»£ç†æœåС噍"/> + <node name="proxyHost" value="代ç†ä¸»æœº"/> + <node name="proxyPort" value="代ç†ç«¯å£"/> + <node name="timeout" value="网络æ“作超时,秒"/> + </node> + <node name="Web" value="网页"> + <node name="enableIntegration" value="在%s打开外部链接"/> + <node name="defaultText" value="在æµè§ˆå™¨æ‰“开外部链接"/> + <node name="choice" value="使用æµè§ˆå™¨"/> + <node name="command" value="执行命令"/> + </node> + </node> + </node> + <node name="SystemOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - System Options"/> + <node name="tab"> + <node name="Language" value="è¯è¨€"> + <node name="autoDetect" value="自动检测è¯è¨€å’Œç¼–ç "/> + <node name="defaultLanguage" value="默认è¯è¨€"/> + <node name="defaultEncodingSet" value="默认编ç 设置"/> + <node name="defaultEncoding" value="默认编ç "/> + <node name="useWindows1252Hack" value="使用windows-1252 代替iso-8859-1"/> + </node> + <node name="Config" value="é…ç½®"> + <node name="autoSave" value="自动ä¿å˜"/> + <node name="timeout" value="ä¿å˜è¶…时,秒"/> + </node> + <node name="Dictionary" value="å—å…¸"> + <node name="enableIntegration" value="å…许整åˆ%s"/> + <node name="defaultText" value="å…许整åˆå—å…¸"/> + <node name="choice" value="æ•´åˆ"/> + <node name="singleClickOpen" value="å•击打开"/> + </node> + <node name="Maemo" value="Maemoå¹³å°"> + <node name="keyActionOnRelease" value="在放开时执行"/> + <node name="minStylusPressure" value="最å°ç¬”触压"/> + <node name="maxStylusPressure" value="最大笔触压"/> + </node> + </node> + </node> + <node name="ReadingOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Reading Options"/> + <node name="tab"> + <node name="Scrolling" value="滚动方å¼"> + <node name="keyScrollDelay" value="按键滚动间的延迟, 兆秒"/> + <node name="keyLinesToScroll" value="行滚动时的行数"/> + <node name="keyLinesToKeep" value="翻页时ä¿ç•™è¡Œæ•°"/> + <node name="enableTapScrolling" value="å…许Tap键滚动"/> + <node name="fingerOnly" value="仅陿‰‹åŠ¨æ»šåŠ¨"/> + </node> + <node name="Selection" value="选择项"> + <node name="enableSelection" value="å…许文本选择"/> + </node> + <node name="Indicator" value="进度æ¡"> + <node name="type" value="显示"> + <node name="osScrollbar" value="OS 滚动æ¡"/> + <node name="fbIndicator" value="è€å¼è¿›åº¦æ¡"/> + <node name="none" value="䏿˜¾ç¤º"/> + </node> + <node name="height" value="进度æ¡é«˜åº¦"/> + <node name="offset" value="å离文本"/> + <node name="pageNumber" value="ç”¨æ•°å—æ˜¾ç¤ºå½“å‰ä½ç½®"/> + <node name="time" value="显示时间"/> + <node name="fontSize" value="å—体大å°"/> + <node name="tocMarks" value="æ˜¾ç¤ºç›®å½•æ ‡è®°"/> + <node name="navigation" value="å¯ç”¨å¯¼èˆª"/> + </node> + <node name="Rotation" value="旋转"> + <node name="direction" value="旋转方å‘"> + <node name="disabled" value="ç¦ç”¨"/> + <node name="clockwise" value="顺时针转90度"/> + <node name="counterclockwise" value="逆时针转90度"/> + <node name="180" value="180度"/> + <node name="cycle" value="便¬¡æ—‹è½¬4个方å‘"/> + </node> + </node> + <node name="Keys" value="按键"> + <node name="grabSystemKeys" value="抓系统键"/> + <node name="separate" value="ä¾èµ–ä¸åŒä½ç½®è®¾å®šå¿«æ·é”®"/> + <node name="orientation" value="æ–¹ä½"> + <node name="degrees0" value="0度"/> + <node name="degrees90ccw" value="逆时针90度"/> + <node name="degrees180" value="180度"/> + <node name="degrees90cw" value="顺时针90度"/> + </node> + <node name="action"> + <node name="none" value="没有"/> + <node name="showLibrary" value="显示书库"/> + <node name="showNetLibrary" value="显示网络书库"/> + <node name="showRecent" value="显示最新书ç±"/> + <node name="previousBook" value="打开上一本书"/> + <node name="toc" value="显示目录"/> + <node name="gotoHome" value="返回书ç±èµ·å§‹"/> + <node name="gotoSectionStart" value="è·³åˆ°ç« èŠ‚å¼€å§‹"/> + <node name="gotoSectionEnd" value="è·³åˆ°ç« èŠ‚æœ«å°¾"/> + <node name="nextTOCSection" value="跳到下一个目录项"/> + <node name="previousTOCSection" value="回到上一个目录项"/> + <node name="pageForward" value="å‘å‰ç¿»é¡µ"/> + <node name="pageBackward" value="å‘åŽç¿»é¡µ"/> + <node name="lineForward" value="å‘剿»šåŠ¨è¡Œ"/> + <node name="lineBackward" value="å‘åŽæ»šåŠ¨è¡Œ"/> + <node name="undo" value="撤销"/> + <node name="redo" value="é‡åš"/> + <node name="copyToClipboard" value="å¤åˆ¶å‰ªè´´æ¿"/> + <node name="openInDictionary" value="在å—兏䏿Ÿ¥è¯¢"/> + <node name="clearSelection" value="清除选项"/> + <node name="search" value="æœç´¢"/> + <node name="findPrevious" value="查找上一个"/> + <node name="findNext" value="查找下一个"/> + <node name="increaseFont" value="å—ä½“åŠ å¤§"/> + <node name="decreaseFont" value="å—体缩å°"/> + <node name="toggleIndicator" value="切æ¢è¿›åº¦æ¡"/> + <node name="toggleFullscreen" value="切æ¢åˆ°å…¨å±æ¨¡å¼"/> + <node name="rotate" value="旋转å±å¹•"/> + <node name="addBook" value="æ·»åŠ ä¹¦ç±"/> + <node name="cancel" value="å–æ¶ˆ"/> + <node name="quit" value="退出"/> + <node name="bookInfo" value="显示书ç±ä¿¡æ¯å¯¹è¯æ¡†"/> + <node name="preferences" toBeTranslated="true" value="Show last opened preferences dialog"/> + </node> + <node name="quitOnCancel" value="æŒ‰å–æ¶ˆé€€å‡ºç¨‹åº"/> + <node name="keyDelay" value="有效按键之间的延迟"/> + </node> + </node> + </node> + <node name="LookAndFeelOptionsDialog"> + <node name="title" toBeTranslated="true" value="TDE-Ebook-Reader - Look & Feel Options"/> + <node name="tab"> + <node name="CSS" value="CSS"> + <node name="overrideSpecifiedFonts" value="始终用自己的å—体"/> + </node> + <node name="Margins" value="è¾¹è·"> + <node name="left" value="左边è·"/> + <node name="right" value="å³è¾¹è·"/> + <node name="top" value="é¡¶è¾¹è·"/> + <node name="bottom" value="底边è·"/> + </node> + <node name="Format" value="æ ¼å¼"> + <node name="optionsFor" value="设置"/> + <node name="lineSpacing" value="行间è·"> + <node name="unchanged" value="<ä¸å¯å˜>"/> + </node> + <node name="firstLineIndent" value="首行缩进"/> + <node name="alignment" value="对é½"> + <node name="left" value="å·¦"/> + <node name="right" value="å³"/> + <node name="center" value="å±…ä¸"/> + <node name="justify" value="对é½"/> + <node name="unchanged" value="<ä¸å˜>"/> + </node> + <node name="spaceBefore" value="å‰é—´è·"/> + <node name="spaceAfter" value="åŽé—´è·"/> + <node name="startIndent" value="行首缩进"/> + <node name="endIndent" value="行末缩进"/> + </node> + <node name="Styles" value="æ ·å¼"> + <node name="optionsFor" value="选项"/> + <node name="fontFamily" value="å—体"> + <node name="unchanged" value="<ä¸å˜>"/> + </node> + <node name="fontSize" value="大å°"/> + <node name="fontSizeDifference" value="大å°å·®å¼‚"/> + <node name="bold" value="åŠ ç²—"/> + <node name="italic" value="倾斜"/> + <node name="allowHyphenations" value="å…许æ–å—"/> + <node name="autoHyphenations" value="自动æ–å—"/> + </node> + <node name="Colors" value="颜色"> + <node name="colorFor" value="颜色设置"> + <node name="background" value="背景色"/> + <node name="selectionBackground" value="选择背景色"/> + <node name="text" value="普通文本"/> + <node name="internalLink" value="内部超链接文å—"/> + <node name="externalLink" value="外部超链接文å—"/> + <node name="bookLink" value="书ç±é“¾æŽ¥"/> + <node name="highlighted" value="高亮显示的文å—"/> + <node name="treeLines" value="æ ‘çŠ¶çº¿"/> + <node name="indicator" value="进度æ¡"/> + </node> + </node> + </node> + </node> + <node name="InfoDialog"> + <node name="title" value="TDE-Ebook-Reader - 书ç±ä¿¡æ¯"/> + <node name="tab"> + <node name="Common" value="通用"> + <node name="file" value="文件"/> + <node name="title" value="书å"/> + <node name="language" value="è¯è¨€"/> + <node name="encodingSet" value="ç¼–ç 集"/> + <node name="encoding" value="ç¼–ç "/> + </node> + <node name="Authors" value="Authors"> + <node name="authorDisplayName" value="作者 (显示姓å)"/> + </node> + <node name="Series" value="系列"> + <node name="seriesTitle" value="书ç±ç³»åˆ—åç§°"/> + <node name="bookIndex" value="书ç±ç¼–å·"/> + </node> + <node name="Tags" value="æ ‡ç¾"> + <node name="tags" value="æ ‡ç¾åˆ—表"/> + </node> + <node name="Text" value="æ£æ–‡"> + <node name="breakType" value="分段"/> + <node name="ignoreIndent" value="忽略缩进å°äºŽ..."/> + <node name="buildTOC" value="创建目录"/> + <node name="emptyLines" value="æ–°ç« èŠ‚å‰çš„空行"/> + </node> + <node name="<PRE>" value="<PRE>"> + <node name="breakType" value="分段è½"/> + <node name="ignoreIndent" value="忽略缩进å°äºŽ..."/> + <node name="buildTOC" value="创建目录"/> + <node name="emptyLines" value="æ–°ç« èŠ‚å‰çš„空行"/> + </node> + </node> + </node> + <node name="AuthorInfoDialog"> + <node name="title" value="TDE-Ebook-Reader - 作者信æ¯"/> + <node name="name" value="作家åå—"/> + <node name="sortKey" value="作家分类键"/> + </node> + <node name="addFileDialog"> + <node name="title" value="TDE-Ebook-Reader - æ·»åŠ ä¹¦ç±åˆ°ä¹¦åº“"/> + </node> + <node name="textSearchDialog"> + <node name="title" value="全文æœç´¢"/> + <node name="text" value=""/> + <node name="ignoreCase" value="&忽略大å°å†™"/> + <node name="wholeText" value="&在全文里"/> + <node name="backward" value="&å‘åŽ"/> + <node name="currentSection" value="&æ¤ç« 节"/> + </node> + <node name="networkSearchDialog"> + <node name="title" value="网络æœç´¢"/> + <node name="titleAndSeries" value="æ ‡é¢˜/系列"/> + <node name="author" value="作者"/> + <node name="category" value="类别"/> + <node name="description" value="摘è¦"/> + <node name="annotation" value="æœç´¢ç»“æžœ: %s"/> + </node> + <node name="gotoPageDialog"> + <node name="title" value="跳转到æŸé¡µ"/> + <node name="pageNumber" value="跳转到页数"/> + </node> + <node name="editTagDialog"> + <node name="title" value="ç¼–è¾‘æ ‡ç¾"/> + <node name="name" value="æ ‡ç¾å"/> + <node name="includeSubtags" value="包å«åæ ‡ç¾"/> + </node> + <node name="cloneTagDialog"> + <node name="title" value="å¤åˆ¶æ ‡ç¾"/> + <node name="name" value="æ ‡ç¾å"/> + <node name="includeSubtags" value="包å«åæ ‡ç¾"/> + </node> + <node name="removeBookBox"> + <node name="title" value="åˆ é™¤ä¹¦ç±"/> + <node name="message" value="从书库ä¸åˆ é™¤ä¹¦ç± â€œ%s†?"/> + <node name="deleteFile" value="确认从ç£ç›˜ä¸åˆ 除 “%s†文件?"/> + </node> + <node name="removeTagBox"> + <node name="title" value="åˆ é™¤æ ‡ç¾"/> + <node name="message" value="åˆ é™¤æ ‡ç¾ â€œ%sâ€?"/> + </node> + <node name="openBookErrorBox"> + <node name="title" value="错误"/> + <node name="message" value="æ— æ³•æ‰“å¼€: %s"/> + </node> + <node name="removeFileErrorBox"> + <node name="title" value="错误"/> + <node name="message" value="æ— æ³•åˆ é™¤æ–‡ä»¶%s"/> + </node> + <node name="noHelpBox"> + <node name="title" value="错误"/> + <node name="message" value="抱æ‰ï¼Œæœªæ‰¾åˆ°å¸®åŠ©æ–‡ä»¶"/> + </node> + <node name="networkError"> + <node name="emptyLibrariesList" value="空的书库列表"/> + <node name="authenticationFailed" value="æ— æ³•è¾¨è¯†"/> + <node name="internalError" value="内部æœåŠ¡å™¨å‡ºé”™"/> + <node name="purchaseNotEnoughMoney" value="ä½™é¢ä¸è¶³"/> + <node name="purchaseMissingBook" value="缺失书ç±"/> + <node name="purchaseAlreadyPurchased" value="å·²è´ä¹°ä¹¦ç±"/> + <node name="bookNotPurchased" value="未è´ä¹°ä¹¦ç±"/> + <node name="downloadLimitExceeded" value="超过下载é™åˆ¶"/> + <node name="unsupportedOperation" value="éžæ³•æ“作"/> + <node name="loginAlreadyTaken" value="用户åå·²ç»å˜åœ¨"/> + <node name="loginNotSpecified" value="请输入用户å"/> + <node name="passwordNotSpecified" value="请输入密ç "/> + <node name="emailNotSpecified" value="è¯·è¾“å…¥ä½ çš„ç”µå邮箱"/> + <node name="invalidEMail" value="æ— æ•ˆçš„ç”µå邮箱"/> + <node name="tooManyRegistrations" value="æ¥è‡ªä½ çš„IP的注册数过多, 请ç¨å€™å†å°è¯•注册"/> + <node name="noUserEmail" value="ä½ çš„ç”µå邮箱å¯ä»¥æ³¨å†Œ "/> + <node name="librariesListDownloadingFailed" value="Downloading list of network libraries failed" toBeTranslated="false"/> + </node> + <node name="downloadError"> + <node name="title" value="下载出现错误"/> + <node name="message" value="çŽ°åœ¨æ— æ³•ä¸‹è½½æ¤ä¹¦"/> + </node> + <node name="waitMessage"> + <node name="loadingBook" value="书ç±åŠ è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="loadingBookList" value="书ç±åˆ—è¡¨åŠ è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="migrate" value="æ£åœ¨å‡çº§åˆ°æ–°ç‰ˆæœ¬ï¼Œè¯·ç‰å¾…..."/> + <node name="downloadBookList" value="下载书ç±åˆ—表,请ç‰å¾…..."/> + <node name="downloadBook" value="书ç±ä¸‹è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="downloadImages" value="图åƒä¸‹è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="authentication" value="验è¯ä¸.请ç‰å¾…..."/> + <node name="purchaseBook" value="书ç±è´ä¹°ä¸. 请ç‰å¾…..."/> + <node name="initializeAuthenticationManager" value="账户信æ¯ä¸‹è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="loadSubCatalog" value="ç›®å½•ä¼ è½½ä¸ï¼Œè¯·ç‰å¾…..."/> + <node name="registerUser" value="æ£åœ¨æ³¨å†Œæ–°è´¦å·ï¼Œè¯·ç¨ç‰..."/> + <node name="passwordRecovery" value="请求找回密ç ä¸ï¼Œè¯·ç¨ç‰..."/> + <node name="authenticationCheck" value="å¸å·éªŒè¯ä¸,请ç¨ç‰..."/> + <node name="signOut" value="退出. æ£åœ¨å¤„ç†,请ç¨ç‰..."/> + <node name="loadingNetworkLibraryList" value="Loading list of network libraries. Please, wait..." toBeTranslated="true"/> + </node> + <node name="purchaseConfirmBox"> + <node name="title" value="è´ä¹°ä¹¦ç±"/> + <node name="message" value="确认è´ä¹°%s书ç±?"/> + </node> + <node name="AuthenticationDialog"> + <node name="title" value="鉴定"/> + <node name="login" value="登录"/> + <node name="password" value="密ç "/> + <node name="skipIP" value="ä¸ç»‘定到IP地å€"/> + <node name="loginIsEmpty" value="用户åä¸å…许为空"/> + </node> + <node name="emptyCatalogBox"> + <node name="title" value="ä¿¡æ¯"/> + <node name="message" value="目录是空的."/> + </node> + <node name="dontShowConfirmBox"> + <node name="title" value="ç¦ç”¨ç›®å½•"/> + <node name="message" value="确定è¦ç¦ç”¨â€œ%sâ€ç›®å½•? å°†æ¥æ‚¨å¯ä»¥åœ¨é€‰é¡¹å¯¹è¯æ¡†ä¸çš„ “网络æœç´¢â€ æ ‡ç¾ é‡æ–°ä½¿ç”¨"/> + </node> + <node name="deleteLocalCopyBox"> + <node name="title" value="åˆ é™¤ä¹¦ç±"/> + <node name="message" value="ä½ ç¡®ä¿¡ è¦åˆ 除 “%s†书ç±ä¹ˆ ?"/> + </node> + <node name="RegisterUserDialog"> + <node name="title" value="注册用户"/> + <node name="login" value="用户å"/> + <node name="password" value="密ç "/> + <node name="confirmPassword" value="密ç 确认"/> + <node name="email" value="E-mail"/> + <node name="differentPasswords" value="密ç 和密ç 确认必须一致."/> + </node> + <node name="PasswordRecoveryDialog"> + <node name="title" value="找回密ç "/> + <node name="email" value="E-mail"/> + </node> + <node name="recoverySuccessfulBox"> + <node name="title" value="找回密ç "/> + <node name="message" value="下一æ¥å¦‚何æ“作的消æ¯å·²ç»å‘é€åˆ°ä½ ä¿¡ç®± ,请查收 %s"/> + </node> + <node name="cantOpenDownloadedFile"> + <node name="title" value="下载å‘生错误"/> + <node name="message" value="æ— æ³•æ‰“å¼€ä¸‹è½½çš„æ–‡æ¡£ %s."/> + </node> + </node> + <node name="style"> + <node name="Base" value="基础"/> + <node name="Regular Paragraph" value="è¿žç»æ®µè½"/> + <node name="Title" value="æ ‡é¢˜"/> + <node name="Section Title" value="ç« èŠ‚æ ‡é¢˜"/> + <node name="Poem Title" value="è¯—æ ‡é¢˜"/> + <node name="Subtitle" value="å‰¯æ ‡é¢˜"/> + <node name="Annotation" value="注释"/> + <node name="Epigraph" value="题è¯"/> + <node name="Stanza" value="节"/> + <node name="Verse" value="韵文"/> + <node name="Preformatted text" value="é¢„ç½®æ ¼å¼æ–‡æœ¬"/> + <node name="Image" value="图åƒ"/> + <node name="Cite" value="举例"/> + <node name="Author" value="作者"/> + <node name="Date" value="日期"/> + <node name="Internal Hyperlink" value="内部超链接"/> + <node name="Footnote" value="脚注"/> + <node name="Emphasis" value="é‡ç‚¹"/> + <node name="Strong" value="固定"/> + <node name="Subscript" value="ä¸‹æ ‡"/> + <node name="Superscript" value="ä¸Šæ ‡"/> + <node name="Code" value="ç¼–ç "/> + <node name="StrikeThrough" value="åˆ é™¤çº¿"/> + <node name="Contents Table" value="目录"/> + <node name="Library Entry" value="书库入å£"/> + <node name="Recent Book List" value="最近书ç±åˆ—表"/> + <node name="Italic" value="倾斜"/> + <node name="Bold" value="åŠ ç²—"/> + <node name="Definition" value="定义"/> + <node name="Definition Description" value="定义æè¿°"/> + <node name="Header 1" value="æ ‡é¢˜ 1"/> + <node name="Header 2" value="æ ‡é¢˜ 2"/> + <node name="Header 3" value="æ ‡é¢˜ 3"/> + <node name="Header 4" value="æ ‡é¢˜ 4"/> + <node name="Header 5" value="æ ‡é¢˜ 5"/> + <node name="Header 6" value="æ ‡é¢˜ 6"/> + <node name="External Hyperlink" value="外部超链接"/> + <node name="Link to Another Book" value="链接到å¦ä¸€æœ¬ä¹¦"/> + </node> + <node name="external"> + <node name="browser" value="æµè§ˆå™¨"/> + <node name="defaultBrowser" value="默认æµè§ˆå™¨"/> + </node> + <node name="mobipocketPlugin"> + <node name="unknown" value="未知的错误"/> + <node name="unsupportedCompressionMethod" value="䏿”¯æŒçš„压缩方法"/> + <node name="encryptedFile" value="å—版æƒä¿æŠ¤æ–‡ä»¶"/> + </node> + <node name="networkLibrary"> + <node name="caption" value="网络书库"/> + </node> + <node name="library"> + <node name="caption" value="书库"/> + </node> +</resources> diff --git a/reader/desktop/desktop b/reader/desktop/desktop new file mode 100644 index 0000000..8bdf367 --- /dev/null +++ b/reader/desktop/desktop @@ -0,0 +1,24 @@ +[Desktop Entry] +Name=TDE Ebook Reader +GenericName=E-book reader +GenericName[ar]=قارئ الكتب الإلكترونية +GenericName[es]=Lector de Libros +GenericName[hu]=E-könyv olvasó +GenericName[pl]=Czytnik e-książek +GenericName[ru]=Чтение Ñлектронных книг +GenericName[zh_CN]=电å书阅读 +Comment=TDE Ebook Reader +Comment[ar]=قارئ الكتب الإلكترونية +Comment[es]=TDE Ebook Reader Lector de Libros Elecrónicos +Comment[hu]=TDE Ebook Reader, E-könyv olvasó program +Comment[pl]=TDE Ebook Reader, czytnik książek elektronicznych +Comment[ru]=TDE Ebook Reader, программа Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñлектронных книг +Comment[zh_CN]=TDE Ebook Reader 电å书阅读器 +TryExec=tde-ebook-reader +Exec=tde-ebook-reader %F +StartupNotify=true +Terminal=false +Type=Application +Icon=TDEEbookReader +Categories=Office;Viewer;Literature; +MimeType=application/epub+zip; diff --git a/reader/desktop/tde-ebook-reader.1 b/reader/desktop/tde-ebook-reader.1 new file mode 100644 index 0000000..e6c7fe8 --- /dev/null +++ b/reader/desktop/tde-ebook-reader.1 @@ -0,0 +1,41 @@ +.TH TDE EBOOK READER 1 +.SH NAME +TDE e-book reader +.SH SYNOPSIS +.B tde-ebook-reader [\fB\-lang \fIlanguage\fP] [\fIe-book\fP] +.SH DESCRIPTION +tde-ebook-reader is an e-book reader. It supports most open e-book formats, and can +read compressed e-book archives. +.PP +For more information on using the program, see the "About TDE Ebook Reader" button +on its toolbar. +.SH OPTIONS +.TP +\fB-lang \fIlanguage\fP +Language for user interface. Current version (0.12.0) of tde-ebook-reader supports +Arabic (specify \fB\-lang ar\fP option), +Chinese (\fB\-lang zh\fP), +Czech (\fB\-lang cs\fP), +Dutch (\fB\-lang nl\fP), +English (\fB\-lang en\fP), +Finnish (\fB\-lang fi\fP), +French (\fB\-lang fr\fP), +German (\fB\-lang de\fP), +Hungarian (\fB\-lang hu\fP), +Indonesian (\fB\-lang id\fP), +Italian (\fB\-lang it\fP), +Lithuanian (\fB\-lang lt\fP), +Russian (\fB\-lang ru\fP), +Spanish (\fB\-lang es\fP) and +Swedish (\fB\-lang sv\fP) and +Ukrainian (\fB\-lang uk\fP). +.TP +\fIe-book\fP +Name of file to open. If this parameter is missing or if tde-ebook-reader cannot open +the specified file, the last opened file will be reopened. If you start tde-ebook-reader +for the first time or the last opened file is missing, "About TDE Ebook Reader" text +will be opened. +.SH AUTHOR +This man page was written by Joey Hess <joeyh@debian.org> and Nikolay Pultsin +<geometer@fbreader.org> for the Debian system, but may be freely reused on other +systems. diff --git a/reader/src/blockTree/ReaderNode.cpp b/reader/src/blockTree/ReaderNode.cpp new file mode 100644 index 0000000..cdca140 --- /dev/null +++ b/reader/src/blockTree/ReaderNode.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLibrary.h> +#include <ZLFileImage.h> + +#include "ReaderNode.h" + +#include "../reader/Reader.h" +#include "../options/FBOptions.h" +#include "../options/FBTextStyle.h" + +const ZLTypeId ReaderNode::TYPE_ID(ZLBlockTreeNode::TYPE_ID); + +class ReaderNode::ExpandTreeAction : public ZLRunnableWithKey { + +public: + ExpandTreeAction(ReaderNode &node); + void run(); + ZLResourceKey key() const; + +private: + ReaderNode &myNode; +}; + +std::map<std::string,shared_ptr<const ZLImage> > ReaderNode::ourDefaultCovers; + +ReaderNode::ReaderNode(ZLBlockTreeNode *parent, std::size_t atPosition) : ZLBlockTreeNode(parent, atPosition), myCoverImageIsStored(false), myIsInitialized(false) { +} + +void ReaderNode::init() { +} + +bool ReaderNode::highlighted() const { + return false; +} + +ReaderNode::~ReaderNode() { +} + +const ZLTypeId &ReaderNode::typeId() const { + return TYPE_ID; +} + +shared_ptr<const ZLImage> ReaderNode::coverImage() const { + if (!myCoverImageIsStored) { + myCoverImageIsStored = true; + myStoredCoverImage = extractCoverImage(); + } + return myStoredCoverImage; +} + +void ReaderNode::drawCover(ZLPaintContext &context, int vOffset) { + drawCoverReal(context, vOffset); +} + +void ReaderNode::drawCoverReal(ZLPaintContext &context, int vOffset) { + shared_ptr<const ZLImage> cover = coverImage(); + if (cover.isNull()) { + return; + } + + shared_ptr<ZLImageData> coverData = ZLImageManager::Instance().imageData(*cover); + if (coverData.isNull()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int h = unit * 9 / 2, w = h * 3 / 4; + vOffset += unit / 2; + const int hOffset = level() * unit * 3 - unit * 2; + + const int origWidth = context.imageWidth(*coverData); + const int origHeight = context.imageHeight(*coverData); + if (origWidth == 0 || origHeight == 0) { + return; + } + + int coeff = std::min(w / origWidth, h / origHeight); + if (coeff == 0) { + coeff = 1; + } + int width = coeff * origWidth; + int height = coeff * origHeight; + if (width > w || height > h) { + width = context.imageWidth(*coverData, w, h, ZLPaintContext::SCALE_REDUCE_SIZE); + height = context.imageHeight(*coverData, w, h, ZLPaintContext::SCALE_REDUCE_SIZE); + } + context.drawImage(hOffset + (w - width) / 2, vOffset + (h + height) / 2, *coverData, width, height, ZLPaintContext::SCALE_FIT_TO_SIZE); +} + +void ReaderNode::drawTitle(ZLPaintContext &context, int vOffset) { + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int hOffset = level() * unit * 3 + unit * 2; + + context.setColor(highlighted() ? + FBOptions::Instance().colorOption(ZLTextStyle::HIGHLIGHTED_TEXT).value() : + FBOptions::Instance().RegularTextColorOption.value()); + context.setFont(style.fontFamily(), style.fontSize(), style.bold(), style.italic()); + + const std::string text = title(); + context.drawString(hOffset, vOffset + 2 * unit, text.data(), text.size(), false); +} + +void ReaderNode::drawSummary(ZLPaintContext &context, int vOffset) { + const std::string text = summary(); + if (text.empty()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int hOffset = level() * unit * 3 + unit * 2; + + context.setColor(highlighted() ? + FBOptions::Instance().colorOption(ZLTextStyle::HIGHLIGHTED_TEXT).value() : + FBOptions::Instance().RegularTextColorOption.value()); + context.setFont(style.fontFamily(), style.fontSize() * 2 / 3, style.bold(), style.italic()); + + context.drawString(hOffset, vOffset + 13 * unit / 4, text.data(), text.size(), false); +} + +void ReaderNode::drawHyperlink(ZLPaintContext &context, int &hOffset, int &vOffset, shared_ptr<ZLRunnableWithKey> action, bool auxiliary) { + // auxiliary makes font size and hSkip to be 70% of their normal sizes + if (action.isNull() || !action->makesSense()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int h = auxiliary ? (unit * 11 / 2) : (unit * 9 / 2); + const int left = hOffset + level() * unit * 3 + unit * 2; + + context.setColor(FBOptions::Instance().colorOption("internal").value()); + context.setFont( + style.fontFamily(), + auxiliary ? (7 * style.fontSize() / 15) : (style.fontSize() * 2 / 3), + style.bold(), + style.italic() + ); + + const std::string text = action->text(resource()); + const int stringW = context.stringWidth(text.data(), text.size(), false); + const int stringH = context.stringHeight(); + context.drawString(left, vOffset + h, text.data(), text.size(), false); + addHyperlink(left, h - stringH, left + stringW, h, action); + hOffset += stringW + 4 * context.spaceWidth(); +} + +ReaderNode::ExpandTreeAction::ExpandTreeAction(ReaderNode &node) : myNode(node) { +} + +void ReaderNode::ExpandTreeAction::run() { + myNode.expandOrCollapseSubtree(); + Reader::Instance().refreshWindow(); +} + +ZLResourceKey ReaderNode::ExpandTreeAction::key() const { + return ZLResourceKey(myNode.isOpen() ? "collapseTree" : "expandTree"); +} + +void ReaderNode::expandOrCollapseSubtree() { + if (isOpen()) { + open(false); + } else if (!children().empty()) { + open(true); + if (view().visibilityMode(this) != ZLBlockTreeView::INVISIBLE) { + ZLBlockTreeNode *lastChild = children().back(); + while (view().visibilityMode(lastChild) != ZLBlockTreeView::VISIBLE && + this != view().firstVisibleNode()) { + view().setFirstVisibleNode(view().firstVisibleNode()->next()); + } + } + } +} + +void ReaderNode::registerAction(shared_ptr<ZLRunnableWithKey> action, bool auxiliary) { + if (!action.isNull()) { + myActions.push_back(std::make_pair(action, auxiliary)); + } +} + +void ReaderNode::registerExpandTreeAction() { + registerAction(new ExpandTreeAction(*this)); +} + +shared_ptr<const ZLImage> ReaderNode::defaultCoverImage(const std::string &id) { + shared_ptr<const ZLImage> cover = ourDefaultCovers[id]; + if (cover.isNull()) { + cover = new ZLFileImage( + ZLFile(ZLibrary::ApplicationImageDirectory() + ZLibrary::FileNameDelimiter + id), 0 + ); + ourDefaultCovers[id] = cover; + } + return cover; +} + +int ReaderNode::height(ZLPaintContext &context) const { + bool hasAuxHyperlink = false; + for (std::vector<std::pair<shared_ptr<ZLRunnableWithKey>,bool> >::const_iterator it = myActions.begin(); it != myActions.end(); ++it) { + if (it->second && it->first->makesSense()) { + hasAuxHyperlink = true; + break; + } + } + return + unitSize(context, FBTextStyle::Instance()) * + (hasAuxHyperlink ? 13 : 11) / 2; +} + +int ReaderNode::unitSize(ZLPaintContext &context, const FBTextStyle &style) const { + context.setFont(style.fontFamily(), style.fontSize(), style.bold(), style.italic()); + return (context.stringHeight() * 2 + 2) / 3; +} + +std::string ReaderNode::summary() const { + std::string result; + int count = 0; + const ZLBlockTreeNode::List &subNodes = children(); + ZLBlockTreeNode::List::const_iterator it = subNodes.begin(); + for (; it != subNodes.end() && count < 3; ++it, ++count) { + if (count > 0) { + result += ", "; + } + result += ((const ReaderNode*)*it)->title(); + } + if (it != subNodes.end()) { + result += ", ..."; + } + return result; +} + +void ReaderNode::paint(ZLPaintContext &context, int vOffset) { + if (!myIsInitialized) { + init(); + myIsInitialized = true; + } + + removeAllHyperlinks(); + + drawCover(context, vOffset); + drawTitle(context, vOffset); + drawSummary(context, vOffset); + + int left = 0; + int auxLeft = 0; + for (std::vector<std::pair<shared_ptr<ZLRunnableWithKey>,bool> >::const_iterator it = myActions.begin(); it != myActions.end(); ++it) { + if (it->first->makesSense()) { + if (it->second) { + drawHyperlink(context, auxLeft, vOffset, it->first, true); + } else { + drawHyperlink(context, left, vOffset, it->first); + } + } + } +} diff --git a/reader/src/blockTree/ReaderNode.h b/reader/src/blockTree/ReaderNode.h new file mode 100644 index 0000000..8abb7a1 --- /dev/null +++ b/reader/src/blockTree/ReaderNode.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __READERNODE_H__ +#define __READERNODE_H__ + +#include <map> +#include <vector> + +#include <ZLBlockTreeView.h> + +class ZLImage; +class ZLResource; +class FBTextStyle; + +class ReaderNode : public ZLBlockTreeNode { + +protected: + static shared_ptr<const ZLImage> defaultCoverImage(const std::string &id); + +private: + static std::map<std::string,shared_ptr<const ZLImage> > ourDefaultCovers; + +private: + class ExpandTreeAction; + +public: + static const ZLTypeId TYPE_ID; + +protected: + ReaderNode(ZLBlockTreeNode *parent, std::size_t atPosition = (std::size_t)-1); + virtual void init(); + virtual const ZLResource &resource() const = 0; + virtual bool highlighted() const; + +public: + ~ReaderNode(); + + void drawCoverReal(ZLPaintContext &context, int vOffset); + +protected: + virtual void drawCover(ZLPaintContext &context, int vOffset); + void drawTitle(ZLPaintContext &context, int vOffset); + void drawSummary(ZLPaintContext &context, int vOffset); + void drawHyperlink(ZLPaintContext &context, int &hOffset, int &vOffset, shared_ptr<ZLRunnableWithKey> action, bool auxiliary = false); + +private: + int unitSize(ZLPaintContext &context, const FBTextStyle &style) const; + +protected: + void paint(ZLPaintContext &context, int vOffset); + void registerAction(shared_ptr<ZLRunnableWithKey> action, bool auxiliary = false); + void registerExpandTreeAction(); + virtual shared_ptr<const ZLImage> extractCoverImage() const = 0; + +private: + const ZLTypeId &typeId() const; + +public: + shared_ptr<const ZLImage> coverImage() const; + virtual std::string title() const = 0; + virtual std::string summary() const; + + void expandOrCollapseSubtree(); + +protected: + int height(ZLPaintContext &context) const; + +private: + mutable bool myCoverImageIsStored; + mutable shared_ptr<const ZLImage> myStoredCoverImage; + std::vector<std::pair<shared_ptr<ZLRunnableWithKey>,bool> > myActions; + bool myIsInitialized; +}; + +#endif /* __READERNODE_H__ */ diff --git a/reader/src/bookmodel/BookModel.cpp b/reader/src/bookmodel/BookModel.cpp new file mode 100644 index 0000000..2123282 --- /dev/null +++ b/reader/src/bookmodel/BookModel.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLImage.h> +#include <ZLFile.h> + +#include "BookModel.h" +#include "BookReader.h" + +#include "../formats/FormatPlugin.h" +#include "../library/Book.h" + +BookModel::BookModel(const shared_ptr<Book> book) : myBook(book) { + myBookTextModel = new ZLTextPlainModel(book->language(), 102400); + myContentsModel = new ContentsModel(book->language()); + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(book->file(), false); + if (!plugin.isNull()) { + plugin->readModel(*this); + } +} + +BookModel::~BookModel() { +} + +void BookModel::setHyperlinkMatcher(shared_ptr<HyperlinkMatcher> matcher) { + myHyperlinkMatcher = matcher; +} + +BookModel::Label BookModel::label(const std::string &id) const { + if (!myHyperlinkMatcher.isNull()) { + return myHyperlinkMatcher->match(myInternalHyperlinks, id); + } + + std::map<std::string,Label>::const_iterator it = myInternalHyperlinks.find(id); + return (it != myInternalHyperlinks.end()) ? it->second : Label(0, -1); +} + +ContentsModel::ContentsModel(const std::string &language) : ZLTextTreeModel(language) { +} + +void ContentsModel::setReference(const ZLTextTreeParagraph *paragraph, int reference) { + myReferenceByParagraph[paragraph] = reference; +} + +int ContentsModel::reference(const ZLTextTreeParagraph *paragraph) const { + std::map<const ZLTextTreeParagraph*,int>::const_iterator it = myReferenceByParagraph.find(paragraph); + return (it != myReferenceByParagraph.end()) ? it->second : -1; +} + +const shared_ptr<Book> BookModel::book() const { + return myBook; +} diff --git a/reader/src/bookmodel/BookModel.h b/reader/src/bookmodel/BookModel.h new file mode 100644 index 0000000..6f83728 --- /dev/null +++ b/reader/src/bookmodel/BookModel.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKMODEL_H__ +#define __BOOKMODEL_H__ + +#include <map> +#include <string> + +#include <ZLTextModel.h> +#include <ZLTextParagraph.h> +#include <ZLUserData.h> + +class ZLImage; +class Book; + +class ContentsModel : public ZLTextTreeModel { + +public: + ContentsModel(const std::string &language); + void setReference(const ZLTextTreeParagraph *paragraph, int reference); + int reference(const ZLTextTreeParagraph *paragraph) const; + +private: + std::map<const ZLTextTreeParagraph*,int> myReferenceByParagraph; +}; + +class BookModel : public ZLUserDataHolder { + +public: + struct Label { + Label(shared_ptr<ZLTextModel> model, int paragraphNumber) : Model(model), ParagraphNumber(paragraphNumber) {} + + const shared_ptr<ZLTextModel> Model; + const int ParagraphNumber; + }; + +public: + class HyperlinkMatcher { + + public: + virtual Label match(const std::map<std::string,Label> &lMap, const std::string &id) const = 0; + }; + +public: + BookModel(const shared_ptr<Book> book); + ~BookModel(); + + void setHyperlinkMatcher(shared_ptr<HyperlinkMatcher> matcher); + + shared_ptr<ZLTextModel> bookTextModel() const; + shared_ptr<ZLTextModel> contentsModel() const; + + const ZLImageMap &imageMap() const; + Label label(const std::string &id) const; + + const shared_ptr<Book> book() const; + +private: + const shared_ptr<Book> myBook; + shared_ptr<ZLTextModel> myBookTextModel; + shared_ptr<ZLTextModel> myContentsModel; + ZLImageMap myImages; + std::map<std::string,shared_ptr<ZLTextModel> > myFootnotes; + std::map<std::string,Label> myInternalHyperlinks; + shared_ptr<HyperlinkMatcher> myHyperlinkMatcher; + +friend class BookReader; +}; + +inline shared_ptr<ZLTextModel> BookModel::bookTextModel() const { return myBookTextModel; } +inline shared_ptr<ZLTextModel> BookModel::contentsModel() const { return myContentsModel; } +inline const ZLImageMap &BookModel::imageMap() const { return myImages; } + +#endif /* __BOOKMODEL_H__ */ diff --git a/reader/src/bookmodel/BookReader.cpp b/reader/src/bookmodel/BookReader.cpp new file mode 100644 index 0000000..2982c43 --- /dev/null +++ b/reader/src/bookmodel/BookReader.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLImage.h> +#include <ZLLogger.h> +#include <ZLTextStyleEntry.h> + +#include "BookReader.h" +#include "BookModel.h" + +#include "../library/Book.h" + +BookReader::BookReader(BookModel &model) : myModel(model) { + myCurrentTextModel = 0; + myLastTOCParagraphIsEmpty = false; + + myContentsParagraphExists = false; + + myInsideTitle = false; + mySectionContainsRegularContents = false; +} + +BookReader::~BookReader() { +} + +void BookReader::setMainTextModel() { + myCurrentTextModel = myModel.myBookTextModel; +} + +void BookReader::setFootnoteTextModel(const std::string &id) { + std::map<std::string,shared_ptr<ZLTextModel> >::iterator it = myModel.myFootnotes.find(id); + if (it != myModel.myFootnotes.end()) { + myCurrentTextModel = (*it).second; + } else { + myCurrentTextModel = new ZLTextPlainModel(myModel.myBookTextModel->language(), 8192); + myModel.myFootnotes.insert(std::make_pair(id, myCurrentTextModel)); + } +} + +bool BookReader::paragraphIsOpen() const { + if (myCurrentTextModel.isNull()) { + return false; + } + for (std::list<shared_ptr<ZLTextModel> >::const_iterator it = myModelsWithOpenParagraphs.begin(); it != myModelsWithOpenParagraphs.end(); ++it) { + if (*it == myCurrentTextModel) { + return true; + } + } + return false; +} + +void BookReader::unsetTextModel() { + myCurrentTextModel.reset(); +} + +void BookReader::pushKind(FBTextKind kind) { + myKindStack.push_back(kind); +} + +bool BookReader::popKind() { + if (!myKindStack.empty()) { + myKindStack.pop_back(); + return true; + } + return false; +} + +bool BookReader::isKindStackEmpty() const { + return myKindStack.empty(); +} + +void BookReader::beginParagraph(ZLTextParagraph::Kind kind) { + endParagraph(); + if (myCurrentTextModel != 0) { + ((ZLTextPlainModel&)*myCurrentTextModel).createParagraph(kind); + for (std::vector<FBTextKind>::const_iterator it = myKindStack.begin(); it != myKindStack.end(); ++it) { + myCurrentTextModel->addControl(*it, true); + } + if (!myHyperlinkReference.empty()) { + myCurrentTextModel->addHyperlinkControl(myHyperlinkKind, myHyperlinkType, myHyperlinkReference); + } + myModelsWithOpenParagraphs.push_back(myCurrentTextModel); + } +} + +void BookReader::endParagraph() { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myModelsWithOpenParagraphs.remove(myCurrentTextModel); + } +} + +void BookReader::addControl(FBTextKind kind, bool start) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addControl(kind, start); + } + if (!start && !myHyperlinkReference.empty() && (kind == myHyperlinkKind)) { + myHyperlinkReference.erase(); + } +} + +void BookReader::addStyleEntry(const ZLTextStyleEntry &entry) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addStyleEntry(entry); + } +} + +void BookReader::addStyleCloseEntry() { + addControl(REGULAR, false); //used instead in XHTMLReader + //TODO implement ZLTextModel::addStyleCloseEntry() +// if (paragraphIsOpen()) { +// flushTextBufferToParagraph(); +// myCurrentTextModel->addStyleCloseEntry(); +// } +} + +void BookReader::addFixedHSpace(unsigned char length) { + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addFixedHSpace(length); + } +} + +void BookReader::addHyperlinkControl(FBTextKind kind, const std::string &label) { + myHyperlinkKind = kind; + std::string type; + switch (myHyperlinkKind) { + case INTERNAL_HYPERLINK: + case FOOTNOTE: + myHyperlinkType = HYPERLINK_INTERNAL; + type = "internal"; + break; + case EXTERNAL_HYPERLINK: + myHyperlinkType = HYPERLINK_EXTERNAL; + type = "external"; + break; + case BOOK_HYPERLINK: + myHyperlinkType = HYPERLINK_BOOK; + type = "book"; + break; + default: + myHyperlinkType = HYPERLINK_NONE; + break; + } + ZLLogger::Instance().println( + "hyperlink", + " + control (" + type + "): " + label + ); + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addHyperlinkControl(kind, myHyperlinkType, label); + } + myHyperlinkReference = label; +} + +void BookReader::addHyperlinkLabel(const std::string &label) { + if (!myCurrentTextModel.isNull()) { + int paragraphNumber = myCurrentTextModel->paragraphsNumber(); + if (paragraphIsOpen()) { + --paragraphNumber; + } + addHyperlinkLabel(label, paragraphNumber); + } +} + +void BookReader::addHyperlinkLabel(const std::string &label, int paragraphNumber) { + ZLLogger::Instance().println( + "hyperlink", + " + label: " + label + ); + myModel.myInternalHyperlinks.insert(std::make_pair( + label, BookModel::Label(myCurrentTextModel, paragraphNumber) + )); +} + +void BookReader::addData(const std::string &data) { + if (!data.empty() && paragraphIsOpen()) { + if (!myInsideTitle) { + mySectionContainsRegularContents = true; + } + myBuffer.push_back(data); + } +} + +void BookReader::addContentsData(const std::string &data) { + if (!data.empty() && !myTOCStack.empty()) { + myContentsBuffer.push_back(data); + } +} + +void BookReader::flushTextBufferToParagraph() { + myCurrentTextModel->addText(myBuffer); + myBuffer.clear(); +} + +void BookReader::addImage(const std::string &id, shared_ptr<const ZLImage> image) { + myModel.myImages[id] = image; +} + +void BookReader::insertEndParagraph(ZLTextParagraph::Kind kind) { + if ((myCurrentTextModel != 0) && mySectionContainsRegularContents) { + std::size_t size = myCurrentTextModel->paragraphsNumber(); + if ((size > 0) && (((*myCurrentTextModel)[(std::size_t)-1])->kind() != kind)) { + ((ZLTextPlainModel&)*myCurrentTextModel).createParagraph(kind); + mySectionContainsRegularContents = false; + } + } +} + +void BookReader::insertEndOfSectionParagraph() { + insertEndParagraph(ZLTextParagraph::END_OF_SECTION_PARAGRAPH); +} + +void BookReader::insertEndOfTextParagraph() { + insertEndParagraph(ZLTextParagraph::END_OF_TEXT_PARAGRAPH); +} + +void BookReader::addImageReference(const std::string &id, short vOffset) { + if (myCurrentTextModel != 0) { + mySectionContainsRegularContents = true; + if (paragraphIsOpen()) { + flushTextBufferToParagraph(); + myCurrentTextModel->addImage(id, myModel.imageMap(), vOffset); + } else { + beginParagraph(); + myCurrentTextModel->addControl(IMAGE, true); + myCurrentTextModel->addImage(id, myModel.imageMap(), vOffset); + myCurrentTextModel->addControl(IMAGE, false); + endParagraph(); + } + } +} + +void BookReader::beginContentsParagraph(int referenceNumber) { + if (myCurrentTextModel == myModel.myBookTextModel) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (referenceNumber == -1) { + referenceNumber = myCurrentTextModel->paragraphsNumber(); + } + ZLTextTreeParagraph *peek = myTOCStack.empty() ? 0 : myTOCStack.top(); + if (!myContentsBuffer.empty()) { + contentsModel.addText(myContentsBuffer); + myContentsBuffer.clear(); + myLastTOCParagraphIsEmpty = false; + } + if (myLastTOCParagraphIsEmpty) { + contentsModel.addText("..."); + } + ZLTextTreeParagraph *para = contentsModel.createParagraph(peek); + contentsModel.addControl(CONTENTS_TABLE_ENTRY, true); + contentsModel.setReference(para, referenceNumber); + myTOCStack.push(para); + myLastTOCParagraphIsEmpty = true; + myContentsParagraphExists = true; + } +} + +void BookReader::endContentsParagraph() { + if (!myTOCStack.empty()) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (!myContentsBuffer.empty()) { + contentsModel.addText(myContentsBuffer); + myContentsBuffer.clear(); + myLastTOCParagraphIsEmpty = false; + } + if (myLastTOCParagraphIsEmpty) { + contentsModel.addText("..."); + myLastTOCParagraphIsEmpty = false; + } + myTOCStack.pop(); + } + myContentsParagraphExists = false; +} + +void BookReader::setReference(std::size_t contentsParagraphNumber, int referenceNumber) { + ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel; + if (contentsParagraphNumber >= contentsModel.paragraphsNumber()) { + return; + } + contentsModel.setReference((const ZLTextTreeParagraph*)contentsModel[contentsParagraphNumber], referenceNumber); +} + +void BookReader::reset() { + myKindStack.clear(); +} diff --git a/reader/src/bookmodel/BookReader.h b/reader/src/bookmodel/BookReader.h new file mode 100644 index 0000000..3a27262 --- /dev/null +++ b/reader/src/bookmodel/BookReader.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKREADER_H__ +#define __BOOKREADER_H__ + +#include <vector> +#include <list> +#include <stack> +#include <string> + +#include <ZLTextParagraph.h> + +#include "FBHyperlinkType.h" +#include "FBTextKind.h" + +class BookModel; +class ZLTextModel; +class ZLInputStream; +class ZLTextStyleEntry; + +class BookReader { + +public: + BookReader(BookModel &model); + virtual ~BookReader(); + + void setMainTextModel(); + void setFootnoteTextModel(const std::string &id); + void unsetTextModel(); + + void insertEndOfSectionParagraph(); + void insertEndOfTextParagraph(); + + void pushKind(FBTextKind kind); + bool popKind(); + bool isKindStackEmpty() const; + + void beginParagraph(ZLTextParagraph::Kind kind = ZLTextParagraph::TEXT_PARAGRAPH); + void endParagraph(); + bool paragraphIsOpen() const; + void addControl(FBTextKind kind, bool start); + void addStyleEntry(const ZLTextStyleEntry &entry); + void addStyleCloseEntry(); //TODO reimplement + void addHyperlinkControl(FBTextKind kind, const std::string &label); + void addHyperlinkLabel(const std::string &label); + void addHyperlinkLabel(const std::string &label, int paragraphNumber); + void addFixedHSpace(unsigned char length); + + void addImageReference(const std::string &id, short vOffset = 0); + void addImage(const std::string &id, shared_ptr<const ZLImage> image); + + void beginContentsParagraph(int referenceNumber = -1); + void endContentsParagraph(); + bool contentsParagraphIsOpen() const; + void setReference(std::size_t contentsParagraphNumber, int referenceNumber); + + void addData(const std::string &data); + void addContentsData(const std::string &data); + + void enterTitle() { myInsideTitle = true; } + void exitTitle() { myInsideTitle = false; } + + const BookModel &model() const { return myModel; } + + void reset(); + +private: + void insertEndParagraph(ZLTextParagraph::Kind kind); + void flushTextBufferToParagraph(); + +private: + BookModel &myModel; + shared_ptr<ZLTextModel> myCurrentTextModel; + std::list<shared_ptr<ZLTextModel> > myModelsWithOpenParagraphs; + + std::vector<FBTextKind> myKindStack; + + bool myContentsParagraphExists; + std::stack<ZLTextTreeParagraph*> myTOCStack; + bool myLastTOCParagraphIsEmpty; + + bool mySectionContainsRegularContents; + bool myInsideTitle; + + std::vector<std::string> myBuffer; + std::vector<std::string> myContentsBuffer; + + std::string myHyperlinkReference; + FBHyperlinkType myHyperlinkType; + FBTextKind myHyperlinkKind; +}; + +inline bool BookReader::contentsParagraphIsOpen() const { + return myContentsParagraphExists; +} + +#endif /* __BOOKREADER_H__ */ diff --git a/reader/src/bookmodel/FBHyperlinkType.h b/reader/src/bookmodel/FBHyperlinkType.h new file mode 100644 index 0000000..fac7d80 --- /dev/null +++ b/reader/src/bookmodel/FBHyperlinkType.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBHYPERLINKTYPE_H__ +#define __FBHYPERLINKTYPE_H__ + +enum FBHyperlinkType { + HYPERLINK_NONE = 0, + HYPERLINK_INTERNAL = 1, + HYPERLINK_EXTERNAL = 2, + HYPERLINK_BOOK = 3, +}; + +#endif /* __FBHYPERLINKTYPE_H__ */ diff --git a/reader/src/bookmodel/FBTextKind.h b/reader/src/bookmodel/FBTextKind.h new file mode 100644 index 0000000..746db2b --- /dev/null +++ b/reader/src/bookmodel/FBTextKind.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBTEXTKIND_H__ +#define __FBTEXTKIND_H__ + +enum FBTextKind { + // please, don't change these numbers + // add new text kinds at end of this enumeration + // + // all the values MUST be in the range 0..127 + REGULAR = 0, + TITLE = 1, + SECTION_TITLE = 2, + POEM_TITLE = 3, + SUBTITLE = 4, + ANNOTATION = 5, + EPIGRAPH = 6, + STANZA = 7, + VERSE = 8, + PREFORMATTED = 9, + IMAGE = 10, + END_OF_SECTION = 11, + CITE = 12, + AUTHOR = 13, + DATEKIND = 14, + INTERNAL_HYPERLINK = 15, + FOOTNOTE = 16, + EMPHASIS = 17, + STRONG = 18, + SUB = 19, + SUP = 20, + CODE = 21, + STRIKETHROUGH = 22, + CONTENTS_TABLE_ENTRY = 23, + //LIBRARY_AUTHOR_ENTRY = 24, + //LIBRARY_BOOK_ENTRY = 25, + LIBRARY_ENTRY = 25, + //RECENT_BOOK_LIST = 26, + ITALIC = 27, + BOLD = 28, + DEFINITION = 29, + DEFINITION_DESCRIPTION = 30, + H1 = 31, + H2 = 32, + H3 = 33, + H4 = 34, + H5 = 35, + H6 = 36, + EXTERNAL_HYPERLINK = 37, + BOOK_HYPERLINK = 38, +}; + +#endif /* __FBTEXTKIND_H__ */ diff --git a/reader/src/database/booksdb/BooksDB.cpp b/reader/src/database/booksdb/BooksDB.cpp new file mode 100644 index 0000000..bf6d2b3 --- /dev/null +++ b/reader/src/database/booksdb/BooksDB.cpp @@ -0,0 +1,503 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLLanguageUtil.h> + +#include "BooksDB.h" +#include "BooksDBQuery.h" + +#include "../../library/Book.h" +#include "../../library/Author.h" +#include "../../library/Tag.h" + +#include "../sqldb/implsqlite/SQLiteFactory.h" + +shared_ptr<BooksDB> BooksDB::ourInstance = 0; + +const std::string BooksDB::DATABASE_NAME = "books.db"; +const std::string BooksDB::STATE_DATABASE_NAME = "state.db"; + +BooksDB &BooksDB::Instance() { + if (ourInstance.isNull()) { + ZLFile dir(databaseDirName()); + dir.directory(true); + ZLFile file(databaseDirName() + ZLibrary::FileNameDelimiter + DATABASE_NAME); + ourInstance = new BooksDB(file.physicalFilePath()); + ourInstance->initDatabase(); + } + return *ourInstance; +} + +BooksDB::BooksDB(const std::string &path) : SQLiteDataBase(path), myInitialized(false) { + initCommands(); +} + +BooksDB::~BooksDB() { +} + +bool BooksDB::initDatabase() { + if (isInitialized()) { + return true; + } + + if (!open()) { + return false; + } + + myInitialized = true; + + ZLFile stateFile(databaseDirName() + ZLibrary::FileNameDelimiter + STATE_DATABASE_NAME); + shared_ptr<DBCommand> cmd = SQLiteFactory::createCommand(BooksDBQuery::PREINIT_DATABASE, connection(), "@stateFile", DBValue::DBTEXT); + ((DBTextValue&)*cmd->parameter("@stateFile").value()) = stateFile.physicalFilePath(); + if (!cmd->execute()) { + myInitialized = false; + close(); + return false; + } + + shared_ptr<DBRunnable> runnable = new InitBooksDBRunnable(connection()); + if (!executeAsTransaction(*runnable)) { + myInitialized = false; + close(); + return false; + } + + return true; +} + +void BooksDB::initCommands() { + myLoadBook = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK, connection(), "@file_id", DBValue::DBINT); + myGetFileSize = SQLiteFactory::createCommand(BooksDBQuery::GET_FILE_SIZE, connection(), "@file_id", DBValue::DBINT); + mySetFileSize = SQLiteFactory::createCommand(BooksDBQuery::SET_FILE_SIZE, connection(), "@file_id", DBValue::DBINT, "@size", DBValue::DBINT); + myFindFileName = SQLiteFactory::createCommand(BooksDBQuery::FIND_FILE_NAME, connection(), "@file_id", DBValue::DBINT); + myFindAuthorId = SQLiteFactory::createCommand(BooksDBQuery::FIND_AUTHOR_ID, connection(), "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); + + myLoadBooks = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOKS, connection()); + + myLoadBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK_STATE_STACK, connection(), "@book_id", DBValue::DBINT); + + myGetPalmType = SQLiteFactory::createCommand(BooksDBQuery::GET_PALM_TYPE, connection(), "@file_id", DBValue::DBINT); + mySetPalmType = SQLiteFactory::createCommand(BooksDBQuery::SET_PALM_TYPE, connection(), "@file_id", DBValue::DBINT, "@type", DBValue::DBTEXT); + + myLoadStackPos = SQLiteFactory::createCommand(BooksDBQuery::LOAD_STACK_POS, connection(), "@book_id", DBValue::DBINT); + mySetStackPos = SQLiteFactory::createCommand(BooksDBQuery::SET_STACK_POS, connection(), "@book_id", DBValue::DBINT, "@stack_pos", DBValue::DBINT); + + myLoadBookState = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK_STATE, connection(), "@book_id", DBValue::DBINT); + mySetBookState = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_STATE, connection(), "@book_id", DBValue::DBINT, "@paragraph", DBValue::DBINT, "@word", DBValue::DBINT, "@char", DBValue::DBINT); + + myInsertBookList = SQLiteFactory::createCommand(BooksDBQuery::INSERT_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + myDeleteBookList = SQLiteFactory::createCommand(BooksDBQuery::DELETE_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + myCheckBookList = SQLiteFactory::createCommand(BooksDBQuery::CHECK_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + + mySaveTableBook = new SaveTableBookRunnable(connection()); + mySaveAuthors = new SaveAuthorsRunnable(connection()); + mySaveSeries = new SaveSeriesRunnable(connection()); + mySaveTags = new SaveTagsRunnable(connection()); + mySaveBook = new SaveBookRunnable(*mySaveTableBook, *mySaveAuthors, *mySaveSeries, *mySaveTags); + mySaveFileEntries = new SaveFileEntriesRunnable(connection()); + + myFindFileId = new FindFileIdRunnable(connection()); + + myLoadFileEntries = new LoadFileEntriesRunnable(connection()); + + myLoadRecentBooks = new LoadRecentBooksRunnable(connection()); + mySaveRecentBooks = new SaveRecentBooksRunnable(connection()); + + mySaveBookStateStack = new SaveBookStateStackRunnable(connection()); + + myDeleteBook = new DeleteBookRunnable(connection()); +} + +bool BooksDB::clearDatabase() { + if (!isInitialized()) { + return false; + } + shared_ptr<DBRunnable> runnable = new ClearBooksDBRunnable(connection()); + return executeAsTransaction(*runnable); +} + +shared_ptr<Book> BooksDB::loadBook(const std::string &fileName) { + if (!isInitialized()) { + return 0; + } + + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return 0; + } + ((DBIntValue&)*myLoadBook->parameter("@file_id").value()) = myFindFileId->fileId(); + shared_ptr<DBDataReader> reader = myLoadBook->executeReader(); + + if (reader.isNull() || !reader->next() || + reader->type(0) != DBValue::DBINT /* book_id */) { + return 0; + } + const int bookId = reader->intValue(0); + + shared_ptr<Book> book = Book::createBook( + ZLFile(fileName), bookId, + reader->textValue(1, Book::AutoEncoding), + reader->textValue(2, ZLLanguageUtil::OtherLanguageCode), + reader->textValue(3, std::string()) + ); + + loadSeries(*book); + loadAuthors(*book); + loadTags(*book); + + return book; +} + + +bool BooksDB::saveBook(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveBook->setBook(book); + return executeAsTransaction(*mySaveBook); +} + +bool BooksDB::saveAuthors(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveAuthors->setBook(book); + return executeAsTransaction(*mySaveAuthors); +} + +bool BooksDB::saveSeries(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveSeries->setBook(book); + return executeAsTransaction(*mySaveSeries); +} + +bool BooksDB::saveTags(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveTags->setBook(book); + return executeAsTransaction(*mySaveTags); +} + +int BooksDB::getFileSize(const std::string fileName) { + if (!isInitialized()) { + return -1; + } + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return 0; + } + ((DBIntValue&)*myGetFileSize->parameter("@file_id").value()) = myFindFileId->fileId(); + + shared_ptr<DBValue> fileSize = myGetFileSize->executeScalar(); + + if (fileSize.isNull()) { + return -1; + } + if (fileSize->type() == DBValue::DBNULL) { + return 0; + } + if (fileSize->type() != DBValue::DBINT) { + return -1; + } + return ((DBIntValue&)*fileSize).value(); +} + +bool BooksDB::setFileSize(const std::string fileName, int size) { + if (!isInitialized()) { + return false; + } + myFindFileId->setFileName(fileName, true); + if (!executeAsTransaction(*myFindFileId)) { + return false; + } + ((DBIntValue&)*mySetFileSize->parameter("@file_id").value()) = myFindFileId->fileId(); + ((DBIntValue&)*mySetFileSize->parameter("@size").value()) = size; + return mySetFileSize->execute(); +} + +bool BooksDB::setEncoding(const Book &book, const std::string &encoding) { + if (!isInitialized()) { + return false; + } + + shared_ptr<DBCommand> command = SQLiteFactory::createCommand(BooksDBQuery::SET_ENCODING, connection()); + + command->parameters().push_back(DBCommandParameter("@book_id", new DBIntValue(book.bookId()))); + command->parameters().push_back(DBCommandParameter("@encoding", new DBTextValue(encoding))); + + return command->execute(); +} + +bool BooksDB::loadFileEntries(const std::string &fileName, std::vector<std::string> &entries) { + myLoadFileEntries->setFileName(fileName); + if (!myLoadFileEntries->run()) { + return false; + } + myLoadFileEntries->collectEntries(entries); + return true; +} + +bool BooksDB::saveFileEntries(const std::string &fileName, const std::vector<std::string> &entries) { + if (!isInitialized()) { + return false; + } + mySaveFileEntries->setEntries(fileName, entries); + return executeAsTransaction(*mySaveFileEntries); +} + +bool BooksDB::loadRecentBooks(std::vector<std::string> &fileNames) { + std::vector<int> fileIds; + if (!myLoadRecentBooks->run()) { + return false; + } + myLoadRecentBooks->collectFileIds(fileIds); + for (std::vector<int>::const_iterator it = fileIds.begin(); it != fileIds.end(); ++it) { + const int fileId = *it; + const std::string fileName = getFileName(fileId); + fileNames.push_back(fileName); + } + return true; +} + +bool BooksDB::saveRecentBooks(const BookList &books) { + if (!isInitialized()) { + return false; + } + mySaveRecentBooks->setBooks(books); + return executeAsTransaction(*mySaveRecentBooks); +} + +std::string BooksDB::getFileName(int fileId) { + std::string fileName; + DBIntValue &findFileId = (DBIntValue&)*myFindFileName->parameter("@file_id").value(); + findFileId = fileId; + while (true) { + shared_ptr<DBDataReader> reader = myFindFileName->executeReader(); + if (reader.isNull() || !reader->next()) { + return std::string(); + } + const std::string namePart = reader->textValue(0, std::string()); + switch (reader->type(1)) { /* parent_id */ + default: + return std::string(); + case DBValue::DBNULL: + return namePart + ZLibrary::FileNameDelimiter + fileName; + case DBValue::DBINT: + if (fileName.empty()) { + fileName = namePart; + } else { + fileName = namePart + BooksDBQuery::ArchiveEntryDelimiter + fileName; + } + findFileId = reader->intValue(1); + break; + } + } +} + +bool BooksDB::loadBooks(BookList &books) { + shared_ptr<DBDataReader> reader = myLoadBooks->executeReader(); + + books.clear(); + std::map<int,shared_ptr<Book> > bookMap; + + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT || /* book_id */ + reader->type(4) != DBValue::DBINT) { /* file_id */ + return false; + } + const int bookId = reader->intValue(0); + const int fileId = reader->intValue(4); + const std::string fileName = getFileName(fileId); + + shared_ptr<Book> book = Book::createBook( + ZLFile(fileName), + bookId, + reader->textValue(1, Book::AutoEncoding), + reader->textValue(2, ZLLanguageUtil::OtherLanguageCode), + reader->textValue(3, std::string()) + ); + books.push_back(book); + bookMap[bookId] = book; + } + + loadSeries(bookMap); + loadAuthors(bookMap); + loadTags(bookMap); + + return true; +} + +bool BooksDB::loadBookStateStack(const Book &book, std::deque<ReadingState> &stack) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myLoadBookStateStack->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = myLoadBookStateStack->executeReader(); + if (reader.isNull()) { + return false; + } + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* paragraph */ + || reader->type(1) != DBValue::DBINT /* word */ + || reader->type(2) != DBValue::DBINT /* char */) { + return false; + } + const int paragraph = reader->intValue(0); + const int word = reader->intValue(1); + const int character = reader->intValue(2); + stack.push_back(ReadingState(paragraph, word, character)); + } + return true; +} + +bool BooksDB::saveBookStateStack(const Book &book, const std::deque<ReadingState> &stack) { + if (!isInitialized() || book.bookId() == 0) { + return false; + } + mySaveBookStateStack->setState(book.bookId(), stack); + return executeAsTransaction(*mySaveBookStateStack); +} + + +bool BooksDB::removeBook(const Book &book) { + if (!isInitialized() || book.bookId() == 0) { + return false; + } + myDeleteBook->setFileName(book.file().path()); + return executeAsTransaction(*myDeleteBook); +} + +std::string BooksDB::getPalmType(const std::string &fileName) { + if (!isInitialized()) { + return ""; + } + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return ""; + } + ((DBIntValue&)*myGetPalmType->parameter("@file_id").value()) = myFindFileId->fileId(); + shared_ptr<DBValue> value = myGetPalmType->executeScalar(); + if (value.isNull() || value->type() != DBValue::DBTEXT) { + return ""; + } + return ((DBTextValue&)*value).value(); +} + +bool BooksDB::setPalmType(const std::string &fileName, const std::string &type) { + if (!isInitialized()) { + return false; + } + myFindFileId->setFileName(fileName, true); + if (!myFindFileId->run()) { + return ""; + } + ((DBIntValue&)*mySetPalmType->parameter("@file_id").value()) = myFindFileId->fileId(); + ((DBTextValue&)*mySetPalmType->parameter("@type").value()) = type; + return mySetPalmType->execute(); +} + +bool BooksDB::loadBookState(const Book &book, ReadingState &state) { + state.Paragraph = state.Word = state.Character = 0; + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myLoadBookState->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = myLoadBookState->executeReader(); + if (reader.isNull()) { + return false; + } + if (!reader->next() + || reader->type(0) != DBValue::DBINT /* paragraph */ + || reader->type(1) != DBValue::DBINT /* word */ + || reader->type(2) != DBValue::DBINT /* char */) { + return false; + } + state.Paragraph = reader->intValue(0); + state.Word = reader->intValue(1); + state.Character = reader->intValue(2); + return true; +} + +bool BooksDB::setBookState(const Book &book, const ReadingState &state) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*mySetBookState->parameter("@book_id").value()) = book.bookId(); + ((DBIntValue&)*mySetBookState->parameter("@paragraph").value()) = state.Paragraph; + ((DBIntValue&)*mySetBookState->parameter("@word").value()) = state.Word; + ((DBIntValue&)*mySetBookState->parameter("@char").value()) = state.Character; + return mySetBookState->execute(); +} + +int BooksDB::loadStackPos(const Book &book) { + if (book.bookId() == 0) { + return 0; + } + ((DBIntValue&)*myLoadStackPos->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBValue> stackPosValue = myLoadStackPos->executeScalar(); + if (stackPosValue.isNull() + || stackPosValue->type() != DBValue::DBINT) { + return 0; + } + return ((DBIntValue&)*stackPosValue).value(); +} + +bool BooksDB::setStackPos(const Book &book, int stackPos) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*mySetStackPos->parameter("@book_id").value()) = book.bookId(); + ((DBIntValue&)*mySetStackPos->parameter("@stack_pos").value()) = stackPos; + return mySetStackPos->execute(); +} + +bool BooksDB::insertIntoBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myInsertBookList->parameter("@book_id").value()) = book.bookId(); + return myInsertBookList->execute(); +} + +bool BooksDB::deleteFromBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myDeleteBookList->parameter("@book_id").value()) = book.bookId(); + return myDeleteBookList->execute(); +} + +bool BooksDB::checkBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myCheckBookList->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBValue> res = myCheckBookList->executeScalar(); + if (res.isNull() || res->type() != DBValue::DBINT) { + return false; + } + const int checkRes = ((DBIntValue&)*res).value(); + return checkRes > 0; +} diff --git a/reader/src/database/booksdb/BooksDB.h b/reader/src/database/booksdb/BooksDB.h new file mode 100644 index 0000000..282a0aa --- /dev/null +++ b/reader/src/database/booksdb/BooksDB.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKSDB_H__ +#define __BOOKSDB_H__ + +#include <set> +#include <map> +#include <deque> + +#include "../sqldb/implsqlite/SQLiteDataBase.h" +#include "DBRunnables.h" + +#include "../../reader/ReadingState.h" + +class Book; + +class BooksDB : public SQLiteDataBase { + +public: + static const std::string DATABASE_NAME; + static const std::string STATE_DATABASE_NAME; + static const std::string NET_DATABASE_NAME; + + static BooksDB &Instance(); + +private: + static shared_ptr<BooksDB> ourInstance; + + BooksDB(const std::string &path); + +public: + virtual ~BooksDB(); + +public: + bool initDatabase(); + bool isInitialized() const; + bool clearDatabase(); + + shared_ptr<Book> loadBook(const std::string &fileName); + bool saveBook(const shared_ptr<Book> book); + bool saveAuthors(const shared_ptr<Book> book); + bool saveSeries(const shared_ptr<Book> book); + bool saveTags(const shared_ptr<Book> book); + + int getFileSize(const std::string fileName); + bool setFileSize(const std::string fileName, int size); + + bool setEncoding(const Book &book, const std::string &encoding); + + bool loadFileEntries(const std::string &fileName, std::vector<std::string> &entries); + bool saveFileEntries(const std::string &fileName, const std::vector<std::string> &entries); + + bool loadRecentBooks(std::vector<std::string> &fileNames); + bool saveRecentBooks(const BookList &books); + + bool loadBooks(BookList &books); + + bool loadBookStateStack(const Book &book, std::deque<ReadingState> &stack); + bool saveBookStateStack(const Book &book, const std::deque<ReadingState> &stack); + + bool removeBook(const Book &book); + + std::string getPalmType(const std::string &fileName); + bool setPalmType(const std::string &fileName, const std::string &type); + + bool loadBookState(const Book &book, ReadingState &state); + bool setBookState(const Book &book, const ReadingState &state); + + int loadStackPos(const Book &book); + bool setStackPos(const Book &book, int stackPos); + + bool insertIntoBookList(const Book &book); + bool deleteFromBookList(const Book &book); + bool checkBookList(const Book &book); + +private: +public: + shared_ptr<Tag> getTagById(int id) const; + void loadAllTagsById() const; + +private: + void loadSeries(Book &book); + void loadSeries(const std::map<int,shared_ptr<Book> > &books); + void loadAuthors(Book &book); + void loadAuthors(const std::map<int,shared_ptr<Book> > &books); + void loadTags(Book &book); + void loadTags(const std::map<int,shared_ptr<Book> > &books); + + std::string getFileName(int fileId); + +private: + void initCommands(); + +private: + bool myInitialized; + + shared_ptr<SaveTableBookRunnable> mySaveTableBook; + shared_ptr<SaveAuthorsRunnable> mySaveAuthors; + shared_ptr<SaveSeriesRunnable> mySaveSeries; + shared_ptr<SaveTagsRunnable> mySaveTags; + shared_ptr<SaveBookRunnable> mySaveBook; + shared_ptr<SaveFileEntriesRunnable> mySaveFileEntries; + + shared_ptr<FindFileIdRunnable> myFindFileId; + + shared_ptr<LoadFileEntriesRunnable> myLoadFileEntries; + + shared_ptr<LoadRecentBooksRunnable> myLoadRecentBooks; + shared_ptr<SaveRecentBooksRunnable> mySaveRecentBooks; + + shared_ptr<SaveBookStateStackRunnable> mySaveBookStateStack; + + shared_ptr<DeleteBookRunnable> myDeleteBook; + + shared_ptr<DBCommand> myLoadNetworkLinks; + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myDeleteNetworkLink; + shared_ptr<DBCommand> myDeleteNetworkLinkUrls; + shared_ptr<DBCommand> myLoadNetworkLinkUrls; + + shared_ptr<DBCommand> myLoadBook; + + shared_ptr<DBCommand> myGetFileSize; + shared_ptr<DBCommand> mySetFileSize; + + shared_ptr<DBCommand> myFindFileName; + + shared_ptr<DBCommand> myFindAuthorId; + + shared_ptr<DBCommand> myLoadBooks; + + shared_ptr<DBCommand> myLoadBookStateStack; + + shared_ptr<DBCommand> myGetPalmType; + shared_ptr<DBCommand> mySetPalmType; + + shared_ptr<DBCommand> myGetNetFile; + shared_ptr<DBCommand> mySetNetFile; + + shared_ptr<DBCommand> myLoadStackPos; + shared_ptr<DBCommand> mySetStackPos; + shared_ptr<DBCommand> myLoadBookState; + shared_ptr<DBCommand> mySetBookState; + + shared_ptr<DBCommand> myInsertBookList; + shared_ptr<DBCommand> myDeleteBookList; + shared_ptr<DBCommand> myCheckBookList; + +private: // disable copying + BooksDB(const BooksDB &); + const BooksDB &operator = (const BooksDB &); +}; + + +inline bool BooksDB::isInitialized() const { return myInitialized; } + +#endif /* __BOOKSDB_H__ */ diff --git a/reader/src/database/booksdb/BooksDBQuery.cpp b/reader/src/database/booksdb/BooksDBQuery.cpp new file mode 100644 index 0000000..134e43b --- /dev/null +++ b/reader/src/database/booksdb/BooksDBQuery.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> + +#include "BooksDBQuery.h" + +const std::string BooksDBQuery::ArchiveEntryDelimiter = ":"; + +const std::string BooksDBQuery::PREINIT_DATABASE = \ + "ATTACH @stateFile AS State; "; + +const std::string BooksDBQuery::INIT_DATABASE = \ + "CREATE TABLE IF NOT EXISTS Files ( " \ + " file_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " parent_id INTEGER REFERENCES Files (file_id), " \ + " size INTEGER, " \ + " CONSTRAINT Files_Unique UNIQUE (name, parent_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Books ( " \ + " book_id INTEGER PRIMARY KEY, " \ + " encoding TEXT, " \ + " language TEXT, " \ + " title TEXT NOT NULL, " \ + " file_id INTEGER UNIQUE NOT NULL REFERENCES Files (file_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Authors ( " \ + " author_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " sort_key TEXT NOT NULL, " \ + " CONSTRAINT Authors_Unique UNIQUE (name, sort_key) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Series ( " \ + " series_id INTEGER PRIMARY KEY, " \ + " name TEXT UNIQUE NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Tags ( " \ + " tag_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " parent_id INTEGER REFERENCES Tags (tag_id), " \ + " CONSTRAINT Tags_Unique UNIQUE (parent_id, name) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookAuthor ( " \ + " author_id INTEGER NOT NULL REFERENCES Authors (author_id), " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " author_index INTEGER NOT NULL, " \ + " CONSTRAINT BookAuthor_Unique0 UNIQUE (author_id, book_id), " \ + " CONSTRAINT BookAuthor_Unique1 UNIQUE (book_id, author_index) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookSeries ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id), " \ + " series_id INTEGER NOT NULL REFERENCES Series (series_id), " \ + " book_index INTEGER " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookTag ( " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " tag_id INTEGER NOT NULL REFERENCES Tags (tag_id), " \ + " CONSTRAINT BookTag_Unique UNIQUE (book_id, tag_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.RecentBooks ( " \ + " book_index INTEGER PRIMARY KEY, " \ + " book_id INTEGER UNIQUE REFERENCES Books (book_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.BookStateStack ( " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " position INTEGER NOT NULL, " \ + " paragraph INTEGER NOT NULL, " \ + " word INTEGER NOT NULL, " \ + " char INTEGER NOT NULL, " \ + " CONSTRAINT BookStateStack_Unique UNIQUE (book_id, position) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS PalmType ( " \ + " file_id INTEGER UNIQUE REFERENCES Files (file_id), " \ + " type TEXT NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.StackPosition ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id), " \ + " stack_pos INTEGER NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.BookList ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id) " \ + "); "; + +const std::string BooksDBQuery::SECOND_INIT_DATABASE = \ + "CREATE TRIGGER IF NOT EXISTS Books_Delete BEFORE DELETE " \ + "ON Books FOR EACH ROW " \ + "BEGIN " \ + " DELETE FROM BookAuthor WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookSeries WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookTag WHERE book_id = OLD.book_id; " \ + " DELETE FROM StackPosition WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookStateStack WHERE book_id = OLD.book_id; " \ + " DELETE FROM RecentBooks WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookList WHERE book_id = OLD.book_id; " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Delete BEFORE DELETE " \ + "ON Files FOR EACH ROW " \ + "BEGIN " \ + " DELETE FROM Books WHERE file_id = OLD.file_id; " \ + " DELETE FROM PalmType WHERE file_id = OLD.file_id; " \ + "END; " \ + " " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Unique_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.parent_id IS NULL AND f.name = NEW.name) " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"columns name, parent_id are not unique\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Directory_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Directory entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_ArchEntry_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NOT NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.file_id = NEW.parent_id AND f.parent_id IS NOT NULL) " \ + " AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Archive Entry entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Unique_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.parent_id IS NULL AND f.name = NEW.name AND f.file_id != NEW.file_id) " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"columns name, parent_id are not unique\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Directory_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Directory entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_ArchEntry_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NOT NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.file_id = NEW.parent_id AND f.parent_id IS NOT NULL) " \ + " AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Archive Entry entry\"); " \ + "END; "; + +const std::string BooksDBQuery::CLEAR_DATABASE = \ + "DROP TRIGGER Books_Delete " \ + "DROP TRIGGER Files_Delete " \ + "DROP TRIGGER Files_Unique_Insert " \ + "DROP TRIGGER Files_Directory_Insert " \ + "DROP TRIGGER Files_ArchEntry_Insert " \ + "DROP TRIGGER Files_Unique_Update " \ + "DROP TRIGGER Files_Directory_Update " \ + "DROP TRIGGER Files_ArchEntry_Update " \ + " " \ + "DROP TABLE State.BookList; " \ + "DROP TABLE State.StackPosition; " \ + "DROP TABLE PalmType; " \ + "DROP TABLE State.BookStateStack; " \ + "DROP TABLE State.RecentBooks; " \ + "DROP TABLE BookTag; " \ + "DROP TABLE BookSeries; " \ + "DROP TABLE BookAuthor; " \ + "DROP TABLE Tags; " \ + "DROP TABLE Series; " \ + "DROP TABLE Authors; " \ + "DROP TABLE Books; " \ + "DROP TABLE Files; "; + + +const std::string BooksDBQuery::LOAD_BOOK = \ + "SELECT " \ + " b.book_id AS book_id, " \ + " b.encoding AS encoding, " \ + " b.language AS language, " \ + " b.title AS title, " \ + " b.file_id AS file_id " \ + "FROM Books AS b " \ + "WHERE b.file_id = @file_id; "; + +const std::string BooksDBQuery::ADD_BOOK = \ + "INSERT INTO Books (encoding, language, title, file_id) " \ + " VALUES ( " \ + " nullif(@encoding,\"auto\"), " \ + " nullif(@language,\"other\"), " \ + " @title, " \ + " @file_id " \ + " ); " \ + " " \ + "SELECT last_insert_rowid() AS book_id; "; + +const std::string BooksDBQuery::UPDATE_BOOK = \ + "UPDATE Books SET " \ + " encoding = nullif(@encoding,\"auto\"), " \ + " language = nullif(@language,\"other\"), " \ + " title = @title " \ + "WHERE " \ + " book_id = @book_id; "; + + + +const std::string BooksDBQuery::SET_BOOK_AUTHOR = \ + "INSERT OR REPLACE INTO BookAuthor (author_id, book_id, author_index) VALUES (@author_id, @book_id, @author_index); "; + +const std::string BooksDBQuery::TRIM_BOOK_AUTHORS = \ + "DELETE FROM BookAuthor WHERE book_id = @book_id AND author_index > @authors_number; "; + +const std::string BooksDBQuery::FIND_AUTHOR_ID = "SELECT author_id FROM Authors WHERE name = @name AND sort_key = @sort_key; "; + +const std::string BooksDBQuery::ADD_AUTHOR = \ + "INSERT INTO Authors (name, sort_key) VALUES (@name, @sort_key); " \ + "SELECT last_insert_rowid() AS author_id; "; + + +const std::string BooksDBQuery::SET_BOOKSERIES = \ + "INSERT OR REPLACE INTO BookSeries (book_id, series_id, book_index) VALUES (" \ + " @book_id, " \ + " @series_id, " \ + " nullif(@book_index, \"\") " \ + "); "; + +const std::string BooksDBQuery::DELETE_BOOKSERIES = \ + "DELETE FROM BookSeries " \ + "WHERE " \ + " book_id = @book_id; "; + +const std::string BooksDBQuery::FIND_SERIES_ID = "SELECT series_id FROM Series WHERE name = @name; "; + +const std::string BooksDBQuery::ADD_SERIES = \ + "INSERT INTO Series (name) VALUES (@name); " \ + "SELECT last_insert_rowid() AS series_id; "; + + +const std::string BooksDBQuery::GET_FILE_SIZE = "SELECT size FROM Files WHERE file_id = @file_id"; +const std::string BooksDBQuery::SET_FILE_SIZE = "UPDATE Files SET size = @size WHERE file_id = @file_id"; + +const std::string BooksDBQuery::SET_ENCODING = "UPDATE Books SET encoding = @encoding WHERE book_id = @book_id; "; + +const std::string BooksDBQuery::LOAD_FILE_ENTRIES = "SELECT name FROM Files WHERE coalesce(parent_id, 0) = @file_id; "; + +const std::string BooksDBQuery::INVALIDATE_BOOKS = "UPDATE Books SET title = \"\" WHERE file_id = @file_id; "; + + +const std::string BooksDBQuery::DELETE_FILE = "DELETE FROM Files WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::DELETE_FILE_ENTRIES = "DELETE FROM Files WHERE parent_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_FILE_ENTRY_IDS = "SELECT file_id FROM Files WHERE coalesce(parent_id, 0) = @file_id; "; + +const std::string BooksDBQuery::FIND_BOOK_ID = "SELECT book_id FROM Books WHERE file_id = @file_id; "; + + +const std::string BooksDBQuery::LOAD_RECENT_BOOKS = \ + "SELECT b.file_id " \ + "FROM Books AS b " \ + " INNER JOIN RecentBooks AS rb ON b.book_id = rb.book_id " \ + "ORDER BY rb.book_index; "; + +const std::string BooksDBQuery::CLEAR_RECENT_BOOKS = "DELETE FROM RecentBooks; "; + +const std::string BooksDBQuery::INSERT_RECENT_BOOKS = "INSERT INTO RecentBooks (book_id) VALUES (@book_id); "; + +const std::string BooksDBQuery::FIND_FILE_NAME = "SELECT name, parent_id FROM Files WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_BOOKS = "SELECT book_id, encoding, language, title, file_id FROM Books; "; + +const std::string BooksDBQuery::UPDATE_AUTHOR = \ + "UPDATE Authors SET " \ + " name = @newName, " \ + " sort_key = @newSortKey " \ + "WHERE name = @oldName " \ + " AND sort_key = @oldSortKey; "; + +const std::string BooksDBQuery::UPDATE_BOOKS_AUTHOR = "UPDATE OR REPLACE BookAuthor SET author_id = @newAuthorId WHERE author_id = @oldAuthorId; "; + +const std::string BooksDBQuery::LOAD_BOOK_STATE_STACK = "SELECT paragraph, word, char FROM BookStateStack WHERE book_id = @book_id AND position > 0 ORDER BY position; "; +const std::string BooksDBQuery::TRIM_BOOK_STATE_STACK = "DELETE FROM BookStateStack WHERE book_id = @book_id AND position > @stackSize; "; +const std::string BooksDBQuery::SET_BOOK_STATE_STACK = "INSERT OR REPLACE INTO BookStateStack(book_id, position, paragraph, word, char) VALUES (@book_id, @position, @paragraph, @word, @char); "; + +const std::string BooksDBQuery::SET_PALM_TYPE = "INSERT OR REPLACE INTO PalmType (file_id, type) VALUES (@file_id, @type); "; +const std::string BooksDBQuery::GET_PALM_TYPE = "SELECT type FROM PalmType WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_STACK_POS = "SELECT stack_pos FROM StackPosition WHERE book_id = @book_id; "; +const std::string BooksDBQuery::SET_STACK_POS = "INSERT OR REPLACE INTO StackPosition(book_id, stack_pos) VALUES (@book_id, @stack_pos); "; + +const std::string BooksDBQuery::LOAD_BOOK_STATE = "SELECT paragraph, word, char FROM BookStateStack WHERE book_id = @book_id AND position = 0; "; +const std::string BooksDBQuery::SET_BOOK_STATE = "INSERT OR REPLACE INTO BookStateStack(book_id, position, paragraph, word, char) VALUES (@book_id, 0, @paragraph, @word, @char); "; + +const std::string BooksDBQuery::INSERT_BOOK_LIST = "INSERT OR IGNORE INTO BookList(book_id) VALUES (@book_id); "; +const std::string BooksDBQuery::DELETE_BOOK_LIST = "DELETE FROM BookList WHERE book_id = @book_id; "; +const std::string BooksDBQuery::CHECK_BOOK_LIST = "SELECT COUNT(*) FROM BookList WHERE book_id = @book_id; "; diff --git a/reader/src/database/booksdb/BooksDBQuery.h b/reader/src/database/booksdb/BooksDBQuery.h new file mode 100644 index 0000000..c202dea --- /dev/null +++ b/reader/src/database/booksdb/BooksDBQuery.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKSDBQUERY_H__ +#define __BOOKSDBQUERY_H__ + +#include <string> + +class BooksDBQuery { + +public: + static const std::string ArchiveEntryDelimiter; + +public: + static const std::string PREINIT_DATABASE; + static const std::string INIT_DATABASE; + static const std::string SECOND_INIT_DATABASE; + static const std::string CLEAR_DATABASE; + + static const std::string LOAD_BOOK; + + static const std::string ADD_BOOK; + static const std::string UPDATE_BOOK; + + static const std::string FIND_AUTHOR_ID; + static const std::string ADD_AUTHOR; + + static const std::string GET_BOOK_AUTHORS_NUMBER; + static const std::string TRIM_BOOK_AUTHORS; + static const std::string SET_BOOK_AUTHOR; + + static const std::string DELETE_BOOKSERIES; + static const std::string FIND_SERIES_ID; + static const std::string ADD_SERIES; + static const std::string SET_BOOKSERIES; + + static const std::string GET_FILE_SIZE; + static const std::string SET_FILE_SIZE; + + static const std::string SET_ENCODING; + + static const std::string LOAD_FILE_ENTRIES; + + static const std::string INVALIDATE_BOOKS; + + static const std::string DELETE_FILE; + static const std::string DELETE_FILE_ENTRIES; + static const std::string LOAD_FILE_ENTRY_IDS; + + static const std::string FIND_BOOK_ID; + + static const std::string LOAD_RECENT_BOOKS; + static const std::string CLEAR_RECENT_BOOKS; + static const std::string INSERT_RECENT_BOOKS; + + static const std::string FIND_FILE_NAME; + + static const std::string LOAD_BOOKS; + + static const std::string UPDATE_AUTHOR; + static const std::string UPDATE_BOOKS_AUTHOR; + + static const std::string LOAD_BOOK_STATE_STACK; + static const std::string TRIM_BOOK_STATE_STACK; + static const std::string SET_BOOK_STATE_STACK; + + static const std::string GET_PALM_TYPE; + static const std::string SET_PALM_TYPE; + + static const std::string LOAD_BOOK_STATE; + static const std::string SET_BOOK_STATE; + static const std::string LOAD_STACK_POS; + static const std::string SET_STACK_POS; + + static const std::string INSERT_BOOK_LIST; + static const std::string DELETE_BOOK_LIST; + static const std::string CHECK_BOOK_LIST; + +private: // disable creation Instances + BooksDBQuery(); +}; + +#endif /* __BOOKSDBQUERY_H__ */ diff --git a/reader/src/database/booksdb/BooksDBUtil.cpp b/reader/src/database/booksdb/BooksDBUtil.cpp new file mode 100644 index 0000000..3a7de96 --- /dev/null +++ b/reader/src/database/booksdb/BooksDBUtil.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLStringUtil.h> + +#include "BooksDBUtil.h" +#include "BooksDB.h" + +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../../library/Author.h" + +shared_ptr<Book> BooksDBUtil::getBook(const std::string &filePath, bool checkFile) { + const std::string physicalFilePath = ZLFile(filePath).physicalFilePath(); + + ZLFile file(physicalFilePath); + if (checkFile && !file.exists()) { + return 0; + } + + if (!checkFile || checkInfo(file)) { + shared_ptr<Book> book = loadFromDB(filePath); + if (!book.isNull() && isBookFull(*book)) { + return book; + } + } else { + if (physicalFilePath != filePath) { + resetZipInfo(file); + } + saveInfo(file); + } + + shared_ptr<Book> book = Book::loadFromFile(ZLFile(filePath)); + if (book.isNull()) { + return 0; + } + BooksDB::Instance().saveBook(book); + return book; +} + +bool BooksDBUtil::getRecentBooks(BookList &books) { + std::vector<std::string> fileNames; + if (!BooksDB::Instance().loadRecentBooks(fileNames)) { + return false; + } + for (std::vector<std::string>::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) { + shared_ptr<Book> book = getBook(*it /*, true OR false ? */); // TODO: check file ??? + if (!book.isNull()) { + books.push_back(book); + } + } + return true; +} + +bool BooksDBUtil::getBooks(std::map<std::string, shared_ptr<Book> > &booksmap, bool checkFile) { + BookList books; + if (!BooksDB::Instance().loadBooks(books)) { + return false; + } + for (BookList::iterator it = books.begin(); it != books.end(); ++it) { + Book &book = **it; + const std::string physicalFilePath = book.file().physicalFilePath(); + ZLFile file(physicalFilePath); + if (!checkFile || file.exists()) { + if (!checkFile || checkInfo(file)) { + if (isBookFull(book)) { + booksmap.insert(std::make_pair(book.file().path(), *it)); + continue; + } + } else { + if (physicalFilePath != book.file().path()) { + resetZipInfo(file); + } + saveInfo(file); + } + shared_ptr<Book> bookptr = Book::loadFromFile(book.file()); + if (!bookptr.isNull()) { + BooksDB::Instance().saveBook(bookptr); + booksmap.insert(std::make_pair(book.file().path(), bookptr)); + } + } + } + return true; +} + +bool BooksDBUtil::isBookFull(const Book &book) { + return + !book.title().empty() && + !book.encoding().empty(); +} + +shared_ptr<Book> BooksDBUtil::loadFromDB(const std::string &filePath) { + if (filePath.empty()) { + return 0; + } + return BooksDB::Instance().loadBook(filePath); +} + +bool BooksDBUtil::checkInfo(const ZLFile &file) { + return BooksDB::Instance().getFileSize(file.path()) == (int) file.size(); +} + +void BooksDBUtil::saveInfo(const ZLFile &file) { + BooksDB::Instance().setFileSize(file.path(), file.size()); +} + +void BooksDBUtil::listZipEntries(const ZLFile &zipFile, std::vector<std::string> &entries) { + entries.clear(); + BooksDB::Instance().loadFileEntries(zipFile.path(), entries); + if (entries.empty()) { + resetZipInfo(zipFile); + BooksDB::Instance().loadFileEntries(zipFile.path(), entries); + } +} + +void BooksDBUtil::resetZipInfo(const ZLFile &zipFile) { + shared_ptr<ZLDir> zipDir = zipFile.directory(); + if (!zipDir.isNull()) { + std::vector<std::string> entries; + zipDir->collectFiles(entries, false); + BooksDB::Instance().saveFileEntries(zipFile.path(), entries); + } +} + +bool BooksDBUtil::canRemoveFile(const std::string &filePath) { + ZLFile bookFile(filePath); + std::string physicalPath = bookFile.physicalFilePath(); + if (filePath != physicalPath) { + ZLFile zipFile(physicalPath); + shared_ptr<ZLDir> zipDir = zipFile.directory(); + if (zipDir.isNull()) { + return false; + } + std::vector<std::string> entries; + zipDir->collectFiles(entries, false); // TODO: replace with BooksDB call??? + if (entries.size() != 1) { + return false; + } + if (zipDir->itemPath(entries[0]) != filePath) { + return false; + } + } + return ZLFile(physicalPath).canRemove(); +} + +void BooksDBUtil::addTag(shared_ptr<Book> book, shared_ptr<Tag> tag) { + if (book->addTag(tag)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::renameTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (book->renameTag(from, to, includeSubTags)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::cloneTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (book->cloneTag(from, to, includeSubTags)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::removeAllTags(shared_ptr<Book> book) { + book->removeAllTags(); +} diff --git a/reader/src/database/booksdb/BooksDBUtil.h b/reader/src/database/booksdb/BooksDBUtil.h new file mode 100644 index 0000000..8d55e1c --- /dev/null +++ b/reader/src/database/booksdb/BooksDBUtil.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKSDBUTIL_H__ +#define __BOOKSDBUTIL_H__ + +#include <map> + +#include <shared_ptr.h> + +#include "../../library/Lists.h" + +class Book; +class ZLFile; + +class BooksDBUtil { + +public: + static shared_ptr<Book> getBook(const std::string &fileName, bool checkFile = true); + + static bool getBooks(std::map<std::string, shared_ptr<Book> > &booksmap, bool checkFile = true); + + static bool getRecentBooks(BookList &books); + +public: + static void addTag(shared_ptr<Book> book, shared_ptr<Tag> tag); + static void renameTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + static void cloneTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + static void removeAllTags(shared_ptr<Book> book); + + static bool checkInfo(const ZLFile &file); + static void saveInfo(const ZLFile &file); + + static void listZipEntries(const ZLFile &zipFile, std::vector<std::string> &entries); + static void resetZipInfo(const ZLFile &zipFile); + + static bool isBookFull(const Book &book); + + static bool canRemoveFile(const std::string &fileName); + +private: + static shared_ptr<Book> loadFromDB(const std::string &fileName); +}; + +#endif /* __BOOKSDBUTIL_H__ */ diff --git a/reader/src/database/booksdb/BooksDB_BookAuthor.cpp b/reader/src/database/booksdb/BooksDB_BookAuthor.cpp new file mode 100644 index 0000000..8cdc2a4 --- /dev/null +++ b/reader/src/database/booksdb/BooksDB_BookAuthor.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <string> + +#include "BooksDB.h" +#include "../../library/Book.h" +#include "../../library/Author.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_AUTHORS_QUERY = + "SELECT Authors.name, Authors.sort_key" \ + " FROM BookAuthor" \ + " INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id" \ + " WHERE BookAuthor.book_id = @book_id" \ + " ORDER BY BookAuthor.author_index;"; +static const std::string LOAD_ALL_AUTHORS_QUERY = + "SELECT Authors.name, Authors.sort_key, BookAuthor.book_id" \ + " FROM BookAuthor" \ + " INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id" \ + " ORDER BY BookAuthor.author_index;"; + +void BooksDB::loadAuthors(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_AUTHORS_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + book.removeAllAuthors(); + + while (reader->next()) { + book.addAuthor( + reader->textValue(0, std::string()), + reader->textValue(1, std::string()) + ); + } +} + +void BooksDB::loadAuthors(const std::map<int,shared_ptr<Book> > &books) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_AUTHORS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + for (std::map<int,shared_ptr<Book> >::const_iterator it = books.begin(); it != books.end(); ++it) { + it->second->removeAllAuthors(); + } + + while (reader->next()) { + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(2) == DBValue::DBINT) ? reader->intValue(2) : 0); + if (it != books.end()) { + it->second->addAuthor( + reader->textValue(0, std::string()), + reader->textValue(1, std::string()) + ); + } + } +} diff --git a/reader/src/database/booksdb/BooksDB_BookSeries.cpp b/reader/src/database/booksdb/BooksDB_BookSeries.cpp new file mode 100644 index 0000000..a9b860b --- /dev/null +++ b/reader/src/database/booksdb/BooksDB_BookSeries.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <string> + +#include "BooksDB.h" +#include "../../library/Book.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_SERIES_QUERY = + "SELECT Series.name, BookSeries.book_index" \ + " FROM BookSeries" \ + " INNER JOIN Series ON Series.series_id = BookSeries.series_id" \ + " WHERE BookSeries.book_id = @book_id;"; +static const std::string LOAD_ALL_SERIES_QUERY = + "SELECT Series.name, BookSeries.book_index, BookSeries.book_id" \ + " FROM BookSeries" \ + " INNER JOIN Series ON Series.series_id = BookSeries.series_id"; + +static Number getSeriesIndex(shared_ptr<DBDataReader> reader) { + Number seriesIndex; + if (reader->type(1) == DBValue::DBTEXT) { + seriesIndex = Number(reader->textValue(1, std::string())); + } else if (reader->type(1) == DBValue::DBREAL){ //for old database scheme + seriesIndex = Number((int)reader->realValue(1)); + } else { //for old database scheme + seriesIndex = Number(reader->intValue(1)); + } + return seriesIndex; +} + +void BooksDB::loadSeries(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_SERIES_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + if (reader->next()) { + std::string seriesTitle = reader->textValue(0, std::string()); + if (!seriesTitle.empty()) { + book.setSeries( + seriesTitle, + getSeriesIndex(reader) + ); + } + } +} + +void BooksDB::loadSeries(const std::map<int,shared_ptr<Book> > &books) { + shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_SERIES_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + while (reader->next()) { + std::string seriesTitle = reader->textValue(0, std::string()); + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(2) == DBValue::DBINT) ? reader->intValue(2) : 0); + if (!seriesTitle.empty() && it != books.end()) { + it->second->setSeries( + seriesTitle, + getSeriesIndex(reader) + ); + } + } +} diff --git a/reader/src/database/booksdb/BooksDB_BookTag.cpp b/reader/src/database/booksdb/BooksDB_BookTag.cpp new file mode 100644 index 0000000..a3d36fe --- /dev/null +++ b/reader/src/database/booksdb/BooksDB_BookTag.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <string> +#include <algorithm> + +#include "BooksDB.h" +#include "DBRunnables.h" +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_BOOK_TAGS_QUERY = + "SELECT tag_id FROM BookTag WHERE book_id = @book_id"; +static const std::string LOAD_ALL_BOOK_TAGS_QUERY = + "SELECT tag_id, book_id FROM BookTag"; +static const std::string LOAD_SINGLE_TAG_QUERY = + "SELECT name, parent_id FROM Tags WHERE tag_id = @tag_id"; +static const std::string LOAD_ALL_TAGS_QUERY = + "SELECT name, parent_id, tag_id FROM Tags ORDER BY tag_id"; +static const std::string ADD_BOOKTAG = + "INSERT INTO BookTag (book_id, tag_id) VALUES (@book_id, @tag_id)"; +static const std::string DELETE_BOOKTAG = + "DELETE FROM BookTag WHERE book_id = @book_id AND tag_id = @tag_id"; +static const std::string FIND_TAG_ID = + "SELECT tag_id FROM Tags" \ + " WHERE name = @name AND coalesce(parent_id, 0) = @parent_id"; +static const std::string ADD_TAG = + "INSERT INTO Tags (name, parent_id) VALUES (@name, nullif(@parent_id, 0));" \ + " SELECT last_insert_rowid() AS tag_id"; + +void BooksDB::loadTags(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_BOOK_TAGS_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + book.removeAllTags(); + while (reader->next()) { + book.addTag(getTagById(reader->intValue(0))); + } +} + +void BooksDB::loadTags(const std::map<int,shared_ptr<Book> > &books) { + loadAllTagsById(); + + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_BOOK_TAGS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + for (std::map<int,shared_ptr<Book> >::const_iterator it = books.begin(); it != books.end(); ++it) { + it->second->removeAllTags(); + } + + while (reader->next()) { + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(1) == DBValue::DBINT) ? reader->intValue(1) : 0); + if (it != books.end()) { + it->second->addTag(getTagById(reader->intValue(0))); + } + } +} + +shared_ptr<Tag> BooksDB::getTagById(int id) const { + if (id == 0) { + return 0; + } + + shared_ptr<Tag> tag = Tag::getTagById(id); + if (!tag.isNull()) { + return tag; + } + + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_SINGLE_TAG_QUERY, connection(), "@tag_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@tag_id").value()) = id; + shared_ptr<DBDataReader> reader = command->executeReader(); + if (!reader->next()) { + return 0; + } + const std::string name = reader->textValue(0, std::string()); + const int parentId = (reader->type(1) == DBValue::DBINT) ? + reader->intValue(1) : 0; + reader.reset(); + + return Tag::getTag(name, getTagById(parentId), id); +} + +void BooksDB::loadAllTagsById() const { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_TAGS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + while (reader->next()) { + if (reader->type(2) != DBValue::DBINT) { + continue; + } + const int id = reader->intValue(2); + if (!Tag::getTagById(id).isNull()) { + continue; + } + Tag::getTag( + reader->textValue(0, std::string()), + Tag::getTagById( + (reader->type(1) == DBValue::DBINT) ? reader->intValue(1) : 0 + ), + id + ); + } +} + +SaveTagsRunnable::SaveTagsRunnable(DBConnection &connection) { + myDeleteBookTag = SQLiteFactory::createCommand( + DELETE_BOOKTAG, connection, + "@book_id", DBValue::DBINT, + "@tag_id", DBValue::DBINT + ); + myFindTagId = SQLiteFactory::createCommand( + FIND_TAG_ID, connection, + "@name", DBValue::DBTEXT, + "@parent_id", DBValue::DBINT + ); + myAddTag = SQLiteFactory::createCommand( + ADD_TAG, connection, + "@name", DBValue::DBTEXT, + "@parent_id", DBValue::DBINT + ); + myAddBookTag = SQLiteFactory::createCommand( + ADD_BOOKTAG, connection, + "@book_id", DBValue::DBINT, + "@tag_id", DBValue::DBINT + ); + myLoadBookTags = SQLiteFactory::createCommand( + LOAD_BOOK_TAGS_QUERY, connection, "@book_id", DBValue::DBINT + ); +} + +bool SaveTagsRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + + ((DBIntValue&)*myDeleteBookTag->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &delTagId = (DBIntValue&)*myDeleteBookTag->parameter("@tag_id").value(); + ((DBIntValue&)*myAddBookTag->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &addTagId = (DBIntValue&)*myAddBookTag->parameter("@tag_id").value(); + + TagList dbTags; + + ((DBIntValue&)*myLoadBookTags->parameter("@book_id").value()) = myBook->bookId(); + shared_ptr<DBDataReader> reader = myLoadBookTags->executeReader(); + + while (reader->next()) { + shared_ptr<Tag> tag = BooksDB::Instance().getTagById(reader->intValue(0)); + if (!tag.isNull()) { + dbTags.push_back(tag); + } + } + + TagList tags = myBook->tags(); // make copy of vector + + for (TagList::const_iterator it = dbTags.begin(); it != dbTags.end(); ++it) { + shared_ptr<Tag> tag = (*it); + findTagId(tag); + TagList::iterator jt = std::find(tags.begin(), tags.end(), tag); + if (jt == tags.end()) { + // Tag `tag` must be removed from BookTag table. + delTagId.setValue(tag->tagId()); + if (!myDeleteBookTag->execute()) { + return false; + } + } else { + // This tag is already in DataBase => need not to be inserted. + tags.erase(jt); + } + } + + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + int tableTagId = findTagId(*it); + if (tableTagId == 0) { + return false; + } + addTagId.setValue(tableTagId); + if (!myAddBookTag->execute()) { + return false; + } + } + return true; +} + + +int SaveTagsRunnable::findTagId(shared_ptr<Tag> tag) { + int tagId = tag->tagId(); + if (tagId != 0) { + return tagId; + } + int parentId = 0; + if (!tag->parent().isNull()) { + parentId = findTagId(tag->parent()); + if (parentId == 0) { + return 0; + } + } + + DBIntValue &findParent = (DBIntValue&)*myFindTagId->parameter("@parent_id").value(); + DBTextValue &findName = (DBTextValue&)*myFindTagId->parameter("@name").value(); + DBIntValue &addParent = (DBIntValue&)*myAddTag->parameter("@parent_id").value(); + DBTextValue &addName = (DBTextValue&)*myAddTag->parameter("@name").value(); + + findParent.setValue(parentId); + findName.setValue(tag->name()); + shared_ptr<DBValue> tableTagId = myFindTagId->executeScalar(); + if (tableTagId.isNull() || tableTagId->type() != DBValue::DBINT || ((DBIntValue&)*tableTagId).value() == 0) { + addParent.setValue(parentId); + addName.setValue(tag->name()); + tableTagId = myAddTag->executeScalar(); + if (tableTagId.isNull() || tableTagId->type() != DBValue::DBINT || ((DBIntValue&)*tableTagId).value() == 0) { + return 0; + } + } + Tag::setTagId(tag, ((DBIntValue&)*tableTagId).value()); + return ((DBIntValue&)*tableTagId).value(); +} + +void SaveTagsRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/reader/src/database/booksdb/DBRunnables.h b/reader/src/database/booksdb/DBRunnables.h new file mode 100644 index 0000000..dcbe438 --- /dev/null +++ b/reader/src/database/booksdb/DBRunnables.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DBRUNNABLES_H__ +#define __DBRUNNABLES_H__ + +#include <deque> +#include <vector> + +#include "../../reader/ReadingState.h" + +#include "../sqldb/DBConnection.h" +#include "../sqldb/DBCommand.h" +#include "../sqldb/DBRunnable.h" + +#include "BooksDBQuery.h" + +#include "../../library/Lists.h" + +class FindFileIdRunnable; +class LoadFileEntriesRunnable; +class DeleteFileEntriesRunnable; + +/* + * Save Runnables + */ + + +class InitBooksDBRunnable : public DBRunnable { + +public: + InitBooksDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class ClearBooksDBRunnable : public DBRunnable { + +public: + ClearBooksDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class SaveTableBookRunnable : public DBRunnable { + +public: + SaveTableBookRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + bool addTableBook(const shared_ptr<Book> book, int fileId); + bool updateTableBook(const shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> myFindBookId; + + shared_ptr<DBCommand> myAddBook; + shared_ptr<DBCommand> myUpdateBook; + + shared_ptr<FindFileIdRunnable> myFindFileId; +}; + +class SaveAuthorsRunnable : public DBRunnable { + +public: + SaveAuthorsRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> mySetBookAuthor; + shared_ptr<DBCommand> myTrimBookAuthors; + + shared_ptr<DBCommand> myFindAuthorId; + shared_ptr<DBCommand> myAddAuthor; +}; + +class SaveTagsRunnable : public DBRunnable { + +public: + SaveTagsRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + int findTagId(shared_ptr<Tag> tag); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> myAddBookTag; + shared_ptr<DBCommand> myDeleteBookTag; + + shared_ptr<DBCommand> myFindTagId; + shared_ptr<DBCommand> myAddTag; + + shared_ptr<DBCommand> myLoadBookTags; +}; + + +class SaveSeriesRunnable : public DBRunnable { + +public: + SaveSeriesRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> mySetBookSeries; + shared_ptr<DBCommand> myDeleteBookSeries; + + shared_ptr<DBCommand> myFindSeriesId; + shared_ptr<DBCommand> myAddSeries; +}; + +class SaveBookRunnable : public DBRunnable { +public: + SaveBookRunnable(SaveTableBookRunnable &saveTableBook, SaveAuthorsRunnable &saveAuthors, + SaveSeriesRunnable &saveSeries, SaveTagsRunnable &saveTags); + + bool run(); + void setBook(shared_ptr<Book> book); + +private: + SaveTableBookRunnable &mySaveTableBook; + SaveAuthorsRunnable &mySaveAuthors; + SaveSeriesRunnable &mySaveSeries; + SaveTagsRunnable &mySaveTags; +}; + +class SaveFileEntriesRunnable : public DBRunnable { + +public: + SaveFileEntriesRunnable(DBConnection &connection); + bool run(); + void setEntries(const std::string &fileName, const std::vector<std::string> &entries); + +private: + std::string myFileName; + std::vector<std::string> myEntries; + + shared_ptr<DBCommand> myAddFile; + + shared_ptr<FindFileIdRunnable> myFindFileId; + shared_ptr<DeleteFileEntriesRunnable> myDeleteFileEntries; +}; + +class SaveRecentBooksRunnable : public DBRunnable { + +public: + SaveRecentBooksRunnable(DBConnection &connection); + bool run(); + void setBooks(const BookList &books); + +private: + BookList myBooks; + + shared_ptr<DBCommand> myClearRecentBooks; + shared_ptr<DBCommand> myInsertRecentBooks; +}; + +class SaveBookStateStackRunnable : public DBRunnable { + +public: + SaveBookStateStackRunnable(DBConnection &connection); + bool run(); + void setState(int bookId, const std::deque<ReadingState > &stack); + +private: + int myBookId; + std::deque<ReadingState > myStack; + + shared_ptr<DBCommand> myTrimBookStateStack; + shared_ptr<DBCommand> mySetBookStateStack; +}; + +class DeleteFileEntriesRunnable : public DBRunnable { + +public: + DeleteFileEntriesRunnable(DBConnection &connection); + bool run(); + void setFileId(int fileId); + +private: + bool doDelete(int fileId); + +private: + int myFileId; + + shared_ptr<DBCommand> myDeleteFileEntries; + shared_ptr<DBCommand> myLoadFileEntryIds; +}; + +class DeleteBookRunnable : public DBRunnable { + +public: + DeleteBookRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName); + +private: + std::string myFileName; + + shared_ptr<FindFileIdRunnable> myFindFileId; + shared_ptr<DBCommand> myDeleteFile; +}; + + +inline InitBooksDBRunnable::InitBooksDBRunnable(DBConnection &connection) : myConnection(connection) {} +inline ClearBooksDBRunnable::ClearBooksDBRunnable(DBConnection &connection) : myConnection(connection) {} + +inline void SaveFileEntriesRunnable::setEntries(const std::string &fileName, const std::vector<std::string> &entries) { + myFileName = fileName; + myEntries = entries; // copy vector +} + +inline void SaveBookStateStackRunnable::setState(int bookId, const std::deque<ReadingState > &stack) { + myBookId = bookId; + myStack = stack; // copy deque +} + +inline void DeleteFileEntriesRunnable::setFileId(int fileId) { myFileId = fileId; } + +inline void DeleteBookRunnable::setFileName(const std::string &fileName) { myFileName = fileName; } + +/* + * Load & Modify Runnables + */ + +class FindFileIdRunnable : public DBRunnable { + +public: + FindFileIdRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName, bool add = false); + + int fileId() const; + +private: + std::string myFileName; + bool myAdd; + int myFileId; + + shared_ptr<DBCommand> myFindFileId; + shared_ptr<DBCommand> myAddFile; +}; + + +/* + * Load Runnables + */ + +class LoadFileEntriesRunnable : public DBRunnable { + +public: + LoadFileEntriesRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName); + void collectEntries(std::vector<std::string> &entries); + +private: + std::string myFileName; + std::vector<std::string> myEntries; + + shared_ptr<FindFileIdRunnable> myFindFileId; + + shared_ptr<DBCommand> myLoadFileEntries; +}; + +class LoadRecentBooksRunnable : public DBRunnable { + +public: + LoadRecentBooksRunnable(DBConnection &connection); + bool run(); + void collectFileIds(std::vector<int> &fileIds); + +private: + std::vector<int> myFileIds; + + shared_ptr<DBCommand> myLoadRecentBooks; +}; + +#endif /* __DBRUNNABLES_H__ */ diff --git a/reader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp b/reader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp new file mode 100644 index 0000000..c0c9063 --- /dev/null +++ b/reader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool ClearBooksDBRunnable::run() { + shared_ptr<DBCommand> cmd; + + cmd = SQLiteFactory::createCommand(BooksDBQuery::CLEAR_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::SECOND_INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/reader/src/database/booksdb/runnables/DeleteBookRunnable.cpp b/reader/src/database/booksdb/runnables/DeleteBookRunnable.cpp new file mode 100644 index 0000000..e9e2c14 --- /dev/null +++ b/reader/src/database/booksdb/runnables/DeleteBookRunnable.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +DeleteBookRunnable::DeleteBookRunnable(DBConnection &connection) { + myFindFileId = new FindFileIdRunnable(connection); + myDeleteFile = SQLiteFactory::createCommand(BooksDBQuery::DELETE_FILE, connection, "@file_id", DBValue::DBINT); +} + +bool DeleteBookRunnable::run() { + myFindFileId->setFileName(myFileName, true); + if (!myFindFileId->run()) { + return false; + } + + (DBIntValue &) *myDeleteFile->parameter("@file_id").value() = myFindFileId->fileId(); + return myDeleteFile->execute(); +} + diff --git a/reader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp b/reader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp new file mode 100644 index 0000000..065a4c2 --- /dev/null +++ b/reader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +DeleteFileEntriesRunnable::DeleteFileEntriesRunnable(DBConnection &connection) { + myDeleteFileEntries = SQLiteFactory::createCommand(BooksDBQuery::DELETE_FILE_ENTRIES, connection, "@file_id", DBValue::DBINT); + myLoadFileEntryIds = SQLiteFactory::createCommand(BooksDBQuery::LOAD_FILE_ENTRY_IDS, connection, "@file_id", DBValue::DBINT); +} + +bool DeleteFileEntriesRunnable::run() { + return doDelete(myFileId); +} + +bool DeleteFileEntriesRunnable::doDelete(int fileId) { + (DBIntValue &) *myLoadFileEntryIds->parameter("@file_id").value() = fileId; + shared_ptr<DBDataReader> reader = myLoadFileEntryIds->executeReader(); + if (reader.isNull()) { + return false; + } + + std::vector<int> fileIds; + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* file_id */ ) { + reader->close(); + return false; + } + fileIds.push_back(reader->intValue(0)); + } + reader->close(); + + if (fileIds.empty()) { + return true; + } + for (std::vector<int>::const_iterator it = fileIds.begin(); it != fileIds.end(); ++it) { + if (!doDelete(*it)) { + return false; + } + } + (DBIntValue &) *myDeleteFileEntries->parameter("@file_id").value() = fileId; + return myDeleteFileEntries->execute(); +} + diff --git a/reader/src/database/booksdb/runnables/FindFileIdRunnable.cpp b/reader/src/database/booksdb/runnables/FindFileIdRunnable.cpp new file mode 100644 index 0000000..4461c4f --- /dev/null +++ b/reader/src/database/booksdb/runnables/FindFileIdRunnable.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> +#include <ZLFile.h> + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string FIND_FILE_ID = + "SELECT file_id FROM Files" \ + " WHERE name = @name AND coalesce(parent_id, 0) = @parent_id;"; + +static const std::string ADD_FILE = + "INSERT INTO Files (name, parent_id, size)" \ + " VALUES(@name, nullif(@parent_id, 0), nullif(@size, 0));" \ + " SELECT last_insert_rowid() AS file_id;"; + +FindFileIdRunnable::FindFileIdRunnable(DBConnection &connection) { + myFindFileId = SQLiteFactory::createCommand(FIND_FILE_ID, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT); + myAddFile = SQLiteFactory::createCommand(ADD_FILE, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT, "@size", DBValue::DBINT); +} + +bool FindFileIdRunnable::run() { + const std::string resolvedPath = ZLFile(myFileName).resolvedPath(); + const std::string physPath = ZLFile(resolvedPath).physicalFilePath(); + const std::string dirName = physPath.substr(0, physPath.rfind(ZLibrary::FileNameDelimiter)); + + DBTextValue &findName = (DBTextValue &) *myFindFileId->parameter("@name").value(); + DBIntValue &findParent = (DBIntValue &) *myFindFileId->parameter("@parent_id").value(); + + DBTextValue &addName = (DBTextValue &) *myAddFile->parameter("@name").value(); + DBIntValue &addParent = (DBIntValue &) *myAddFile->parameter("@parent_id").value(); + ((DBIntValue &) *myAddFile->parameter("@size").value()) = 0; + + std::size_t index = dirName.length() + 1; + findName = dirName; + findParent = 0; + while (true) { + shared_ptr<DBValue> physId = myFindFileId->executeScalar(); + if (physId.isNull() || physId->type() != DBValue::DBINT || ((DBIntValue &) *physId).value() == 0) { + if (!myAdd) { + return false; + } + addName = findName.value(); + addParent = findParent.value(); + physId = myAddFile->executeScalar(); + if (physId.isNull() || physId->type() != DBValue::DBINT || ((DBIntValue &) *physId).value() == 0) { + return false; + } + } + if (index == 0) { + myFileId = ((DBIntValue &) *physId).value(); + return true; + } + std::size_t index2 = resolvedPath.find(BooksDBQuery::ArchiveEntryDelimiter, index); + findName = resolvedPath.substr(index, index2 - index); + index = index2 + 1; + findParent = ((DBIntValue &) *physId).value(); + } +} + +void FindFileIdRunnable::setFileName(const std::string &fileName, bool add) { + myFileName = fileName; + myAdd = add; + myFileId = 0; +} + +int FindFileIdRunnable::fileId() const { + return myFileId; +} + +SaveFileEntriesRunnable::SaveFileEntriesRunnable(DBConnection &connection) { + myAddFile = SQLiteFactory::createCommand(ADD_FILE, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT, "@size", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); + myDeleteFileEntries = new DeleteFileEntriesRunnable(connection); +} + +bool SaveFileEntriesRunnable::run() { + myFindFileId->setFileName(myFileName, true); + if (!myFindFileId->run()) { + return false; + } + + myDeleteFileEntries->setFileId(myFindFileId->fileId()); + if (!myDeleteFileEntries->run()) { + return false; + } + + DBTextValue &addName = (DBTextValue &) *myAddFile->parameter("@name").value(); + ((DBIntValue &) *myAddFile->parameter("@parent_id").value()) = myFindFileId->fileId(); + ((DBIntValue &) *myAddFile->parameter("@size").value()) = 0; + + for (std::vector<std::string>::const_iterator it = myEntries.begin(); it != myEntries.end(); ++it) { + const std::string &entry = (*it); + if (entry.empty()) { + continue; + } + addName = entry; + if (!myAddFile->execute()) { + return false; + } + } + return true; +} + diff --git a/reader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp b/reader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp new file mode 100644 index 0000000..b8a4b01 --- /dev/null +++ b/reader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool InitBooksDBRunnable::run() { + shared_ptr<DBCommand> cmd; + cmd = SQLiteFactory::createCommand(BooksDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::SECOND_INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/reader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp b/reader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp new file mode 100644 index 0000000..3668b83 --- /dev/null +++ b/reader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +LoadFileEntriesRunnable::LoadFileEntriesRunnable(DBConnection &connection) { + myLoadFileEntries = SQLiteFactory::createCommand(BooksDBQuery::LOAD_FILE_ENTRIES, connection, "@file_id", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); +} + +bool LoadFileEntriesRunnable::run() { + DBCommand &cmd = *myLoadFileEntries; + + myFindFileId->setFileName(myFileName); + if (!myFindFileId->run()) { + return false; + } + ((DBIntValue &) *cmd.parameter("@file_id").value()) = myFindFileId->fileId(); + + shared_ptr<DBDataReader> reader = cmd.executeReader(); + + if (reader.isNull()) { + return false; + } + + myEntries.clear(); + + bool res = true; + while (reader->next()) { + if (reader->type(0) != DBValue::DBTEXT /* name */) { + res = false; + continue; + } + myEntries.push_back( + myFileName + BooksDBQuery::ArchiveEntryDelimiter + + reader->textValue(0, std::string()) + ); + } + reader->close(); + return res; +} + +void LoadFileEntriesRunnable::setFileName(const std::string &fileName) { + myFileName = fileName; +} + +void LoadFileEntriesRunnable::collectEntries(std::vector<std::string> &entries) { + myEntries.swap(entries); + myEntries.clear(); +} diff --git a/reader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp b/reader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp new file mode 100644 index 0000000..06e6f79 --- /dev/null +++ b/reader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../library/Author.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +LoadRecentBooksRunnable::LoadRecentBooksRunnable(DBConnection &connection) { + myLoadRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::LOAD_RECENT_BOOKS, connection); +} + +bool LoadRecentBooksRunnable::run() { + shared_ptr<DBDataReader> reader = myLoadRecentBooks->executeReader(); + if (reader.isNull()) { + return false; + } + myFileIds.clear(); + + bool res = true; + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* file_id */) { + res = false; + continue; + } + const int fileId = reader->intValue(0); + myFileIds.push_back(fileId); + } + reader->close(); + return res; +} + +void LoadRecentBooksRunnable::collectFileIds(std::vector<int> &fileIds) { + myFileIds.swap(fileIds); + myFileIds.clear(); +} diff --git a/reader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp b/reader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp new file mode 100644 index 0000000..7336a74 --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../../library/Author.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveAuthorsRunnable::SaveAuthorsRunnable(DBConnection &connection) { + mySetBookAuthor = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_AUTHOR, connection, "@author_id", DBValue::DBINT, "@book_id", DBValue::DBINT, "@author_index", DBValue::DBINT); + myTrimBookAuthors = SQLiteFactory::createCommand(BooksDBQuery::TRIM_BOOK_AUTHORS, connection, "@book_id", DBValue::DBINT, "@authors_number", DBValue::DBINT); + myFindAuthorId = SQLiteFactory::createCommand(BooksDBQuery::FIND_AUTHOR_ID, connection, "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); + myAddAuthor = SQLiteFactory::createCommand(BooksDBQuery::ADD_AUTHOR, connection, "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); +} + +bool SaveAuthorsRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + const AuthorList &bookAuthors = myBook->authors(); // save link to vector + + ((DBIntValue &) *mySetBookAuthor->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &setAuthorId = (DBIntValue &) *mySetBookAuthor->parameter("@author_id").value(); + DBIntValue &setAuthorIndex = (DBIntValue &) *mySetBookAuthor->parameter("@author_index").value(); + DBTextValue &findAuthor = (DBTextValue &) *myFindAuthorId->parameter("@name").value(); + DBTextValue &findSortKey = (DBTextValue &) *myFindAuthorId->parameter("@sort_key").value(); + DBTextValue &addAuthor = (DBTextValue &) *myAddAuthor->parameter("@name").value(); + DBTextValue &addSortKey = (DBTextValue &) *myAddAuthor->parameter("@sort_key").value(); + + int index = 0; + for (AuthorList::const_iterator it = bookAuthors.begin(); it != bookAuthors.end(); ++it) { + const Author &author = **it; + findAuthor.setValue( author.name() ); + findSortKey.setValue( author.sortKey() ); + shared_ptr<DBValue> tableAuthorId = myFindAuthorId->executeScalar(); + if (tableAuthorId.isNull() || tableAuthorId->type() != DBValue::DBINT || ((DBIntValue &) *tableAuthorId).value() == 0) { + addAuthor.setValue( author.name() ); + addSortKey.setValue( author.sortKey() ); + tableAuthorId = myAddAuthor->executeScalar(); + if (tableAuthorId.isNull() || tableAuthorId->type() != DBValue::DBINT || ((DBIntValue &) *tableAuthorId).value() == 0) { + return false; + } + } + setAuthorId = ((DBIntValue &) *tableAuthorId).value(); + setAuthorIndex = ++index; + if (!mySetBookAuthor->execute()) { + return false; + } + } + ((DBIntValue &) *myTrimBookAuthors->parameter("@book_id").value()) = myBook->bookId(); + ((DBIntValue &) *myTrimBookAuthors->parameter("@authors_number").value()) = index; + return myTrimBookAuthors->execute(); +} + +void SaveAuthorsRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/reader/src/database/booksdb/runnables/SaveBookRunnable.cpp b/reader/src/database/booksdb/runnables/SaveBookRunnable.cpp new file mode 100644 index 0000000..7cf8dff --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveBookRunnable.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../library/Book.h" + +SaveBookRunnable::SaveBookRunnable(SaveTableBookRunnable &saveTableBook, SaveAuthorsRunnable &saveAuthors, + SaveSeriesRunnable &saveSeries, SaveTagsRunnable &saveTags) : + mySaveTableBook(saveTableBook), + mySaveAuthors(saveAuthors), + mySaveSeries(saveSeries), + mySaveTags(saveTags) { +} + +bool SaveBookRunnable::run() { + return mySaveTableBook.run() + && mySaveAuthors.run() + && mySaveSeries.run() + && mySaveTags.run(); +} + +void SaveBookRunnable::setBook(shared_ptr<Book> book) { + mySaveTableBook.setBook(book); + mySaveAuthors.setBook(book); + mySaveTags.setBook(book); + mySaveSeries.setBook(book); +} diff --git a/reader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp b/reader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp new file mode 100644 index 0000000..85d4a89 --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + + +SaveBookStateStackRunnable::SaveBookStateStackRunnable(DBConnection &connection) { + myTrimBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::TRIM_BOOK_STATE_STACK, connection, "@book_id", DBValue::DBINT, "@stackSize", DBValue::DBINT); + mySetBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_STATE_STACK, connection, "@book_id", DBValue::DBINT, "@position", DBValue::DBINT, "@paragraph", DBValue::DBINT, "@word", DBValue::DBINT, "@char", DBValue::DBINT); +} + +bool SaveBookStateStackRunnable::run() { + ((DBIntValue &) *myTrimBookStateStack->parameter("@book_id").value()) = myBookId; + ((DBIntValue &) *myTrimBookStateStack->parameter("@stackSize").value()) = myStack.size(); + + if (!myTrimBookStateStack->execute()) { + return false; + } + + ((DBIntValue &) *mySetBookStateStack->parameter("@book_id").value()) = myBookId; + + DBIntValue &savePosition = (DBIntValue &) *mySetBookStateStack->parameter("@position").value(); + DBIntValue &saveParagraph = (DBIntValue &) *mySetBookStateStack->parameter("@paragraph").value(); + DBIntValue &saveWord = (DBIntValue &) *mySetBookStateStack->parameter("@word").value(); + DBIntValue &saveChar = (DBIntValue &) *mySetBookStateStack->parameter("@char").value(); + + for (std::size_t i = 0; i < myStack.size(); ++i) { + const ReadingState &pos = myStack[i]; + savePosition = i + 1; + saveParagraph = pos.Paragraph; + saveWord = pos.Word; + saveChar = pos.Character; + if (!mySetBookStateStack->execute()) { + return false; + } + } + return true; +} + diff --git a/reader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp b/reader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp new file mode 100644 index 0000000..1c355ed --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveRecentBooksRunnable::SaveRecentBooksRunnable(DBConnection &connection) { + myClearRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::CLEAR_RECENT_BOOKS, connection); + myInsertRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::INSERT_RECENT_BOOKS, connection, "@book_id", DBValue::DBINT); +} + +bool SaveRecentBooksRunnable::run() { + if (!myClearRecentBooks->execute()) { + return false; + } + DBIntValue &insertBookId = (DBIntValue &) *myInsertRecentBooks->parameter("@book_id").value(); + for (BookList::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + shared_ptr<Book> book = (*it); + if (book->bookId() == 0) { + return false; + } + insertBookId = book->bookId(); + if (!myInsertRecentBooks->execute()) { + return false; + } + } + return true; +} + +void SaveRecentBooksRunnable::setBooks(const BookList &books) { + myBooks = books; // copy vector +} diff --git a/reader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp b/reader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp new file mode 100644 index 0000000..e56777b --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveSeriesRunnable::SaveSeriesRunnable(DBConnection &connection) { + mySetBookSeries = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOKSERIES, connection, "@book_id", DBValue::DBINT, "@series_id", DBValue::DBINT, "@book_index", DBValue::DBTEXT); + myDeleteBookSeries = SQLiteFactory::createCommand(BooksDBQuery::DELETE_BOOKSERIES, connection, "@book_id", DBValue::DBINT); + myFindSeriesId = SQLiteFactory::createCommand(BooksDBQuery::FIND_SERIES_ID, connection, "@name", DBValue::DBTEXT); + myAddSeries = SQLiteFactory::createCommand(BooksDBQuery::ADD_SERIES, connection, "@name", DBValue::DBTEXT); +} + +bool SaveSeriesRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + + if (myBook->seriesTitle().empty()) { + ((DBIntValue &) *myDeleteBookSeries->parameter("@book_id").value()) = myBook->bookId(); + return myDeleteBookSeries->execute(); + } + + ((DBTextValue &) *myFindSeriesId->parameter("@name").value()) = myBook->seriesTitle(); + shared_ptr<DBValue> tableSeriesId = myFindSeriesId->executeScalar(); + if (tableSeriesId.isNull() || tableSeriesId->type() != DBValue::DBINT || ((DBIntValue &) *tableSeriesId).value() == 0) { + ((DBTextValue &) *myAddSeries->parameter("@name").value()) = myBook->seriesTitle(); + tableSeriesId = myAddSeries->executeScalar(); + if (tableSeriesId.isNull() || tableSeriesId->type() != DBValue::DBINT || ((DBIntValue &) *tableSeriesId).value() == 0) { + return false; + } + } + ((DBIntValue &) *mySetBookSeries->parameter("@book_id").value()) = myBook->bookId(); + mySetBookSeries->parameter("@series_id").setValue( tableSeriesId ); + ((DBTextValue &) *mySetBookSeries->parameter("@book_index").value()) = myBook->indexInSeries().value(); + return mySetBookSeries->execute(); +} + +void SaveSeriesRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/reader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp b/reader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp new file mode 100644 index 0000000..770963e --- /dev/null +++ b/reader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveTableBookRunnable::SaveTableBookRunnable(DBConnection &connection) { + myFindBookId = SQLiteFactory::createCommand(BooksDBQuery::FIND_BOOK_ID, connection, "@file_id", DBValue::DBINT); + + myAddBook = SQLiteFactory::createCommand(BooksDBQuery::ADD_BOOK, connection, "@encoding", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@title", DBValue::DBTEXT, "@file_id", DBValue::DBINT); + myUpdateBook = SQLiteFactory::createCommand(BooksDBQuery::UPDATE_BOOK, connection, "@encoding", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@title", DBValue::DBTEXT, "@book_id", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); +} + +bool SaveTableBookRunnable::run() { + if (myBook->bookId() != 0) { + return updateTableBook(myBook); + } + + myFindFileId->setFileName(myBook->file().path(), true); + if (!myFindFileId->run()) { + return false; + } + const int fileId = myFindFileId->fileId(); + + ((DBIntValue &) *myFindBookId->parameter("@file_id").value()) = fileId; + shared_ptr<DBValue> dbBookId = myFindBookId->executeScalar(); + + if (dbBookId.isNull() || dbBookId->type() != DBValue::DBINT || ((DBIntValue &) *dbBookId).value() == 0) { + return addTableBook(myBook, fileId); + } else { + myBook->setBookId( ((DBIntValue &) *dbBookId).value() ); + return updateTableBook(myBook); + } +} + +bool SaveTableBookRunnable::addTableBook(const shared_ptr<Book> book, int fileId) { + + ((DBTextValue &) *myAddBook->parameter("@encoding").value()) = book->encoding(); + ((DBTextValue &) *myAddBook->parameter("@language").value()) = book->language(); + ((DBTextValue &) *myAddBook->parameter("@title").value()) = book->title(); + ((DBIntValue &) *myAddBook->parameter("@file_id").value()) = fileId; + shared_ptr<DBValue> dbBookId = myAddBook->executeScalar(); + + if (dbBookId.isNull() || dbBookId->type() != DBValue::DBINT || ((DBIntValue &) *dbBookId).value() == 0) { + return false; + } + book->setBookId(((DBIntValue&)*dbBookId).value()); + return true; +} + +bool SaveTableBookRunnable::updateTableBook(const shared_ptr<Book> book) { + ((DBTextValue&)*myUpdateBook->parameter("@encoding").value()) = book->encoding(); + ((DBTextValue&)*myUpdateBook->parameter("@language").value()) = book->language(); + ((DBTextValue&)*myUpdateBook->parameter("@title").value()) = book->title(); + ((DBIntValue&)*myUpdateBook->parameter("@book_id").value()) = book->bookId(); + return myUpdateBook->execute(); +} + +void SaveTableBookRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/reader/src/database/networkdb/DBRunnables.h b/reader/src/database/networkdb/DBRunnables.h new file mode 100644 index 0000000..e9633f6 --- /dev/null +++ b/reader/src/database/networkdb/DBRunnables.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DBRUNNABLES_H__ +#define __DBRUNNABLES_H__ + +#include "../sqldb/DBConnection.h" +#include "../sqldb/DBCommand.h" +#include "../sqldb/DBRunnable.h" + +#include "NetworkDBQuery.h" + +#include "../../network/NetworkLink.h" +#include "../../network/opds/OPDSLink.h" + +class InitNetworkDBRunnable : public DBRunnable { + +public: + InitNetworkDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class ClearNetworkDBRunnable : public DBRunnable { + +public: + ClearNetworkDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class SaveNetworkLinkRunnable : public DBRunnable { + +public: + SaveNetworkLinkRunnable(DBConnection &connection); + bool run(); + void setNetworkLink(shared_ptr<NetworkLink> link); + +private: + bool addNetworkLink(); + bool updateNetworkLink(int linkId); + bool updateNetworkLinkUrls(int linkId); + +private: + shared_ptr<NetworkLink> myNetworkLink; + + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myAddNetworkLink; + shared_ptr<DBCommand> myUpdateNetworkLink; + + shared_ptr<DBCommand> myFindNetworkLinkUrls; + shared_ptr<DBCommand> myAddNetworkLinkUrl; + shared_ptr<DBCommand> myUpdateNetworkLinkUrl; + shared_ptr<DBCommand> myDeleteNetworkLinkUrl; + +}; + +inline InitNetworkDBRunnable::InitNetworkDBRunnable(DBConnection &connection) : myConnection(connection) {} +inline ClearNetworkDBRunnable::ClearNetworkDBRunnable(DBConnection &connection) : myConnection(connection) {} + +#endif /* __DBRUNNABLES_H__ */ diff --git a/reader/src/database/networkdb/NetworkDB.cpp b/reader/src/database/networkdb/NetworkDB.cpp new file mode 100644 index 0000000..f422643 --- /dev/null +++ b/reader/src/database/networkdb/NetworkDB.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> +#include <ZLDir.h> + +#include "NetworkDB.h" + +shared_ptr<NetworkDB> NetworkDB::ourInstance = 0; + +const std::string NetworkDB::DATABASE_NAME = "network.db"; + +NetworkDB &NetworkDB::Instance() { + if (ourInstance.isNull()) { + ZLFile dir(databaseDirName()); + dir.directory(true); + ZLFile file(databaseDirName() + ZLibrary::FileNameDelimiter + DATABASE_NAME); + ourInstance = new NetworkDB(file.physicalFilePath()); + ourInstance->initDatabase(); + } + return *ourInstance; +} + +NetworkDB::NetworkDB(const std::string &path) : SQLiteDataBase(path), myInitialized(false) { + initCommands(); +} + +NetworkDB::~NetworkDB() { +} + +bool NetworkDB::initDatabase() { + if (isInitialized()) { + return true; + } + + if (!open()) { + return false; + } + + myInitialized = true; + + shared_ptr<DBRunnable> runnable = new InitNetworkDBRunnable(connection()); + if (!executeAsTransaction(*runnable)) { + myInitialized = false; + close(); + return false; + } + + return true; +} + +void NetworkDB::initCommands() { + myLoadNetworkLinks = SQLiteFactory::createCommand(NetworkDBQuery::LOAD_NETWORK_LINKS, connection()); + myLoadNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::LOAD_NETWORK_LINKURLS, connection(), "@link_id", DBValue::DBINT); + myFindNetworkLinkId = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINK_ID, connection(), "@site_name", DBValue::DBTEXT); + myDeleteNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINKURLS, connection(), "@link_id", DBValue::DBINT); + myDeleteNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINK, connection(), "@link_id", DBValue::DBINT); + + mySaveNetworkLink = new SaveNetworkLinkRunnable(connection()); +} + +bool NetworkDB::clearDatabase() { + if (!isInitialized()) { + return false; + } + shared_ptr<DBRunnable> runnable = new ClearNetworkDBRunnable(connection()); + return executeAsTransaction(*runnable); +} + + +bool NetworkDB::saveNetworkLink(shared_ptr<NetworkLink> link) { + if (!isInitialized()) { + return false; + } + mySaveNetworkLink->setNetworkLink(link); + bool result = executeAsTransaction(*mySaveNetworkLink); + return result; +} + +bool NetworkDB::loadNetworkLinks(std::vector<shared_ptr<NetworkLink> >& links) { + shared_ptr<DBDataReader> reader = myLoadNetworkLinks->executeReader(); + + links.clear(); + + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT) {/* link_id */ + return false; + } + std::map<std::string,std::string> linkUrls; + ((DBIntValue &) *myLoadNetworkLinkUrls->parameter("@link_id").value()) = reader->intValue(0); + shared_ptr<DBDataReader> urlreader = myLoadNetworkLinkUrls->executeReader(); + long t = 0; + while (urlreader->next()) { + linkUrls[urlreader->textValue(0, std::string())] = urlreader->textValue(1, std::string()); + t = urlreader->intValue(2); + } + shared_ptr<ATOMUpdated> atomUpdated = new ATOMUpdated(); + atomUpdated->setLongSeconds_stupid(t); + std::string iconUrl; + if (linkUrls .count("icon") != 0) { + iconUrl = linkUrls["icon"]; + linkUrls.erase("icon"); + } + std::string siteName = reader->textValue(2, std::string()); + std::string predId = reader->textValue(5, std::string()); + std::string title = reader->textValue(1, std::string()); + std::string summary = reader->textValue(3, std::string()); + std::string language = reader->textValue(4, std::string()); + bool isEnabled = reader->intValue(6) == 1; + + shared_ptr<NetworkLink> link = new OPDSLink(siteName); + link->setTitle(title); + link->setSummary(summary); + link->setLanguage(language); + link->setIcon(iconUrl); + link->setLinks(linkUrls); + link->setPredefinedId(predId); + link->setEnabled(isEnabled); + link->setUpdated(atomUpdated); + links.push_back(link); + } + return true; +} + +bool NetworkDB::deleteNetworkLink(const std::string &siteName){ + ((DBTextValue &) *myFindNetworkLinkId->parameter("@site_name").value()) = siteName; + shared_ptr<DBDataReader> reader = myFindNetworkLinkId->executeReader(); + if (reader.isNull() || !reader->next()) { + return false; + } + int linkId = reader->intValue(0); + ((DBIntValue &) *myDeleteNetworkLink->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myDeleteNetworkLinkUrls->parameter("@link_id").value()) = linkId; + return myDeleteNetworkLinkUrls->execute() && myDeleteNetworkLink->execute(); + +} diff --git a/reader/src/database/networkdb/NetworkDB.h b/reader/src/database/networkdb/NetworkDB.h new file mode 100644 index 0000000..d4761a6 --- /dev/null +++ b/reader/src/database/networkdb/NetworkDB.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKDB_H__ +#define __NETWORKDB_H__ + +#include <set> +#include <map> +#include <deque> + +#include "../sqldb/implsqlite/SQLiteDataBase.h" +#include "DBRunnables.h" + +class NetworkDB : public SQLiteDataBase { + +public: + static const std::string DATABASE_NAME; + + static NetworkDB &Instance(); + +private: + static shared_ptr<NetworkDB> ourInstance; + + NetworkDB(const std::string &path); + +public: + virtual ~NetworkDB(); + +public: + bool initDatabase(); + bool isInitialized() const; + bool clearDatabase(); + + bool saveNetworkLink(shared_ptr<NetworkLink> link); + bool loadNetworkLinks(std::vector<shared_ptr<NetworkLink> >& links); + bool deleteNetworkLink(const std::string &siteName); + +private: + void initCommands(); + +private: + bool myInitialized; + + shared_ptr<DBCommand> myLoadNetworkLinks; + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myDeleteNetworkLink; + shared_ptr<DBCommand> myDeleteNetworkLinkUrls; + shared_ptr<DBCommand> myLoadNetworkLinkUrls; + + shared_ptr<SaveNetworkLinkRunnable> mySaveNetworkLink; + +private: // disable copying + NetworkDB(const NetworkDB &); + const NetworkDB &operator = (const NetworkDB &); +}; + + +inline bool NetworkDB::isInitialized() const { return myInitialized; } + +#endif /* __NETWORKDB_H__ */ diff --git a/reader/src/database/networkdb/NetworkDBQuery.cpp b/reader/src/database/networkdb/NetworkDBQuery.cpp new file mode 100644 index 0000000..a8771cb --- /dev/null +++ b/reader/src/database/networkdb/NetworkDBQuery.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkDBQuery.h" + +const std::string NetworkDBQuery::INIT_DATABASE = \ + " CREATE TABLE IF NOT EXISTS Links( " \ + " link_id INTEGER PRIMARY KEY, " \ + " title TEXT NOT NULL, " \ + " site_name TEXT NOT NULL, " \ + " summary TEXT, " \ + " language TEXT, " \ + " predefined_id TEXT, " \ + " is_enabled INTEGER " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS LinkUrls( " \ + " key TEXT NOT NULL, " \ + " link_id INTEGER NOT NULL REFERENCES Links(link_id), " \ + " url TEXT, " \ + " update_time INTEGER, " \ + " CONSTRAINT LinkUrls_PK PRIMARY KEY (key, link_id) " \ + "); "; + +const std::string NetworkDBQuery::CLEAR_DATABASE = \ + "DROP TABLE Links; " \ + "DROP TABLE LinkUrls; "; + + +const std::string NetworkDBQuery::FIND_NETWORK_LINK_ID = "SELECT link_id, predefined_id FROM Links WHERE site_name = @site_name; "; +const std::string NetworkDBQuery::ADD_NETWORK_LINK = \ + "INSERT INTO Links (title, site_name, summary, language, predefined_id, is_enabled) " \ + " VALUES ( " \ + " @title, " \ + " @site_name, " \ + " @summary, " \ + " nullif(@language,\"\"), " \ + " nullif(@predefined_id,\"\"), " \ + " @is_enabled " \ + " ); " \ + " " \ + "SELECT last_insert_rowid() AS link_id; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINK = \ + "DELETE FROM Links WHERE link_id = @link_id; "; + +const std::string NetworkDBQuery::UPDATE_NETWORK_LINK = \ + "UPDATE Links SET " \ + " title = @title, " \ + " summary = @summary, " \ + " language = nullif(@language,\"\"), " \ + " predefined_id = nullif(@predefined_id,\"\"), " \ + " is_enabled = @is_enabled " \ + "WHERE " \ + " link_id = @link_id; "; + +const std::string NetworkDBQuery::ADD_NETWORK_LINKURL = \ + "INSERT INTO LinkUrls (key, link_id, url, update_time) " \ + " VALUES ( " \ + " @key, " \ + " @link_id, " \ + " @url, " \ + " @update_time " \ + " ); "; + +const std::string NetworkDBQuery::FIND_NETWORK_LINKURLS = "SELECT key, url, update_time FROM LinkUrls WHERE link_id = @link_id; "; + +const std::string NetworkDBQuery::UPDATE_NETWORK_LINKURL = \ + "UPDATE LinkUrls SET " \ + " url = @url, " \ + " update_time = @update_time " \ + "WHERE " \ + " link_id = @link_id AND key = @key; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINKURLS = \ + "DELETE FROM LinkUrls " \ + "WHERE " \ + " link_id = @link_id; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINKURL = \ + "DELETE FROM LinkUrls " \ + "WHERE " \ + " link_id = @link_id AND key = @key; "; + +const std::string NetworkDBQuery::LOAD_NETWORK_LINKS = "SELECT link_id, title, site_name, summary, language, predefined_id, is_enabled FROM Links; "; + +const std::string NetworkDBQuery::LOAD_NETWORK_LINKURLS = "SELECT key, url, update_time FROM LinkUrls WHERE link_id = @link_id; "; diff --git a/reader/src/database/networkdb/NetworkDBQuery.h b/reader/src/database/networkdb/NetworkDBQuery.h new file mode 100644 index 0000000..931705e --- /dev/null +++ b/reader/src/database/networkdb/NetworkDBQuery.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKDBQUERY_H__ +#define __NETWORKDBQUERY_H__ + +#include <string> + +class NetworkDBQuery { + +public: + static const std::string INIT_DATABASE; + static const std::string CLEAR_DATABASE; + + static const std::string FIND_NETWORK_LINK_ID; + static const std::string ADD_NETWORK_LINK; + static const std::string UPDATE_NETWORK_LINK; + static const std::string DELETE_NETWORK_LINK; + + static const std::string ADD_NETWORK_LINKURL; + static const std::string DELETE_NETWORK_LINKURLS; + static const std::string FIND_NETWORK_LINKURLS; + static const std::string DELETE_NETWORK_LINKURL; + static const std::string UPDATE_NETWORK_LINKURL; + + static const std::string LOAD_NETWORK_LINKS; + static const std::string LOAD_NETWORK_LINKURLS; + +private: // disable creation Instances + NetworkDBQuery(); +}; +#endif /* __NETWORKDBQUERY_H__ */ diff --git a/reader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp b/reader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp new file mode 100644 index 0000000..fe79ed3 --- /dev/null +++ b/reader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool ClearNetworkDBRunnable::run() { + shared_ptr<DBCommand> cmd; + + cmd = SQLiteFactory::createCommand(NetworkDBQuery::CLEAR_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(NetworkDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/reader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp b/reader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp new file mode 100644 index 0000000..d0730b7 --- /dev/null +++ b/reader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool InitNetworkDBRunnable::run() { + shared_ptr<DBCommand> cmd; + cmd = SQLiteFactory::createCommand(NetworkDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + return true; +} diff --git a/reader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp b/reader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp new file mode 100644 index 0000000..4c80499 --- /dev/null +++ b/reader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../DBRunnables.h" +#include "../../../network/NetworkLink.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveNetworkLinkRunnable::SaveNetworkLinkRunnable(DBConnection &connection) { + myFindNetworkLinkId = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINK_ID, connection, "@site_name", DBValue::DBTEXT); + myAddNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::ADD_NETWORK_LINK, connection, "@title", DBValue::DBTEXT, "@site_name", DBValue::DBTEXT, "@summary", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@predefined_id", DBValue::DBTEXT, "@is_enabled", DBValue::DBINT); + myUpdateNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::UPDATE_NETWORK_LINK, connection, "@title", DBValue::DBTEXT, "@summary", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@predefined_id", DBValue::DBTEXT, "@is_enabled", DBValue::DBINT, "@link_id", DBValue::DBINT); + + myFindNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINKURLS, connection, "@link_id", DBValue::DBINT); + myAddNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::ADD_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT, "@url", DBValue::DBTEXT, "@update_time", DBValue::DBINT); + myUpdateNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::UPDATE_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT, "@url", DBValue::DBTEXT, "@update_time", DBValue::DBINT); + myDeleteNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT); +} + +bool SaveNetworkLinkRunnable::run() { + if (myNetworkLink.isNull()) { + return false; + } + ((DBTextValue &) *myFindNetworkLinkId->parameter("@site_name").value()) = myNetworkLink->getSiteName(); + shared_ptr<DBDataReader> reader = myFindNetworkLinkId->executeReader(); + if (reader.isNull() || !reader->next()) { + return addNetworkLink(); + } else if (myNetworkLink->isPredefined()) { + return updateNetworkLink(reader->intValue(0)) && updateNetworkLinkUrls(reader->intValue(0)); + } else { + //TODO implement for custom links + return false; + } + return false; +} + +bool SaveNetworkLinkRunnable::addNetworkLink() { + ((DBTextValue &) *myAddNetworkLink->parameter("@title").value()) = myNetworkLink->getTitle(); + ((DBTextValue &) *myAddNetworkLink->parameter("@site_name").value()) = myNetworkLink->getSiteName(); + ((DBTextValue &) *myAddNetworkLink->parameter("@summary").value()) = myNetworkLink->getSummary(); + ((DBTextValue &) *myAddNetworkLink->parameter("@language").value()) = myNetworkLink->getLanguage(); + ((DBTextValue &) *myAddNetworkLink->parameter("@predefined_id").value()) = myNetworkLink->getPredefinedId(); + ((DBIntValue &) *myAddNetworkLink->parameter("@is_enabled").value()) = myNetworkLink->isEnabled(); + shared_ptr<DBValue> dbLinkId = myAddNetworkLink->executeScalar(); + if (dbLinkId.isNull() || dbLinkId->type() != DBValue::DBINT || ((DBIntValue &) *dbLinkId).value() == 0) { + return false; + } + + bool allExecuted = true; + std::map<std::string,std::string> tempLinks = myNetworkLink->getLinks(); + if (myNetworkLink->getIcon() != std::string()) { + tempLinks["icon"] = myNetworkLink->getIcon(); + } + long t = 0; + if (myNetworkLink->getUpdated() != 0) { + t = myNetworkLink->getUpdated()->getLongSeconds_stupid(); + } + for (std::map<std::string,std::string>::iterator it = tempLinks.begin(); it != tempLinks.end(); ++it) { + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@key").value()) = it->first; + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@url").value()) = it->second; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@link_id").value()) = ((DBIntValue &) *dbLinkId).value(); + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@update_time").value()) = t; + allExecuted = allExecuted && myAddNetworkLinkUrl->execute(); + } + return allExecuted; +} + +bool SaveNetworkLinkRunnable::updateNetworkLink(int linkId) { + ((DBTextValue &) *myUpdateNetworkLink->parameter("@title").value()) = myNetworkLink->getTitle(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@summary").value()) = myNetworkLink->getSummary(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@language").value()) = myNetworkLink->getLanguage(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@predefined_id").value()) = myNetworkLink->getPredefinedId(); + ((DBIntValue &) *myUpdateNetworkLink->parameter("@is_enabled").value()) = myNetworkLink->isEnabled(); + ((DBIntValue &) *myUpdateNetworkLink->parameter("@link_id").value()) = linkId; + + return myUpdateNetworkLink->execute(); +} + +bool SaveNetworkLinkRunnable::updateNetworkLinkUrls(int linkId) { + bool allExecuted = true; + ((DBIntValue &) *myFindNetworkLinkUrls->parameter("@link_id").value()) = linkId; + shared_ptr<DBDataReader> reader = myFindNetworkLinkUrls->executeReader(); + std::map<std::string,std::string> linksToCheck = myNetworkLink->getLinks(); + if (!myNetworkLink->getIcon().empty()) { + linksToCheck["icon"] = myNetworkLink->getIcon(); + } + long t = 0; + if (!myNetworkLink->getUpdated().isNull()) { + t = myNetworkLink->getUpdated()->getLongSeconds_stupid(); + } + while (reader->next()) { + if (reader->type(0) != DBValue::DBTEXT || reader->type(1) != DBValue::DBTEXT) { + return false; + } + std::string key = reader->textValue(0, std::string()); +// std::string url = reader->textValue(1, std::string()); + if (linksToCheck.count(key) == 0) { + ((DBTextValue &) *myDeleteNetworkLinkUrl->parameter("@key").value()) = key; + ((DBIntValue &) *myDeleteNetworkLinkUrl->parameter("@link_id").value()) = linkId; + allExecuted = allExecuted && myDeleteNetworkLinkUrl->execute(); + } else { + ((DBTextValue &) *myUpdateNetworkLinkUrl->parameter("@key").value()) = key; + ((DBTextValue &) *myUpdateNetworkLinkUrl->parameter("@url").value()) = linksToCheck[key]; + ((DBIntValue &) *myUpdateNetworkLinkUrl->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myUpdateNetworkLinkUrl->parameter("@update_time").value()) = t; + linksToCheck.erase(key); + allExecuted = allExecuted && myUpdateNetworkLinkUrl->execute(); + } + } + + for (std::map<std::string,std::string>::iterator it = linksToCheck.begin(); it != linksToCheck.end(); ++it) { + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@key").value()) = it->first; + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@url").value()) = it->second; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@update_time").value()) = t; + allExecuted = allExecuted && myAddNetworkLinkUrl->execute(); + } + return allExecuted; +} + +void SaveNetworkLinkRunnable::setNetworkLink(shared_ptr<NetworkLink> link) { + myNetworkLink = link; +} diff --git a/reader/src/database/sqldb/DBCommand.cpp b/reader/src/database/sqldb/DBCommand.cpp new file mode 100644 index 0000000..8986401 --- /dev/null +++ b/reader/src/database/sqldb/DBCommand.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#include "DBCommand.h" +#include <algorithm> + +DBCommand::DBCommand(const std::string &command, DBConnection &connection) + : myParameters() + , myCommandString(command) + , myConnection(connection) { +} + +DBCommand::~DBCommand() { +} + + +class ParameterPredicate { + +public: + ParameterPredicate(const std::string &name); + bool operator () (const DBCommandParameter &p); +private: + const std::string &myName; +}; + +ParameterPredicate::ParameterPredicate(const std::string &name) : myName(name) {} + +bool ParameterPredicate::operator () (const DBCommandParameter &p) { + return p.name() == myName; +} + + +DBCommandParameter &DBCommand::parameter(const std::string &name) { + std::vector<DBCommandParameter>::iterator it = std::find_if(myParameters.begin(), myParameters.end(), ParameterPredicate(name)); + return *it; +} + +const DBCommandParameter &DBCommand::parameters(const std::string &name) const { + std::vector<DBCommandParameter>::const_iterator it = std::find_if(myParameters.begin(), myParameters.end(), ParameterPredicate(name)); + return *it; +} + diff --git a/reader/src/database/sqldb/DBCommand.h b/reader/src/database/sqldb/DBCommand.h new file mode 100644 index 0000000..2ac9ade --- /dev/null +++ b/reader/src/database/sqldb/DBCommand.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __DBCOMMAND_H__ +#define __DBCOMMAND_H__ + +#include "DBCommandParameter.h" +#include "DBDataReader.h" +#include "DBConnection.h" + +class DBCommand { + +public: + DBCommand(const std::string &command, DBConnection &connection); + virtual ~DBCommand(); + + std::vector<DBCommandParameter> ¶meters(); + const std::vector<DBCommandParameter> ¶meters() const; + + DBCommandParameter ¶meter(const std::string &name); + const DBCommandParameter ¶meters(const std::string &name) const; + + const std::string &commandString() const; + +protected: + const DBConnection &connection() const; + +public: // to implement: + virtual bool execute() = 0; + virtual shared_ptr<DBValue> executeScalar() = 0; + virtual shared_ptr<DBDataReader> executeReader() = 0; + +private: // against copying: + DBCommand(const DBCommand &); + const DBCommand &operator = (const DBCommand &); + +private: + std::vector<DBCommandParameter> myParameters; + const std::string myCommandString; + const DBConnection &myConnection; +}; + + +inline std::vector<DBCommandParameter> &DBCommand::parameters() { return myParameters; } +inline const std::vector<DBCommandParameter> &DBCommand::parameters() const { return myParameters; } + +inline const std::string &DBCommand::commandString() const { return myCommandString; } +inline const DBConnection &DBCommand::connection() const { return myConnection; } + + +#endif /* __DBCOMMAND_H__ */ + diff --git a/reader/src/database/sqldb/DBCommandParameter.cpp b/reader/src/database/sqldb/DBCommandParameter.cpp new file mode 100644 index 0000000..d8ec08a --- /dev/null +++ b/reader/src/database/sqldb/DBCommandParameter.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#include "DBCommandParameter.h" + + +DBCommandParameter::DBCommandParameter() + : myName(""), myValue(DBValue::create(DBValue::DBNULL)) { +} + +DBCommandParameter::DBCommandParameter(const std::string &name) + : myName(name), myValue(DBValue::create(DBValue::DBNULL)) { +} + +DBCommandParameter::DBCommandParameter(DBValue::ValueType type) + : myName(""), myValue(DBValue::create(type)) { +} + +DBCommandParameter::DBCommandParameter(const std::string &name, DBValue::ValueType type) + : myName(name), myValue(DBValue::create(type)) { +} + +DBCommandParameter::DBCommandParameter(shared_ptr<DBValue> value) + : myName(""), myValue(value) { + if (value.isNull()) { + myValue = DBValue::create(DBValue::DBNULL); + } +} + +DBCommandParameter::DBCommandParameter(const std::string &name, shared_ptr<DBValue> value) + : myName(name), myValue(value) { + if (value.isNull()) { + myValue = DBValue::create(DBValue::DBNULL); + } +} + +DBCommandParameter::DBCommandParameter(const DBCommandParameter ¶meter) + : myName(parameter.name()), myValue(parameter.value()) { +} + +const DBCommandParameter &DBCommandParameter::operator = (const DBCommandParameter ¶meter) { + myName = parameter.name(); + myValue = parameter.value(); + return *this; +} + diff --git a/reader/src/database/sqldb/DBCommandParameter.h b/reader/src/database/sqldb/DBCommandParameter.h new file mode 100644 index 0000000..2e3c8ae --- /dev/null +++ b/reader/src/database/sqldb/DBCommandParameter.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __DBCOMMANDPARAMETERS_H__ +#define __DBCOMMANDPARAMETERS_H__ + +#include <vector> + +#include "DBValues.h" + + +class DBCommandParameter { + +public: + // create anonymous parameter with DBNULL value: + DBCommandParameter(); + + // create named parameter with DBNULL value: + DBCommandParameter(const std::string &name); + + // create anonymous parameter with default value of specified type: + DBCommandParameter(DBValue::ValueType type); + + // create named parameter with default value of specified type: + DBCommandParameter(const std::string &name, DBValue::ValueType type); + + // create anonymous parameter with specified value: + DBCommandParameter(shared_ptr<DBValue> value); + + // create named parameter with specified value: + DBCommandParameter(const std::string &name, shared_ptr<DBValue> value); + +public: + const std::string &name() const; + void setName(const std::string &name); + + shared_ptr<DBValue> value() const; + void setValue(shared_ptr<DBValue> value); + + DBValue::ValueType type() const; + + bool hasName() const; + +public: // implement copying: + DBCommandParameter(const DBCommandParameter &par); + const DBCommandParameter &operator = (const DBCommandParameter &par); + +private: + std::string myName; + DBValue::ValueType myType; + shared_ptr<DBValue> myValue; +}; + + +inline const std::string &DBCommandParameter::name() const { return myName; } +inline void DBCommandParameter::setName(const std::string &name) { myName = name; } +inline shared_ptr<DBValue> DBCommandParameter::value() const { return myValue; } +inline void DBCommandParameter::setValue(shared_ptr<DBValue> value) { myValue = value; } +inline DBValue::ValueType DBCommandParameter::type() const { return myValue->type(); } +inline bool DBCommandParameter::hasName() const { return myName != ""; } + + +#endif /* __DBCOMMANDPARAMETERS_H__ */ + diff --git a/reader/src/database/sqldb/DBConnection.cpp b/reader/src/database/sqldb/DBConnection.cpp new file mode 100644 index 0000000..20f4402 --- /dev/null +++ b/reader/src/database/sqldb/DBConnection.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#include "DBConnection.h" + +DBConnection::DBConnection() { +} + +DBConnection::~DBConnection() { +} + diff --git a/reader/src/database/sqldb/DBConnection.h b/reader/src/database/sqldb/DBConnection.h new file mode 100644 index 0000000..2345ddf --- /dev/null +++ b/reader/src/database/sqldb/DBConnection.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __DBCONNECTION_H__ +#define __DBCONNECTION_H__ + +class DBConnection { +public: + DBConnection(); + virtual ~DBConnection(); + +public: // to implement: + virtual bool open() = 0; + virtual bool close() = 0; + virtual bool isOpened() const = 0; + +private: // against copying: + DBConnection(const DBConnection &); + const DBConnection &operator = (const DBConnection &); +}; + +#endif /* __DBCONNECTION_H__ */ + diff --git a/reader/src/database/sqldb/DBDataReader.cpp b/reader/src/database/sqldb/DBDataReader.cpp new file mode 100644 index 0000000..7c40b03 --- /dev/null +++ b/reader/src/database/sqldb/DBDataReader.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBDataReader.h" + +DBDataReader::DBDataReader() { +} + +DBDataReader::~DBDataReader() { +} diff --git a/reader/src/database/sqldb/DBDataReader.h b/reader/src/database/sqldb/DBDataReader.h new file mode 100644 index 0000000..f07b323 --- /dev/null +++ b/reader/src/database/sqldb/DBDataReader.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DBDATAREADER_H__ +#define __DBDATAREADER_H__ + +#include "DBValues.h" + +class DBDataReader { + +public: + DBDataReader(); + virtual ~DBDataReader(); + +public: // to implement: + virtual bool next() = 0; + virtual bool reset() = 0; + virtual void close() = 0; + + virtual std::size_t columnsNumber() const = 0; + + virtual DBValue::ValueType type(std::size_t column) const = 0; + virtual shared_ptr<DBValue> value(std::size_t column) const = 0; + + virtual int intValue(std::size_t column) const = 0; + virtual double realValue(std::size_t column) const = 0; + virtual std::string textValue(std::size_t column, const std::string &defaultValue) const = 0; + +public: + bool isDBNull(std::size_t column) const; + bool isInt(std::size_t column) const; + bool isReal(std::size_t column) const; + bool isText(std::size_t column) const; +}; + +inline bool DBDataReader::isDBNull(std::size_t column) const { return type(column) == DBValue::DBNULL; } +inline bool DBDataReader::isInt(std::size_t column) const { return type(column) == DBValue::DBINT; } +inline bool DBDataReader::isReal(std::size_t column) const { return type(column) == DBValue::DBREAL; } +inline bool DBDataReader::isText(std::size_t column) const { return type(column) == DBValue::DBTEXT; } + +#endif /* __DBDATAREADER_H__ */ + diff --git a/reader/src/database/sqldb/DBIntValue.cpp b/reader/src/database/sqldb/DBIntValue.cpp new file mode 100644 index 0000000..cd3e900 --- /dev/null +++ b/reader/src/database/sqldb/DBIntValue.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBValues.h" + + +DBIntValue::DBIntValue() + : myValue(0) { +} + +DBIntValue::DBIntValue(int value) + : myValue(value) { +} + +DBIntValue::~DBIntValue() { +} + +DBValue::ValueType DBIntValue::type() const { + return DBINT; +} + diff --git a/reader/src/database/sqldb/DBNullValue.cpp b/reader/src/database/sqldb/DBNullValue.cpp new file mode 100644 index 0000000..cd6ab1c --- /dev/null +++ b/reader/src/database/sqldb/DBNullValue.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBValues.h" + +const shared_ptr<DBValue> DBNullValue::Instance = new DBNullValue(); + + +DBNullValue::DBNullValue() { +} + +DBNullValue::~DBNullValue() { +} + +DBValue::ValueType DBNullValue::type() const { + return DBNULL; +} + diff --git a/reader/src/database/sqldb/DBRealValue.cpp b/reader/src/database/sqldb/DBRealValue.cpp new file mode 100644 index 0000000..eb849e5 --- /dev/null +++ b/reader/src/database/sqldb/DBRealValue.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBValues.h" + + +DBRealValue::DBRealValue() + : myValue(0.0) { +} + +DBRealValue::DBRealValue(double value) + : myValue(value) { +} + +DBRealValue::~DBRealValue() { +} + +DBValue::ValueType DBRealValue::type() const { + return DBREAL; +} + diff --git a/reader/src/database/sqldb/DBRunnable.h b/reader/src/database/sqldb/DBRunnable.h new file mode 100644 index 0000000..8e44a67 --- /dev/null +++ b/reader/src/database/sqldb/DBRunnable.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DBRUNNABLE_H__ +#define __DBRUNNABLE_H__ + + +class DBRunnable { + +public: + virtual ~DBRunnable() {} + + virtual bool run() = 0; +}; + +#endif /* __DBRUNNABLE_H__ */ diff --git a/reader/src/database/sqldb/DBTextValue.cpp b/reader/src/database/sqldb/DBTextValue.cpp new file mode 100644 index 0000000..27b4d96 --- /dev/null +++ b/reader/src/database/sqldb/DBTextValue.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBValues.h" + + +DBTextValue::DBTextValue() + : myValue("") { +} + +DBTextValue::DBTextValue(const std::string &value) + : myValue(value) { +} + +DBTextValue::~DBTextValue() { +} + +DBValue::ValueType DBTextValue::type() const { + return DBTEXT; +} + + +DBTextValue::DBTextValue(const DBTextValue &value) + : DBValue() + , myValue(value.myValue) { +} + +const DBTextValue &DBTextValue::operator = (const DBTextValue &value) { + myValue = value.myValue; + return *this; +} + diff --git a/reader/src/database/sqldb/DBValue.cpp b/reader/src/database/sqldb/DBValue.cpp new file mode 100644 index 0000000..75c4376 --- /dev/null +++ b/reader/src/database/sqldb/DBValue.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "DBValues.h" + + +DBValue::DBValue() { +} + +DBValue::~DBValue() { +} + +shared_ptr<DBValue> DBValue::create(ValueType type) { + switch (type) { + case DBNULL: + return DBNullValue::Instance; + case DBINT: + return new DBIntValue(); + case DBREAL: + return new DBRealValue(); + case DBTEXT: + return new DBTextValue(); + } + return 0; +} + diff --git a/reader/src/database/sqldb/DBValues.h b/reader/src/database/sqldb/DBValues.h new file mode 100644 index 0000000..eb64d56 --- /dev/null +++ b/reader/src/database/sqldb/DBValues.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __DBVALUES_H__ +#define __DBVALUES_H__ + +#include <string> +#include <shared_ptr.h> + + +class DBValue { + +public: + enum ValueType { + DBNULL, + DBINT, + DBREAL, + DBTEXT, + }; + + static shared_ptr<DBValue> create(ValueType type); + +public: + DBValue(); + virtual ~DBValue(); + +public: // to implement: + virtual ValueType type() const = 0; +}; + +class DBNullValue : public DBValue { + +friend class DBValue; + +public: + static const shared_ptr<DBValue> Instance; // the only Instance of DBNullValue class + +private: + DBNullValue(); + ~DBNullValue(); + +public: + ValueType type() const; +}; + +class DBIntValue : public DBValue { + +friend class DBValue; + +protected: + DBIntValue(); + +public: + DBIntValue(int value); + ~DBIntValue(); + + ValueType type() const; + + int value() const; + void setValue(int value); + const DBIntValue &operator = (int value); + +private: + int myValue; +}; + +class DBRealValue : public DBValue { + +friend class DBValue; + +protected: + DBRealValue(); + +public: + DBRealValue(double value); + ~DBRealValue(); + + ValueType type() const; + + double value() const; + void setValue(double value); + const DBRealValue &operator = (double value); + +private: + double myValue; +}; + +class DBTextValue : public DBValue { + +friend class DBValue; + +protected: + DBTextValue(); + +public: + DBTextValue(const std::string &value); + ~DBTextValue(); + + ValueType type() const; + + const std::string &value() const; + void setValue(const std::string &value); + const DBTextValue &operator = (const std::string &value); + +public: + DBTextValue(const DBTextValue &value); + const DBTextValue &operator = (const DBTextValue &value); + +private: + std::string myValue; +}; + + + +inline int DBIntValue::value() const { return myValue; } +inline void DBIntValue::setValue(int value) { myValue = value; } +inline const DBIntValue &DBIntValue::operator = (int value) { myValue = value; return *this; } + +inline double DBRealValue::value() const { return myValue; } +inline void DBRealValue::setValue(double value) { myValue = value; } +inline const DBRealValue &DBRealValue::operator = (double value) { myValue = value; return *this; } + +inline const std::string &DBTextValue::value() const { return myValue; } +inline void DBTextValue::setValue(const std::string &value) { myValue = value; } +inline const DBTextValue &DBTextValue::operator = (const std::string &value) { myValue = value; return *this; } + +#endif /* __DBVALUES_H__ */ + diff --git a/reader/src/database/sqldb/DataBase.cpp b/reader/src/database/sqldb/DataBase.cpp new file mode 100644 index 0000000..e1d0b3f --- /dev/null +++ b/reader/src/database/sqldb/DataBase.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> + +#include "DataBase.h" + +std::string DataBase::databaseDirName() { + return ZLibrary::ApplicationWritableDirectory(); +} + +DataBase::~DataBase() { +} + + diff --git a/reader/src/database/sqldb/DataBase.h b/reader/src/database/sqldb/DataBase.h new file mode 100644 index 0000000..33430aa --- /dev/null +++ b/reader/src/database/sqldb/DataBase.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __DATABASE_H__ +#define __DATABASE_H__ + +#include <shared_ptr.h> + +#include "DBConnection.h" +#include "DBRunnable.h" + +class DataBase { + +public: + static std::string databaseDirName(); + +public: + DataBase(shared_ptr<DBConnection> connection); + virtual ~DataBase(); + + DBConnection &connection() const; + +protected: + virtual bool executeAsTransaction(DBRunnable &runnable) = 0; + +private: + shared_ptr<DBConnection> myConnection; + +private: // against copying: + DataBase(const DataBase &); + const DataBase &operator = (const DataBase &); +}; + +inline DataBase::DataBase(shared_ptr<DBConnection> connection) : myConnection(connection) { } + +inline DBConnection &DataBase::connection() const { return *myConnection; } + +#endif /* __DATABASE_H__ */ diff --git a/reader/src/database/sqldb/implsqlite/SQLiteCommand.cpp b/reader/src/database/sqldb/implsqlite/SQLiteCommand.cpp new file mode 100644 index 0000000..58d90f6 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteCommand.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <iostream> +#include <algorithm> + +#include <ZLLogger.h> +#include <ZLStringUtil.h> + +#include "SQLiteCommand.h" + +#include "SQLiteConnection.h" +#include "SQLiteDataReader.h" + + +std::string SQLiteCommand::packCommand(const std::string &command) { + static const char _spaces[] = " \t\n"; + std::string stripped = command; + ZLStringUtil::stripWhiteSpaces(stripped); + + std::size_t pos = 0; + while (true) { + pos = stripped.find_first_of(_spaces, pos); + if (pos == std::string::npos) { + break; + } + stripped[pos++] = ' '; + const std::size_t next = stripped.find_first_not_of(_spaces, pos); + if (pos != std::string::npos && next > pos) { + stripped.erase(pos, next - pos); + } + } + return stripped; +} + + +SQLiteCommand::~SQLiteCommand() { + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (con.isOpened() && myStatements.size() != 0) { + finalizeStatements(); + } +} + + +bool SQLiteCommand::execute() { + ZLLogger::Instance().println("sqlite", "execute: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return false; + } + if (!prepareStatements(con)) { + return false; + } + std::vector<sqlite3_stmt *>::iterator it = myStatements.begin(); + std::vector<sqlite3_stmt *>::iterator end = myStatements.end(); + while (true) { + int res = sqlite3_step(*it); + switch (res) { + case SQLITE_DONE: + if (++it == end) { + resetStatements(); + return true; + } + break; + case SQLITE_OK: + case SQLITE_ROW: + break; + default: + dumpError(); + finalizeStatements(); + return false; + } + } +} + +shared_ptr<DBValue> SQLiteCommand::executeScalar() { + ZLLogger::Instance().println("sqlite", "executeScalar: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return 0; + } + if (!prepareStatements(con)) { + return 0; + } + std::vector<sqlite3_stmt *>::iterator it = myStatements.begin(); + std::vector<sqlite3_stmt *>::iterator end = myStatements.end(); + while (true) { + int res = sqlite3_step(*it); + switch (res) { + case SQLITE_DONE: + if (++it == end) { + resetStatements(); + return 0; + } + break; + case SQLITE_OK: + break; + case SQLITE_ROW: { + shared_ptr<DBValue> val = SQLiteDataReader::makeDBValue(*it, /* column = */ 0); + resetStatements(); + return val; + } + default: + dumpError(); + finalizeStatements(); + return 0; + } + } +} + +shared_ptr<DBDataReader> SQLiteCommand::executeReader() { + ZLLogger::Instance().println("sqlite", "executeReader: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return 0; + } + if (!prepareStatements(con)) { + return 0; + } + myLocked = true; + return new SQLiteDataReader(*this); +} + + +bool SQLiteCommand::prepareStatements(SQLiteConnection &conn) { + sqlite3 *db = conn.database(); + if (myLocked) { + return false; + } + if (myStatements.size() != 0) { + const std::size_t size = myStatements.size(); + int res = SQLITE_OK; + for (std::size_t i = 0; i < size && res == SQLITE_OK; ++i) { + res = sqlite3_reset(myStatements[i]); + } + if (res == SQLITE_OK) { + bindParameters(); + return true; + } + finalizeStatements(); + } + const std::string sql = commandString(); + const int length = -1; + const char *tail = sql.c_str(); + while (true) { + sqlite3_stmt *statement; + int res = sqlite3_prepare_v2(db, tail, length, &statement, &tail); + if (res != SQLITE_OK) { + dumpError(); + finalizeStatements(); + return false; + } + if (statement == 0) { + break; + } + myStatements.push_back(statement); + conn.addStatement(statement); + } + if (!bindParameters()) { + finalizeStatements(); + return false; + } + return true; +} + + +void SQLiteCommand::prepareBindContext() { + if (myBindContext.size() > 0) { + return; + } + + std::size_t number = 0; + + for (std::size_t i = 0; i < myStatements.size(); ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int count = sqlite3_bind_parameter_count(statement); + for (int j = 1; j <= count; ++j) { + ++number; + const char *name = sqlite3_bind_parameter_name(statement, j); + if (name == 0) { + myBindContext.push_back(BindParameter(number)); + } else { + const std::string namestr(name); + if (std::find_if(myBindContext.begin(), myBindContext.end(), BindParameterComparator(namestr)) == myBindContext.end()) { + myBindContext.push_back(BindParameter(number, namestr)); + } + } + } + } +} + + +bool SQLiteCommand::bindParameters() { + prepareBindContext(); + + std::vector<DBCommandParameter> ¶ms = parameters(); + + bool res = true; + const std::size_t size = params.size(); + for (std::size_t i = 0; i < size; ++i) { + DBCommandParameter &p = params[i]; + if (p.hasName()) { + const std::string &name = p.name(); + if (!bindParameterByName(name, p.value())) { + res = false; + } + } else if (i < myBindContext.size()) { + BindParameter &bp = myBindContext[i]; + if (myBindContext[i].hasName()) { + if (!bindParameterByName(bp.Name, p.value())) { + res = false; + } + } else { + if (!bindParameterByIndex(bp.Position, p.value())) { + res = false; + } + } + } else { + res = false; + } + } + return res; +} + + +bool SQLiteCommand::bindParameterByName(const std::string &name, shared_ptr<DBValue> value) { + const std::size_t size = myStatements.size(); + bool res = true; + bool binded = false; + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int index = sqlite3_bind_parameter_index(statement, name.c_str()); + if (index == 0) { + continue; + } + binded = true; + if (!bindParameter(statement, index, value)) { + res = false; + } + } + if (!binded) { + dumpError("parameter \"" + name + "\" is not found"); + } + return res; +} + +bool SQLiteCommand::bindParameterByIndex(std::size_t index, shared_ptr<DBValue> value) { + if (index == 0) { + return true; + } + const std::size_t size = myStatements.size(); + int number = index; + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int count = sqlite3_bind_parameter_count(statement); + if (number > count) { + number -= count; + continue; + } + return bindParameter(statement, number, value); + } + return true; +} + +bool SQLiteCommand::bindParameter(sqlite3_stmt *statement, int number, shared_ptr<DBValue> value) { + DBValue::ValueType type = (value.isNull()) ? (DBValue::DBNULL) : (value->type()); + int res; + switch (type) { + case DBValue::DBNULL: + res = sqlite3_bind_null(statement, number); + break; + case DBValue::DBINT: + res = sqlite3_bind_int(statement, number, ((DBIntValue &) *value).value()); + break; + case DBValue::DBREAL: + res = sqlite3_bind_double(statement, number, ((DBRealValue &) *value).value()); + break; + case DBValue::DBTEXT: + res = sqlite3_bind_text(statement, number, ((DBTextValue &) *value).value().c_str(), -1 /* zero-terminated string */, SQLITE_TRANSIENT); + break; + default: + return false; + } + if (res != SQLITE_OK) { + dumpError(); + } + return res == SQLITE_OK; +} + + +void SQLiteCommand::finalizeStatements() { + SQLiteConnection &con = (SQLiteConnection &) connection(); + const std::size_t size = myStatements.size(); + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + con.removeStatement(statement); + const int res = sqlite3_finalize(statement); + if (res != SQLITE_OK) { + dumpError(); + } + } + myStatements.clear(); +} + + +void SQLiteCommand::dumpError() const { + static const std::size_t cmdlimit = 114; + ((SQLiteConnection &) connection()).dumpError(); + const std::string &cmd = commandString(); + if (cmd.length() > cmdlimit) { + std::cerr << "SQLITE IMPLEMENTATION ERROR: in command \"" << cmd.substr(0, cmdlimit - 3) << "...\"" << std::endl; + } else { + std::cerr << "SQLITE IMPLEMENTATION ERROR: in command \"" << cmd << "\"" << std::endl; + } +} + +void SQLiteCommand::dumpError(const std::string &msg) const { + static const std::size_t cmdlimit = 129; + std::cerr << "SQLITE ERROR: " << msg << std::endl; + const std::string &cmd = commandString(); + if (cmd.length() > cmdlimit) { + std::cerr << "SQLITE ERROR: in command \"" << cmd.substr(0, cmdlimit - 3) << "...\"" << std::endl; + } else { + std::cerr << "SQLITE ERROR: in command \"" << cmd << "\"" << std::endl; + } +} + +bool SQLiteCommand::resetStatements() { + if (myStatements.size() == 0) { + return true; + } + const std::size_t size = myStatements.size(); + int res = SQLITE_OK; + for (std::size_t i = 0; i < size && res == SQLITE_OK; ++i) { + res = sqlite3_reset(myStatements[i]); + } + if (res == SQLITE_OK) { + return true; + } + dumpError(); + finalizeStatements(); + return false; +} + diff --git a/reader/src/database/sqldb/implsqlite/SQLiteCommand.h b/reader/src/database/sqldb/implsqlite/SQLiteCommand.h new file mode 100644 index 0000000..395fd30 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteCommand.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __SQLITECOMMAND_H__ +#define __SQLITECOMMAND_H__ + +#include <sqlite3.h> + +#include "../DBCommand.h" + +#include "SQLiteConnection.h" + + +/* + * Command can contain parameters with following names: + * ? - anonymous parameter + * @AAA - named parameter + * + * where AAA is alpha-numeric parameter name + */ +class SQLiteCommand : public DBCommand { + +public: + static std::string packCommand(const std::string &command); + +public: + SQLiteCommand(const std::string &command, DBConnection &connection); + ~SQLiteCommand(); + + bool execute(); + shared_ptr<DBValue> executeScalar(); + shared_ptr<DBDataReader> executeReader(); + +public: + void unlock(); + + // TODO: hide sqlite3_stmt object inside + std::vector<sqlite3_stmt *> &statements(); + const std::vector<sqlite3_stmt *> &statements() const; + + void dumpError() const; + void dumpError(const std::string &msg) const; + + bool resetStatements(); + +private: + + struct BindParameter { + std::size_t Position; + std::string Name; + + BindParameter(std::size_t pos) : Position(pos), Name("") {} + BindParameter(std::size_t pos, const std::string &name) : Position(pos), Name(name) {} + + bool hasName() const; + }; + + class BindParameterComparator { + + public: + BindParameterComparator(const std::string &name); + bool operator () (const SQLiteCommand::BindParameter &p) const; + + private: + const std::string myName; + }; + + void prepareBindContext(); + bool bindParameters(); + bool bindParameterByName(const std::string &name, shared_ptr<DBValue> value); + bool bindParameterByIndex(std::size_t index, shared_ptr<DBValue> value); + bool bindParameter(sqlite3_stmt *statement, int number, shared_ptr<DBValue> value); + bool prepareStatements(SQLiteConnection &conn); + + void finalizeStatements(); + +private: + std::vector<sqlite3_stmt *> myStatements; + std::vector<BindParameter> myBindContext; + bool myLocked; + +private: // disable copying: + SQLiteCommand(const SQLiteCommand &); + const SQLiteCommand &operator = (const SQLiteCommand &); +}; + + +inline SQLiteCommand::SQLiteCommand(const std::string &command, DBConnection &connection) + : DBCommand(SQLiteCommand::packCommand(command), connection), myStatements(), myLocked(false) {} + +inline void SQLiteCommand::unlock() { myLocked = false; } +inline std::vector<sqlite3_stmt *> &SQLiteCommand::statements() { return myStatements; } +inline const std::vector<sqlite3_stmt *> &SQLiteCommand::statements() const { return myStatements; } + +inline bool SQLiteCommand::BindParameter::hasName() const { return Name.size() > 0; } + +inline SQLiteCommand::BindParameterComparator::BindParameterComparator(const std::string &name) : myName(name) {} +inline bool SQLiteCommand::BindParameterComparator::operator () (const SQLiteCommand::BindParameter &p) const { return myName == p.Name; } + +#endif /* __SQLITECOMMAND_H__ */ diff --git a/reader/src/database/sqldb/implsqlite/SQLiteConnection.cpp b/reader/src/database/sqldb/implsqlite/SQLiteConnection.cpp new file mode 100644 index 0000000..f1a0f30 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteConnection.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <iostream> + +#include "SQLiteConnection.h" + +SQLiteConnection::SQLiteConnection(const std::string &name) + : DBConnection() + , myName(name) + , myDatabase(0) { +} + +SQLiteConnection::~SQLiteConnection() { + if (isOpened()) { + close(); + } +} + + +bool SQLiteConnection::open() { + if (myDatabase != 0) { + return true; + } + int res = sqlite3_open(myName.c_str(), &myDatabase); + if (res == SQLITE_OK) { + return true; + } + dumpError(); + if (myDatabase != 0) { + sqlite3_close(myDatabase); + myDatabase = 0; + } + return false; +} + +void SQLiteConnection::finalizeOpenedStatements() { + std::size_t size = myStatements.size(); + for (std::size_t i = 0; i < size; ++i) { + const int res = sqlite3_finalize(myStatements[i]); + if (res != SQLITE_OK) { + dumpError(); + } + } + myStatements.clear(); +} + +bool SQLiteConnection::close() { + if (myDatabase == 0) { + return true; + } + + finalizeOpenedStatements(); + + int res = sqlite3_close(myDatabase); + if (res == SQLITE_OK) { + myDatabase = 0; + return true; + } + dumpError(); + return false; +} + +void SQLiteConnection::dumpError() const { + if (myDatabase != 0) { + const std::string msg = sqlite3_errmsg(myDatabase); // TODO: error & message handling + const int code = sqlite3_errcode(myDatabase); // TODO: error & message handling + std::cerr << "SQLITE IMPLEMENTATION ERROR: (" << code << ") " << msg << std::endl; + } +} diff --git a/reader/src/database/sqldb/implsqlite/SQLiteConnection.h b/reader/src/database/sqldb/implsqlite/SQLiteConnection.h new file mode 100644 index 0000000..6854800 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteConnection.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __SQLITECONNECTION_H__ +#define __SQLITECONNECTION_H__ + +#include <sqlite3.h> + +#include <algorithm> +#include <vector> +#include <string> + +#include "../DBConnection.h" + +class SQLiteConnection : public DBConnection { + +public: + SQLiteConnection(const std::string &name); + ~SQLiteConnection(); + + bool open(); + bool close(); + bool isOpened() const; + +public: + const std::string &name() const; + + sqlite3 *database(); // TODO: hide sqlite3 object inside + + void addStatement(sqlite3_stmt *statement); + void removeStatement(sqlite3_stmt *statement); + +public: + void dumpError() const; + +private: + void finalizeOpenedStatements(); + +private: + const std::string myName; + sqlite3 *myDatabase; + std::vector<sqlite3_stmt *> myStatements; + +private: // disable copying: + SQLiteConnection(const SQLiteConnection &); + const SQLiteConnection &operator = (const SQLiteConnection &); +}; + + +inline const std::string &SQLiteConnection::name() const { return myName; } +inline sqlite3 *SQLiteConnection::database() { return myDatabase; } + +inline void SQLiteConnection::addStatement(sqlite3_stmt *statement) { myStatements.push_back(statement); } + +inline void SQLiteConnection::removeStatement(sqlite3_stmt *statement) { + std::vector<sqlite3_stmt *>::iterator it = std::find(myStatements.begin(), myStatements.end(), statement); + if (it != myStatements.end()) { + myStatements.erase(it); + } +} + +inline bool SQLiteConnection::isOpened() const { return myDatabase != 0; } + + +#endif /* __SQLITECONNECTION_H__ */ diff --git a/reader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp b/reader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp new file mode 100644 index 0000000..1cccc0a --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#include <ZLStringUtil.h> + +#include "SQLiteDataBase.h" + +#include "SQLiteConnection.h" +#include "SQLiteCommand.h" + +//----------- Transaction subclass ----------------- + +SQLiteDataBase::Transaction::Transaction(SQLiteDataBase &db) : myDataBase(db), mySuccess(false), myStarted(false), myDepth((unsigned int)-1) { +} + +SQLiteDataBase::Transaction::~Transaction() { + if (myStarted) { + end(mySuccess); + } +} + +bool SQLiteDataBase::Transaction::start() { + myDepth = myDataBase.myTransactionDepth; + if (myDepth == 0) { + myStarted = myDataBase.myBeginTransaction->execute(); + } else { + //((DBTextValue &) *myDataBase.myMakeSavePoint->parameter("@name").value()).setValue(name()); + //myStarted = myDataBase.myMakeSavePoint->execute(); + myStarted = true; + } + if (myStarted) { + ++myDataBase.myTransactionDepth; + } + return myStarted; +} + +void SQLiteDataBase::Transaction::end(bool success) { + --myDataBase.myTransactionDepth; + if (myDepth == 0) { + if (success) { + myDataBase.myCommitTransaction->execute(); + } else { + myDataBase.myRollbackTransaction->execute(); + } + } else { + if (success) { + //((DBTextValue &) *myDataBase.myCommitSavePoint->parameter("@name").value()).setValue(name()); + //myDataBase.myCommitSavePoint->execute(); + } else { + //((DBTextValue &) *myDataBase.myRollbackSavePoint->parameter("@name").value()).setValue(name()); + //myDataBase.myRollbackSavePoint->execute(); + } + } +} + +std::string SQLiteDataBase::Transaction::name() const { + std::string name = "tran"; + ZLStringUtil::appendNumber(name, myDepth); + return name; +} + +//----------- End Transaction subclass ----------------- + + + +SQLiteDataBase::SQLiteDataBase(const std::string &path) : DataBase( new SQLiteConnection(path) ), myTransactionDepth(0) { + myBeginTransaction = SQLiteFactory::createCommand("BEGIN IMMEDIATE TRANSACTION", connection()); + myCommitTransaction = SQLiteFactory::createCommand("COMMIT TRANSACTION", connection()); + myRollbackTransaction = SQLiteFactory::createCommand("ROLLBACK TRANSACTION", connection()); + myMakeSavePoint = SQLiteFactory::createCommand("SAVEPOINT @name", connection(), "@name", DBValue::DBTEXT); + myCommitSavePoint = SQLiteFactory::createCommand("RELEASE @name", connection(), "@name", DBValue::DBTEXT); + myRollbackSavePoint = SQLiteFactory::createCommand("ROLLBACK TO @name; RELEASE @name", connection(), "@name", DBValue::DBTEXT); +} + +SQLiteDataBase::~SQLiteDataBase() { + if (connection().isOpened()) { + connection().close(); + } +} + +bool SQLiteDataBase::executeAsTransaction(DBRunnable &runnable) { + Transaction tran(*this); + if (tran.start() && runnable.run()) { + tran.setSuccessful(); + return true; + } + return false; +} + + diff --git a/reader/src/database/sqldb/implsqlite/SQLiteDataBase.h b/reader/src/database/sqldb/implsqlite/SQLiteDataBase.h new file mode 100644 index 0000000..dce8e5b --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteDataBase.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __SQLITEDATABASE_H__ +#define __SQLITEDATABASE_H__ + +#include "../DataBase.h" +#include "../DBCommand.h" + +#include "SQLiteFactory.h" + + +class SQLiteDataBase : public DataBase { + +public: + SQLiteDataBase(const std::string &path); + virtual ~SQLiteDataBase(); + + bool open(); + void close(); + +public: + bool executeAsTransaction(DBRunnable &runnable); + +private: + friend class Transaction; + + class Transaction { + public: + Transaction(SQLiteDataBase &db); + ~Transaction(); + public: + bool start(); + void setSuccessful(); + private: + void end(bool success); + std::string name() const; + private: + SQLiteDataBase &myDataBase; + bool mySuccess; + bool myStarted; + unsigned int myDepth; + }; + +private: // Transaction handling + unsigned int myTransactionDepth; + shared_ptr<DBCommand> myBeginTransaction; + shared_ptr<DBCommand> myCommitTransaction; + shared_ptr<DBCommand> myRollbackTransaction; + shared_ptr<DBCommand> myMakeSavePoint; + shared_ptr<DBCommand> myCommitSavePoint; + shared_ptr<DBCommand> myRollbackSavePoint; + +private: // disable copying: + SQLiteDataBase(const SQLiteDataBase &); + const SQLiteDataBase &operator = (const SQLiteDataBase &); +}; + +inline bool SQLiteDataBase::open() { return connection().open(); } +inline void SQLiteDataBase::close() { connection().close(); } + +inline void SQLiteDataBase::Transaction::setSuccessful() { mySuccess = true; } + + +#endif /* __SQLITEDATABASE_H__ */ diff --git a/reader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp b/reader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp new file mode 100644 index 0000000..3ea4091 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "SQLiteDataReader.h" + +shared_ptr<DBValue> SQLiteDataReader::makeDBValue(sqlite3_stmt *statement, std::size_t column) { + if (column >= (std::size_t) sqlite3_column_count(statement)) { + return 0; + } + const int type = sqlite3_column_type(statement, column); + switch (type) { + case SQLITE_INTEGER: return new DBIntValue(sqlite3_column_int(statement, column)); + case SQLITE_FLOAT: return new DBRealValue(sqlite3_column_double(statement, column)); + case SQLITE_TEXT: return new DBTextValue((const char *) sqlite3_column_text(statement, column)); + case SQLITE_NULL: return DBValue::create(DBValue::DBNULL); + } + return 0; +} + +SQLiteDataReader::SQLiteDataReader(SQLiteCommand &command) : + myCommand(command), + myCurrentStatement(0), + myLocked(true) { +} + +SQLiteDataReader::~SQLiteDataReader() { + close(); +} + +bool SQLiteDataReader::next() { + const std::vector<sqlite3_stmt *> &statements = myCommand.statements(); + while (true) { + int res = sqlite3_step(statements[myCurrentStatement]); + switch (res) { + case SQLITE_OK: + break; + case SQLITE_ROW: + return true; + case SQLITE_DONE: + if (++myCurrentStatement >= statements.size()) { + return false; + } + break; + default: + myCommand.dumpError(); + return false; + } + } +} + +bool SQLiteDataReader::reset() { + return myCommand.resetStatements(); +} + +void SQLiteDataReader::close() { + if (myLocked) { + reset(); + myCommand.unlock(); + myLocked = false; + } +} + +std::size_t SQLiteDataReader::columnsNumber() const { + sqlite3_stmt *statement = currentStatement(); + return sqlite3_column_count(statement); +} + +DBValue::ValueType SQLiteDataReader::type(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t) sqlite3_column_count(statement)) { + return DBValue::DBNULL; + } + const int type = sqlite3_column_type(statement, column); + switch (type) { + case SQLITE_INTEGER: return DBValue::DBINT; + case SQLITE_FLOAT: return DBValue::DBREAL; + case SQLITE_TEXT: return DBValue::DBTEXT; + case SQLITE_NULL: return DBValue::DBNULL; + default: + return DBValue::DBNULL; + } +} + +shared_ptr<DBValue> SQLiteDataReader::value(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + return makeDBValue(statement, column); +} + +int SQLiteDataReader::intValue(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t)sqlite3_column_count(statement) || + sqlite3_column_type(statement, column) != SQLITE_INTEGER) { + return 0; + } + return sqlite3_column_int(statement, column); +} + +double SQLiteDataReader::realValue(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t)sqlite3_column_count(statement) || + sqlite3_column_type(statement, column) != SQLITE_FLOAT) { + return 0; + } + return sqlite3_column_double(statement, column); +} + +std::string SQLiteDataReader::textValue(std::size_t column, const std::string &defaultValue) const { + sqlite3_stmt *statement = currentStatement(); + if (column < (std::size_t)sqlite3_column_count(statement) && + sqlite3_column_type(statement, column) == SQLITE_TEXT) { + const char *result = (const char*)sqlite3_column_text(statement, column); + if (result != 0) { + return result; + } + } + return defaultValue; +} diff --git a/reader/src/database/sqldb/implsqlite/SQLiteDataReader.h b/reader/src/database/sqldb/implsqlite/SQLiteDataReader.h new file mode 100644 index 0000000..b220b39 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteDataReader.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __SQLITEDATAREADER_H__ +#define __SQLITEDATAREADER_H__ + +#include "../DBDataReader.h" + +#include "SQLiteCommand.h" +#include "SQLiteConnection.h" + +class SQLiteDataReader : public DBDataReader { + +public: + static shared_ptr<DBValue> makeDBValue(sqlite3_stmt *statement, std::size_t column); + +public: + SQLiteDataReader(SQLiteCommand &command); + ~SQLiteDataReader(); + + bool next(); + bool reset(); + void close(); + + std::size_t columnsNumber() const; + + DBValue::ValueType type(std::size_t column) const; + + shared_ptr<DBValue> value(std::size_t column) const; + + int intValue(std::size_t column) const; + double realValue(std::size_t column) const; + std::string textValue(std::size_t column, const std::string &defaultValue) const; + +private: + sqlite3_stmt *currentStatement() const; + +private: + SQLiteCommand &myCommand; + std::size_t myCurrentStatement; + bool myLocked; +}; + + +inline sqlite3_stmt *SQLiteDataReader::currentStatement() const { return myCommand.statements()[myCurrentStatement]; } + +#endif /* __SQLITEDATAREADER_H__ */ diff --git a/reader/src/database/sqldb/implsqlite/SQLiteFactory.cpp b/reader/src/database/sqldb/implsqlite/SQLiteFactory.cpp new file mode 100644 index 0000000..5054cc9 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteFactory.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#include "SQLiteFactory.h" + +#include "SQLiteCommand.h" + + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection) { + return new SQLiteCommand(command, connection); +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + cmd->parameters().push_back( DBCommandParameter(name5, type5) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5, + const std::string &name6, DBValue::ValueType type6) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + cmd->parameters().push_back( DBCommandParameter(name5, type5) ); + cmd->parameters().push_back( DBCommandParameter(name6, type6) ); + + return cmd; +} + diff --git a/reader/src/database/sqldb/implsqlite/SQLiteFactory.h b/reader/src/database/sqldb/implsqlite/SQLiteFactory.h new file mode 100644 index 0000000..b58b785 --- /dev/null +++ b/reader/src/database/sqldb/implsqlite/SQLiteFactory.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + + +#ifndef __SQLITEFACTORY_H__ +#define __SQLITEFACTORY_H__ + +#include "../DBConnection.h" +#include "../DBCommand.h" + +class SQLiteFactory { + +private: + SQLiteFactory(); + +public: + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5, const std::string &name6, DBValue::ValueType type6); +}; + + +#endif /* __SQLITEFACTORY_H__ */ diff --git a/reader/src/encodingOption/EncodingOptionEntry.cpp b/reader/src/encodingOption/EncodingOptionEntry.cpp new file mode 100644 index 0000000..04d25d0 --- /dev/null +++ b/reader/src/encodingOption/EncodingOptionEntry.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <shared_ptr.h> +#include <ZLEncodingConverter.h> +#include <ZLUnicodeUtil.h> + +#include "EncodingOptionEntry.h" + +#include "../library/Book.h" + +AbstractEncodingEntry::AbstractEncodingEntry(const std::string ¤tValue) { + if (currentValue == Book::AutoEncoding) { + myInitialSetName = currentValue; + myInitialValues[currentValue] = currentValue; + setActive(false); + return; + } + + const std::string &value = ZLUnicodeUtil::toLower(currentValue); + + const std::vector<shared_ptr<ZLEncodingSet> > &sets = ZLEncodingCollection::Instance().sets(); + for (std::vector<shared_ptr<ZLEncodingSet> >::const_iterator it = sets.begin(); it != sets.end(); ++it) { + const std::vector<ZLEncodingConverterInfoPtr> &infos = (*it)->infos(); + mySetNames.push_back((*it)->name()); + std::vector<std::string> &names = myValues[(*it)->name()]; + for (std::vector<ZLEncodingConverterInfoPtr>::const_iterator jt = infos.begin(); jt != infos.end(); ++jt) { + const std::vector<std::string> &aliases = (*jt)->aliases(); + for (std::vector<std::string>::const_iterator kt = aliases.begin(); kt != aliases.end(); ++kt) { + if (value == ZLUnicodeUtil::toLower(*kt)) { + myInitialSetName = (*it)->name(); + myInitialValues[myInitialSetName] = (*jt)->visibleName(); + break; + } + } + names.push_back((*jt)->visibleName()); + myValueByName[(*jt)->visibleName()] = (*jt)->name(); + } + } + + if (myInitialSetName.empty()) { + myInitialSetName = mySetNames[0]; + } +} + +const std::vector<std::string> &AbstractEncodingEntry::values() const { + if (initialValue() == Book::AutoEncoding) { + static std::vector<std::string> AUTO_ENCODING; + if (AUTO_ENCODING.empty()) { + AUTO_ENCODING.push_back(Book::AutoEncoding); + } + return AUTO_ENCODING; + } + std::map<std::string,std::vector<std::string> >::const_iterator it = myValues.find(myInitialSetName); + return it->second; +} + +const std::string &AbstractEncodingEntry::initialValue() const { + if (myInitialValues[myInitialSetName].empty()) { + std::map<std::string,std::vector<std::string> >::const_iterator it = myValues.find(myInitialSetName); + myInitialValues[myInitialSetName] = it->second[0]; + } + return myInitialValues[myInitialSetName]; +} + +void AbstractEncodingEntry::onAccept(const std::string &value) { + if (initialValue() != Book::AutoEncoding) { + onAcceptValue(myValueByName[value]); + } +} + +void AbstractEncodingEntry::onValueSelected(int index) { + myInitialValues[myInitialSetName] = values()[index]; +} + + + + + +EncodingEntry::EncodingEntry(ZLStringOption &encodingOption) : + AbstractEncodingEntry(encodingOption.value()), + myEncodingOption(encodingOption) { +} + +void EncodingEntry::onAcceptValue(const std::string &value) { + myEncodingOption.setValue(value); +} + + + + +EncodingSetEntry::EncodingSetEntry(AbstractEncodingEntry &encodingEntry) : myEncodingEntry(encodingEntry) { +} + +const std::string &EncodingSetEntry::initialValue() const { + return myEncodingEntry.myInitialSetName; +} + +const std::vector<std::string> &EncodingSetEntry::values() const { + return myEncodingEntry.mySetNames; +} + +void EncodingSetEntry::onValueSelected(int index) { + myEncodingEntry.myInitialSetName = values()[index]; + myEncodingEntry.resetView(); +} diff --git a/reader/src/encodingOption/EncodingOptionEntry.h b/reader/src/encodingOption/EncodingOptionEntry.h new file mode 100644 index 0000000..7b43c60 --- /dev/null +++ b/reader/src/encodingOption/EncodingOptionEntry.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ENCODINGOPTIONENTRY_H__ +#define __ENCODINGOPTIONENTRY_H__ + +#include <map> + +#include <ZLOptionEntry.h> + +class AbstractEncodingEntry : public ZLComboOptionEntry { + +public: + AbstractEncodingEntry(const std::string ¤tValue); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + void onValueSelected(int index); + + virtual void onAcceptValue(const std::string &value) = 0; + +private: + std::vector<std::string> mySetNames; + std::map<std::string,std::vector<std::string> > myValues; + mutable std::map<std::string,std::string> myInitialValues; + std::map<std::string,std::string> myValueByName; + std::string myInitialSetName; + +friend class EncodingSetEntry; +}; + +class EncodingEntry : public AbstractEncodingEntry { + +public: + EncodingEntry(ZLStringOption &encodingOption); + + void onAcceptValue(const std::string &value); + +private: + ZLStringOption &myEncodingOption; +}; + +class EncodingSetEntry : public ZLComboOptionEntry { + +public: + EncodingSetEntry(AbstractEncodingEntry &encodingEntry); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string&) {} + void onValueSelected(int index); + +private: + AbstractEncodingEntry &myEncodingEntry; +}; + +#endif /* __ENCODINGOPTIONENTRY_H__ */ diff --git a/reader/src/external/ProgramCollection.cpp b/reader/src/external/ProgramCollection.cpp new file mode 100644 index 0000000..9599d90 --- /dev/null +++ b/reader/src/external/ProgramCollection.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLXMLReader.h> +#include <ZLResource.h> + +#include "ProgramCollection.h" +#include "../options/FBCategoryKey.h" + +class ProgramCollectionBuilder : public ZLXMLReader { + +public: + ProgramCollectionBuilder(ProgramCollectionMap &collectionMap); + ~ProgramCollectionBuilder(); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + +private: + ProgramCollectionMap &myCollectionMap; + shared_ptr<ProgramCollection> myCurrentCollection; + shared_ptr<Program> myCurrentProgram; +}; + +static const std::string SECTION = "section"; +static const std::string PROGRAM = "program"; +static const std::string ACTION = "action"; +static const std::string OPTION = "option"; + +ProgramCollectionBuilder::ProgramCollectionBuilder(ProgramCollectionMap &collectionMap) : myCollectionMap(collectionMap) { +} + +ProgramCollectionBuilder::~ProgramCollectionBuilder() { +} + +void ProgramCollectionBuilder::startElementHandler(const char *tag, const char **attributes) { + if (SECTION == tag) { + const char *name = attributeValue(attributes, "name"); + if (name != 0) { + myCurrentCollection = myCollectionMap.myMap[name]; + if (myCurrentCollection.isNull()) { + myCurrentCollection = new ProgramCollection(name); + myCollectionMap.myMap[name] = myCurrentCollection; + } + } + } else if (!myCurrentCollection.isNull() && (PROGRAM == tag)) { + const char *name = attributeValue(attributes, "name"); + const char *protocol = attributeValue(attributes, "protocol"); + const char *testFile = attributeValue(attributes, "testFile"); + if ((name != 0) && (protocol != 0)) { + shared_ptr<ZLMessageOutputChannel> channel = + ZLCommunicationManager::Instance().createMessageOutputChannel(protocol, (testFile != 0) ? testFile : ""); + if (!channel.isNull()) { + std::string sName = name; + if (!sName.empty()) { + if (sName[0] == '%') { + sName = ZLResource::resource("external")[sName.substr(1)].value(); + } + myCurrentProgram = new Program(sName, channel); + myCurrentCollection->myNames.push_back(sName); + myCurrentCollection->myPrograms[sName] = myCurrentProgram; + } + } + } + } else if (!myCurrentProgram.isNull() && (ACTION == tag)) { + const char *name = attributeValue(attributes, "name"); + if (name != 0) { + static const std::string NAME = "name"; + ZLCommunicationManager::Data &data = myCurrentProgram->myCommandData[name]; + for (const char **it = attributes; (*it != 0) && (*(it + 1) != 0); it += 2) { + if (NAME != *it) { + data[*it] = *(it + 1); + } + } + } + } else if (!myCurrentProgram.isNull() && (OPTION == tag)) { + const char *name = attributeValue(attributes, "name"); + if (name != 0) { + const char *defaultValue = attributeValue(attributes, "defaultValue"); + const std::string sName = name; + const std::string sDefaultValue = (defaultValue != 0) ? defaultValue : std::string(); + myCurrentProgram->myOptions.push_back(Program::OptionDescription(sName, sDefaultValue)); + myCurrentProgram->myDefaultValues[sName] = sDefaultValue; + } + } +} + +void ProgramCollectionBuilder::endElementHandler(const char *tag) { + if (SECTION == tag) { + if (!myCurrentCollection.isNull()) { + const std::vector<std::string> &names = myCurrentCollection->names(); + ZLStringOption &nameOption = myCurrentCollection->CurrentNameOption; + if (!names.empty() && (std::find(names.begin(), names.end(), nameOption.value()) == names.end())) { + nameOption.setValue(names.front()); + } + } + myCurrentCollection = 0; + myCurrentProgram = 0; + } else if (PROGRAM == tag) { + myCurrentProgram = 0; + } +} + +ProgramCollectionMap::ProgramCollectionMap() { + ProgramCollectionBuilder builder(*this); + builder.readDocument(ZLFile(ZLibrary::DefaultFilesPathPrefix() + "external.xml")); +} + +shared_ptr<ProgramCollection> ProgramCollectionMap::collection(const std::string &name) const { + std::map<std::string,shared_ptr<ProgramCollection> >::const_iterator it = myMap.find(name); + return (it != myMap.end()) ? it->second : 0; +} + +ProgramCollection::ProgramCollection(const std::string &name) : + EnableCollectionOption(ZLCategoryKey::CONFIG, name, "Enabled", true), + CurrentNameOption(ZLCategoryKey::CONFIG, name, "Name", "") { +} + +const std::vector<std::string> &ProgramCollection::names() const { + return myNames; +} + +shared_ptr<Program> ProgramCollection::program(const std::string &name) const { + std::map<std::string,shared_ptr<Program> >::const_iterator it = myPrograms.find(name); + return (it != myPrograms.end()) ? it->second : 0; +} + +shared_ptr<Program> ProgramCollection::currentProgram() const { + if (!EnableCollectionOption.value()) { + return 0; + } + return program(CurrentNameOption.value()); +} + +Program::Program(const std::string &name, shared_ptr<ZLMessageOutputChannel> channel) : myName(name), myChannel(channel) { +} + +void Program::run(const std::string &command, const std::string ¶meter) const { + if (!myChannel.isNull()) { + std::map<std::string,ZLCommunicationManager::Data>::const_iterator it = myCommandData.find(command); + if (it != myCommandData.end()) { + ZLCommunicationManager::Data data = it->second; + for (ZLCommunicationManager::Data::iterator jt = data.begin(); jt != data.end(); ++jt) { + if (!jt->second.empty() && jt->second[0] == '%') { + const std::string optionName = jt->second.substr(1); + std::map<std::string,std::string>::const_iterator st = myDefaultValues.find(optionName); + jt->second = ZLStringOption( + FBCategoryKey::EXTERNAL, + myName, + optionName, + (st != myDefaultValues.end()) ? st->second : "").value(); + } + } + shared_ptr<ZLMessageSender> sender = myChannel->createSender(data); + if (!sender.isNull()) { + sender->sendStringMessage(parameter); + } + } + } +} + +const std::vector<Program::OptionDescription> &Program::options() const { + return myOptions; +} + +Program::OptionDescription::OptionDescription(const std::string &name, const std::string &defaultValue) : OptionName(name), DefaultValue(defaultValue) { +} diff --git a/reader/src/external/ProgramCollection.h b/reader/src/external/ProgramCollection.h new file mode 100644 index 0000000..a8aa3ec --- /dev/null +++ b/reader/src/external/ProgramCollection.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PROGRAMCOLLECTION_H__ +#define __PROGRAMCOLLECTION_H__ + +#include <string> +#include <map> +#include <vector> + +#include <shared_ptr.h> +#include <ZLMessage.h> +#include <ZLOptions.h> + +class Program { + +private: + Program(const std::string &name, shared_ptr<ZLMessageOutputChannel> channel); + +public: + void run(const std::string &command, const std::string ¶meter) const; + +public: + struct OptionDescription { + OptionDescription(const std::string &name, const std::string &defaultValue); + std::string OptionName; + std::string DefaultValue; + }; + const std::vector<OptionDescription> &options() const; + +private: + const std::string myName; + shared_ptr<ZLMessageOutputChannel> myChannel; + std::map<std::string,ZLCommunicationManager::Data> myCommandData; + std::vector<OptionDescription> myOptions; + std::map<std::string,std::string> myDefaultValues; + +friend class ProgramCollection; +friend class ProgramCollectionBuilder; +}; + +class ProgramCollection { + +public: + mutable ZLBooleanOption EnableCollectionOption; + mutable ZLStringOption CurrentNameOption; + +public: + ProgramCollection(const std::string &name); + + const std::vector<std::string> &names() const; + shared_ptr<Program> currentProgram() const; + shared_ptr<Program> program(const std::string &name) const; + +private: + std::vector<std::string> myNames; + std::map<std::string,shared_ptr<Program> > myPrograms; + +friend class ProgramCollectionBuilder; +}; + +class ProgramCollectionMap { + +public: + ProgramCollectionMap(); + shared_ptr<ProgramCollection> collection(const std::string &name) const; + +private: + std::map<std::string,shared_ptr<ProgramCollection> > myMap; + +friend class ProgramCollectionBuilder; +}; + +#endif /* __PROGRAMCOLLECTION_H__ */ diff --git a/reader/src/formats/EncodedTextReader.cpp b/reader/src/formats/EncodedTextReader.cpp new file mode 100644 index 0000000..12102c1 --- /dev/null +++ b/reader/src/formats/EncodedTextReader.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "EncodedTextReader.h" + +EncodedTextReader::EncodedTextReader(const std::string &encoding) { + ZLEncodingCollection &collection = ZLEncodingCollection::Instance(); + ZLEncodingConverterInfoPtr info = collection.info(encoding); + myConverter = !info.isNull() ? info->createConverter() : collection.defaultConverter(); +} + +EncodedTextReader::~EncodedTextReader() { +} diff --git a/reader/src/formats/EncodedTextReader.h b/reader/src/formats/EncodedTextReader.h new file mode 100644 index 0000000..8035508 --- /dev/null +++ b/reader/src/formats/EncodedTextReader.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ENCODEDTEXTREADER_H__ +#define __ENCODEDTEXTREADER_H__ + +#include <string> + +#include <ZLEncodingConverter.h> + +class EncodedTextReader { + +protected: + EncodedTextReader(const std::string &encoding); + virtual ~EncodedTextReader(); + +protected: + shared_ptr<ZLEncodingConverter> myConverter; +}; + +#endif /* __ENCODEDTEXTREADER_H__ */ diff --git a/reader/src/formats/FormatPlugin.cpp b/reader/src/formats/FormatPlugin.cpp new file mode 100644 index 0000000..059a53b --- /dev/null +++ b/reader/src/formats/FormatPlugin.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> +#include <ZLLanguageDetector.h> +#include <ZLImage.h> + +#include "FormatPlugin.h" + +#include "../library/Book.h" + +bool FormatPlugin::detectEncodingAndLanguage(Book &book, ZLInputStream &stream, bool force) { + std::string language = book.language(); + std::string encoding = book.encoding(); + if (!force && !encoding.empty() && !language.empty()) { + return true; + } + + bool detected = false; + + PluginCollection &collection = PluginCollection::Instance(); + if (language.empty()) { + language = collection.DefaultLanguageOption.value(); + } + if (encoding.empty()) { + encoding = collection.DefaultEncodingOption.value(); + } + if (collection.LanguageAutoDetectOption.value() && stream.open()) { + static const int BUFSIZE = 65536; + char *buffer = new char[BUFSIZE]; + const std::size_t size = stream.read(buffer, BUFSIZE); + stream.close(); + shared_ptr<ZLLanguageDetector::LanguageInfo> info = + ZLLanguageDetector().findInfo(buffer, size); + delete[] buffer; + if (!info.isNull()) { + detected = true; + if (!info->Language.empty()) { + language = info->Language; + } + encoding = info->Encoding; + if (encoding == "US-ASCII" || encoding == "ISO-8859-1") { + encoding = "windows-1252"; + } + } + } + book.setEncoding(encoding); + book.setLanguage(language); + return detected; +} + +bool FormatPlugin::detectLanguage(Book &book, ZLInputStream &stream, const std::string &encoding, bool force) { + std::string language = book.language(); + if (!force && !language.empty()) { + return true; + } + + bool detected = false; + + PluginCollection &collection = PluginCollection::Instance(); + if (language.empty()) { + language = collection.DefaultLanguageOption.value(); + } + if (collection.LanguageAutoDetectOption.value() && stream.open()) { + static const int BUFSIZE = 65536; + char *buffer = new char[BUFSIZE]; + const std::size_t size = stream.read(buffer, BUFSIZE); + stream.close(); + shared_ptr<ZLLanguageDetector::LanguageInfo> info = + ZLLanguageDetector().findInfoForEncoding(encoding, buffer, size, -20000); + delete[] buffer; + if (!info.isNull()) { + if (!info->Language.empty()) { + detected = true; + language = info->Language; + } + } + } + book.setLanguage(language); + return detected; +} + +const std::string &FormatPlugin::tryOpen(const ZLFile&) const { + static const std::string EMPTY = ""; + return EMPTY; +} + +shared_ptr<const ZLImage> FormatPlugin::coverImage(const ZLFile &file) const { + return 0; +} diff --git a/reader/src/formats/FormatPlugin.h b/reader/src/formats/FormatPlugin.h new file mode 100644 index 0000000..5e1075e --- /dev/null +++ b/reader/src/formats/FormatPlugin.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FORMATPLUGIN_H__ +#define __FORMATPLUGIN_H__ + +#include <string> +#include <vector> + +#include <shared_ptr.h> +#include <ZLOptions.h> + +class Book; +class BookModel; +class ZLOptionsDialog; +class ZLOptionsDialogTab; +class ZLFile; +class ZLInputStream; +class ZLImage; + +class FormatInfoPage { + +protected: + FormatInfoPage(); + +public: + virtual ~FormatInfoPage(); +}; + +class FormatPlugin { + +protected: + FormatPlugin(); + +public: + virtual ~FormatPlugin(); + + virtual bool providesMetaInfo() const = 0; + virtual bool acceptsFile(const ZLFile &file) const = 0; + virtual FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); + + virtual const std::string &tryOpen(const ZLFile &file) const; + virtual bool readMetaInfo(Book &book) const = 0; + virtual bool readLanguageAndEncoding(Book &book) const = 0; + virtual bool readModel(BookModel &model) const = 0; + virtual shared_ptr<const ZLImage> coverImage(const ZLFile &file) const; + +protected: + static bool detectEncodingAndLanguage(Book &book, ZLInputStream &stream, bool force = false); + static bool detectLanguage(Book &book, ZLInputStream &stream, const std::string &encoding, bool force = false); +}; + +class PluginCollection { + +public: + ZLBooleanOption LanguageAutoDetectOption; + ZLStringOption DefaultLanguageOption; + ZLStringOption DefaultEncodingOption; + +public: + static PluginCollection &Instance(); + static void deleteInstance(); + +private: + PluginCollection(); + +public: + shared_ptr<FormatPlugin> plugin(const ZLFile &file, bool strong); + shared_ptr<FormatPlugin> plugin(const Book &book); + +private: + static PluginCollection *ourInstance; + + std::vector<shared_ptr<FormatPlugin> > myPlugins; +}; + +inline FormatInfoPage::FormatInfoPage() {} +inline FormatInfoPage::~FormatInfoPage() {} +inline FormatPlugin::FormatPlugin() {} +inline FormatPlugin::~FormatPlugin() {} +inline FormatInfoPage *FormatPlugin::createInfoPage(ZLOptionsDialog&, const ZLFile&) { return 0; } + +#endif /* __FORMATPLUGIN_H__ */ diff --git a/reader/src/formats/PluginCollection.cpp b/reader/src/formats/PluginCollection.cpp new file mode 100644 index 0000000..d120de1 --- /dev/null +++ b/reader/src/formats/PluginCollection.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> +#include <ZLFile.h> + +#include "FormatPlugin.h" + +#include "../library/Book.h" + +#include "fb2/FB2Plugin.h" +//#include "docbook/DocBookPlugin.h" +#include "html/HtmlPlugin.h" +#include "txt/TxtPlugin.h" +#include "pdb/PdbPlugin.h" +#include "tcr/TcrPlugin.h" +#include "oeb/OEBPlugin.h" +#include "chm/CHMPlugin.h" +#include "rtf/RtfPlugin.h" +#include "openreader/OpenReaderPlugin.h" +#include "doc/DocPlugin.h" +//#include "pdf/PdfPlugin.h" + +PluginCollection *PluginCollection::ourInstance = 0; + +PluginCollection &PluginCollection::Instance() { + if (ourInstance == 0) { + ourInstance = new PluginCollection(); + ourInstance->myPlugins.push_back(new FB2Plugin()); + //ourInstance->myPlugins.push_back(new DocBookPlugin()); + ourInstance->myPlugins.push_back(new HtmlPlugin()); + ourInstance->myPlugins.push_back(new TxtPlugin()); + ourInstance->myPlugins.push_back(new PluckerPlugin()); + ourInstance->myPlugins.push_back(new PalmDocPlugin()); + ourInstance->myPlugins.push_back(new MobipocketPlugin()); + ourInstance->myPlugins.push_back(new EReaderPlugin()); + ourInstance->myPlugins.push_back(new ZTXTPlugin()); + ourInstance->myPlugins.push_back(new TcrPlugin()); + ourInstance->myPlugins.push_back(new CHMPlugin()); + ourInstance->myPlugins.push_back(new OEBPlugin()); + ourInstance->myPlugins.push_back(new RtfPlugin()); + ourInstance->myPlugins.push_back(new OpenReaderPlugin()); + ourInstance->myPlugins.push_back(new DocPlugin()); + //ourInstance->myPlugins.push_back(new PdfPlugin()); + } + return *ourInstance; +} + +void PluginCollection::deleteInstance() { + if (ourInstance != 0) { + delete ourInstance; + ourInstance = 0; + } +} + +PluginCollection::PluginCollection() : + LanguageAutoDetectOption(ZLCategoryKey::CONFIG, "Format", "AutoDetect", true), + DefaultLanguageOption(ZLCategoryKey::CONFIG, "Format", "DefaultLanguageS", ZLibrary::Language()), + DefaultEncodingOption(ZLCategoryKey::CONFIG, "Format", "DefaultEncoding", "UTF-8") { +} + +shared_ptr<FormatPlugin> PluginCollection::plugin(const Book &book) { + return plugin(book.file(), false); +} + +shared_ptr<FormatPlugin> PluginCollection::plugin(const ZLFile &file, bool strong) { + for (std::vector<shared_ptr<FormatPlugin> >::const_iterator it = myPlugins.begin(); it != myPlugins.end(); ++it) { + if ((!strong || (*it)->providesMetaInfo()) && (*it)->acceptsFile(file)) { + return *it; + } + } + return 0; +} diff --git a/reader/src/formats/chm/BitStream.cpp b/reader/src/formats/chm/BitStream.cpp new file mode 100644 index 0000000..bf6c642 --- /dev/null +++ b/reader/src/formats/chm/BitStream.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include "BitStream.h" + +const int BitStream::BufferSize = sizeof(unsigned int) * 8; + +unsigned int BitStream::get4BytesDirect() { + if (myByteStream + 4 > myByteStreamEnd) { + return 0; + } + unsigned int bytes = *myByteStream++ << 24; + bytes += *myByteStream++ << 16; + bytes += *myByteStream++ << 8; + bytes += *myByteStream++; + return bytes; +} + +bool BitStream::getBytesDirect(unsigned char *buffer, unsigned int length) { + if (myByteStream + length > myByteStreamEnd) { + return false; + } + std::memcpy(buffer, myByteStream, length); + myByteStream += length; + return true; +} diff --git a/reader/src/formats/chm/BitStream.h b/reader/src/formats/chm/BitStream.h new file mode 100644 index 0000000..80c1e25 --- /dev/null +++ b/reader/src/formats/chm/BitStream.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BITSTREAM_H__ +#define __BITSTREAM_H__ + +#include <string> + +class BitStream { + +public: + static const int BufferSize; + +public: + BitStream(); + void setData(const std::string &data); + void reset(); + unsigned int peek(unsigned char length); + void remove(unsigned char length); + unsigned int get(unsigned char length); + unsigned int bytesLeft() const; + + unsigned int get4BytesDirect(); + bool getBytesDirect(unsigned char *buffer, unsigned int length); + +private: + bool ensure(unsigned char length); + +private: + unsigned int myBuffer; + unsigned char myBitCounter; + const unsigned char *myByteStream; + const unsigned char *myByteStreamEnd; + +private: + BitStream(const BitStream&); + const BitStream &operator = (const BitStream&); +}; + +inline BitStream::BitStream() : myBuffer(0), myBitCounter(0) { +} + +inline void BitStream::setData(const std::string &data) { + myByteStream = (const unsigned char*)data.data(); + myByteStreamEnd = myByteStream + data.length(); + myBuffer = 0; + myBitCounter = 0; +} + +inline void BitStream::reset() { + myByteStream -= myBitCounter / 8; + myBuffer = 0; + myBitCounter = 0; +} + +inline bool BitStream::ensure(unsigned char length) { + while ((myBitCounter < length) && (bytesLeft() >= 2)) { + myBuffer |= ((myByteStream[1] << 8) | myByteStream[0]) << (BitStream::BufferSize - 16 - myBitCounter); + myBitCounter += 16; + myByteStream += 2; + } + return myBitCounter >= length; +} + +inline unsigned int BitStream::peek(unsigned char length) { + ensure(length); + return (length > 0) ? (myBuffer >> (BufferSize - length)) : 0; +} + +inline void BitStream::remove(unsigned char length) { + if (ensure(length)) { + myBuffer <<= length; + myBitCounter -= length; + } +} + +inline unsigned int BitStream::get(unsigned char length) { + unsigned int bits; + if (length > 16) { + bits = peek(length - 16) << 16; + remove(length - 16); + bits += peek(16); + remove(16); + } else { + bits = peek(length); + remove(length); + } + return bits; +} + +inline unsigned int BitStream::bytesLeft() const { + return myByteStreamEnd - myByteStream; +} + +#endif /* __BITSTREAM_H__ */ diff --git a/reader/src/formats/chm/CHMFile.cpp b/reader/src/formats/chm/CHMFile.cpp new file mode 100644 index 0000000..8c62bca --- /dev/null +++ b/reader/src/formats/chm/CHMFile.cpp @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLInputStream.h> + +#include "CHMFile.h" +#include "CHMReferenceCollection.h" + +#include "LZXDecompressor.h" + +static std::string readString(ZLInputStream &stream, std::size_t length) { + std::string string(length, ' '); + stream.read(const_cast<char*>(string.data()), length); + return string; +} + +static unsigned short readUnsignedWord(ZLInputStream &stream) { + unsigned char buffer[2]; + stream.read((char*)buffer, 2); + unsigned short result = buffer[1]; + result = result << 8; + result += buffer[0]; + return result; +} + +static unsigned long readUnsignedDWord(ZLInputStream &stream) { + unsigned long lowPart = readUnsignedWord(stream); + unsigned long highPart = readUnsignedWord(stream); + return (highPart << 16) + lowPart; +} + +static unsigned long long readUnsignedQWord(ZLInputStream &stream) { + unsigned long long lowPart = readUnsignedDWord(stream); + unsigned long long highPart = readUnsignedDWord(stream); + return (highPart << 32) + lowPart; +} + +static unsigned long long readEncodedInteger(ZLInputStream &stream) { + unsigned long long result = 0; + char part; + do { + result = result << 7; + stream.read(&part, 1); + result += part & 0x7F; + } while (part & -0x80); + return result; +} + +CHMInputStream::CHMInputStream(shared_ptr<ZLInputStream> base, const CHMFileInfo::SectionInfo §ionInfo, std::size_t offset, std::size_t size) : myBase(base), mySectionInfo(sectionInfo), mySize(size) { + myBaseStartIndex = offset / 0x8000; + myBaseStartIndex -= myBaseStartIndex % sectionInfo.ResetInterval; + myBytesToSkip = offset - myBaseStartIndex * 0x8000; + myOutData = new unsigned char[0x8000]; +} + +CHMInputStream::~CHMInputStream() { + close(); + delete[] myOutData; +} + +bool CHMInputStream::open() { + myOffset = 0; + myDoSkip = true; + myBaseIndex = myBaseStartIndex; + if (myDecompressor.isNull()) { + myDecompressor = new LZXDecompressor(mySectionInfo.WindowSizeIndex); + } else { + myDecompressor->reset(); + } + myOutDataOffset = 0; + myOutDataLength = 0; + return true; +} + +std::size_t CHMInputStream::read(char *buffer, std::size_t maxSize) { + if (myDoSkip) { + do_read(0, myBytesToSkip); + myDoSkip = false; + } + std::size_t realSize = do_read(buffer, std::min(maxSize, mySize - myOffset)); + myOffset += realSize; + return realSize; +} + +std::size_t CHMInputStream::do_read(char *buffer, std::size_t maxSize) { + std::size_t realSize = 0; + do { + if (myOutDataLength == 0) { + if (myBaseIndex >= mySectionInfo.ResetTable.size()) { + break; + } + const bool isTail = myBaseIndex + 1 == mySectionInfo.ResetTable.size(); + const std::size_t start = mySectionInfo.ResetTable[myBaseIndex]; + const std::size_t end = isTail ? mySectionInfo.CompressedSize : mySectionInfo.ResetTable[myBaseIndex + 1]; + myOutDataLength = isTail ? mySectionInfo.UncompressedSize % 0x8000 : 0x8000; + myOutDataOffset = 0; + + myInData.erase(); + myInData.append(end - start, '\0'); + myBase->seek(mySectionInfo.Offset + start, true); + myBase->read((char*)myInData.data(), myInData.length()); + if (myBaseIndex % mySectionInfo.ResetInterval == 0) { + myDecompressor->reset(); + } + ++myBaseIndex; + + if (!myDecompressor->decompress(myInData, myOutData, myOutDataLength)) { + break; + } + } + const std::size_t partSize = std::min(myOutDataLength, maxSize); + if (buffer != 0) { + std::memcpy(buffer + realSize, myOutData + myOutDataOffset, partSize); + } + maxSize -= partSize; + realSize += partSize; + myOutDataLength -= partSize; + myOutDataOffset += partSize; + } while (maxSize != 0); + return realSize; +} + +void CHMInputStream::close() { + myDecompressor = 0; +} + +void CHMInputStream::seek(int offset, bool absoluteOffset) { + if (absoluteOffset) { + offset -= myOffset; + } + if (offset > 0) { + read(0, offset); + } else if (offset < 0) { + open(); + read(0, std::max(offset + (int)myOffset, 0)); + } +} + +std::size_t CHMInputStream::offset() const { + return myOffset; +} + +std::size_t CHMInputStream::sizeOfOpened() { + return mySize; +} + +shared_ptr<ZLInputStream> CHMFileInfo::entryStream(shared_ptr<ZLInputStream> base, const std::string &name) const { + RecordMap::const_iterator it = myRecords.find(ZLUnicodeUtil::toLower(name)); + if (it == myRecords.end()) { + return 0; + } + const RecordInfo &recordInfo = it->second; + if (recordInfo.Length == 0) { + return 0; + } + if (recordInfo.Section == 0) { + // TODO: implement + return 0; + } + if (recordInfo.Section > mySectionInfos.size()) { + return 0; + } + const SectionInfo §ionInfo = mySectionInfos[recordInfo.Section - 1]; + if (recordInfo.Offset + recordInfo.Length > sectionInfo.UncompressedSize) { + return 0; + } + + return new CHMInputStream(base, sectionInfo, recordInfo.Offset, recordInfo.Length); +} + +CHMFileInfo::CHMFileInfo(const ZLFile &file) : myFilePath(file.path()) { +} + +bool CHMFileInfo::moveToEntry(ZLInputStream &stream, const std::string &entryName) { + RecordMap::const_iterator it = myRecords.find(entryName); + if (it == myRecords.end()) { + return false; + } + RecordInfo recordInfo = it->second; + if (recordInfo.Section > mySectionInfos.size()) { + return false; + } + if (recordInfo.Section != 0) { + // TODO: ??? + return false; + } + + stream.seek(mySection0Offset + recordInfo.Offset, true); + return true; +} + +bool CHMFileInfo::init(ZLInputStream &stream) { + { + // header start + if (readString(stream, 4) != "ITSF") { + return false; + } + + unsigned long version = readUnsignedDWord(stream); + + // DWORD total length + // DWORD unknown + // DWORD timestamp + // DWORD language id + // 0x10 bytes 1st GUID + // 0x10 bytes 2nd GUID + // QWORD section 0 offset + // QWORD section 0 length + stream.seek(4 * 4 + 2 * 0x10 + 2 * 8, false); + + unsigned long long sectionOffset1 = readUnsignedQWord(stream); + unsigned long long sectionLength1 = readUnsignedQWord(stream); + mySection0Offset = sectionOffset1 + sectionLength1; + // header end + + // additional header data start + if (version > 2) { + mySection0Offset = readUnsignedQWord(stream); + } + // additional header data end + + stream.seek(sectionOffset1, true); + // header section 1 start + // directory header start + if (readString(stream, 4) != "ITSP") { + return false; + } + + // DWORD version + // DWORD length + // DWORD 0x000A + // DWORD chunk size + // DWORD density + // DWORD depth + // DWORD root chunk number + // DWORD first chunk number + // DWORD last chunk number + // DWORD -1 + stream.seek(10 * 4, false); + unsigned long dirChunkNumber = readUnsignedDWord(stream); + // ... + stream.seek(36, false); + // header section 1 end + + std::size_t nextOffset = stream.offset(); + for (unsigned long i = 0; i < dirChunkNumber; ++i) { + nextOffset += 4096; + std::string header = readString(stream, 4); + if (header == "PMGL") { + unsigned long quickRefAreaSize = readUnsignedDWord(stream) % 4096; + stream.seek(12, false); + std::size_t startOffset = stream.offset(); + std::size_t oldOffset = startOffset; + while (startOffset < nextOffset - quickRefAreaSize) { + int nameLength = readEncodedInteger(stream); + std::string name = readString(stream, nameLength); + int contentSection = readEncodedInteger(stream); + int offset = readEncodedInteger(stream); + int length = readEncodedInteger(stream); + if (name.substr(0, 2) != "::") { + name = ZLUnicodeUtil::toLower(name); + } + myRecords.insert( + std::make_pair( + name, + CHMFileInfo::RecordInfo(contentSection, offset, length) + ) + ); + startOffset = stream.offset(); + if (oldOffset == startOffset) { + break; + } + oldOffset = startOffset; + } + } else if (header == "PMGI") { + unsigned long quickRefAreaSize = readUnsignedDWord(stream); + std::size_t startOffset = stream.offset(); + std::size_t oldOffset = startOffset; + while (startOffset < nextOffset - quickRefAreaSize) { + int nameLength = readEncodedInteger(stream); + std::string name = readString(stream, nameLength); + // chunk number + readEncodedInteger(stream); + startOffset = stream.offset(); + if (oldOffset == startOffset) { + break; + } + oldOffset = startOffset; + } + } + stream.seek(nextOffset, true); + if (stream.offset() != nextOffset) { + break; + } + } + } + + { + if (!moveToEntry(stream, "::DataSpace/NameList")) { + return false; + } + stream.seek(2, false); + const int sectionNumber = readUnsignedWord(stream); + for (int i = 0; i < sectionNumber; ++i) { + const int length = readUnsignedWord(stream); + std::string sectionName; + sectionName.reserve(length); + for (int j = 0; j < length; ++j) { + sectionName += (char)readUnsignedWord(stream); + } + stream.seek(2, false); + mySectionNames.push_back(sectionName); + } + } + + { + for (unsigned int i = 1; i < mySectionNames.size(); ++i) { + RecordMap::const_iterator it = + myRecords.find("::DataSpace/Storage/" + mySectionNames[i] + "/Content"); + if (it == myRecords.end()) { + return false; + } + RecordInfo recordInfo = it->second; + if (recordInfo.Section != 0) { + return false; + } + mySectionInfos.push_back(SectionInfo()); + SectionInfo &info = mySectionInfos.back(); + info.Offset = mySection0Offset + recordInfo.Offset; + info.Length = recordInfo.Length; + + if (!moveToEntry(stream, "::DataSpace/Storage/" + mySectionNames[i] + "/ControlData")) { + return false; + } + stream.seek(4, false); + std::string lzxc = readString(stream, 4); + if (lzxc != "LZXC") { + return false; + } + const int version = readUnsignedDWord(stream); + if ((version <= 0) || (version > 2)) { + return false; + } + info.ResetInterval = readUnsignedDWord(stream); + if (version == 1) { + info.ResetInterval /= 0x8000; + } + info.WindowSizeIndex = (version == 1) ? 0 : 15; + { + int ws = readUnsignedDWord(stream); + if (ws > 0) { + while ((ws & 1) == 0) { + ws >>= 1; + info.WindowSizeIndex++; + } + } + } + + if (!moveToEntry(stream, "::DataSpace/Storage/" + mySectionNames[i] + "/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable")) { + return false; + } + stream.seek(4, false); + const std::size_t entriesNumber = readUnsignedDWord(stream); + if (entriesNumber == 0) { + return false; + } + if (entriesNumber > 2048) { + // file size is greater than 60 Mb + return false; + } + info.ResetTable.reserve(entriesNumber); + stream.seek(8, false); + info.UncompressedSize = readUnsignedQWord(stream); + if ((info.UncompressedSize - 1) / 0x8000 != entriesNumber - 1) { + return false; + } + info.CompressedSize = readUnsignedQWord(stream); + stream.seek(8, false); + std::size_t previous = 0; + for (std::size_t j = 0; j < entriesNumber; ++j) { + std::size_t value = readUnsignedQWord(stream); + if ((j > 0) == (value <= previous)) { + return false; + } + info.ResetTable.push_back(value); + previous = value; + } + } + } + + return true; +} + +static std::string readNTString(ZLInputStream &stream) { + std::string s; + char c; + while (stream.read(&c, 1) == 1) { + if (c == '\0') { + break; + } else { + s += c; + } + } + return CHMReferenceCollection::fullReference("/", s); +} + +bool CHMFileInfo::FileNames::empty() const { + return Start.empty() && TOC.empty() && Home.empty() && Index.empty(); +} + +CHMFileInfo::FileNames CHMFileInfo::sectionNames(shared_ptr<ZLInputStream> base) const { + FileNames names; + shared_ptr<ZLInputStream> stringsStream = entryStream(base, "/#STRINGS"); + if (!stringsStream.isNull() && stringsStream->open()) { + std::vector<std::string> fileNames; + int tocIndex = -1; + int indexIndex = -1; + for (int i = 0; i < 12; ++i) { + std::string argument = readNTString(*stringsStream); + if (argument.empty() || (argument[argument.length() - 1] == '/')) { + continue; + } + if (myRecords.find(argument) == myRecords.end()) { + continue; + } + if ((tocIndex == -1) && ZLStringUtil::stringEndsWith(argument, ".hhc")) { + tocIndex = fileNames.size(); + names.TOC = argument; + } else if ((indexIndex == -1) && ZLStringUtil::stringEndsWith(argument, ".hhk")) { + indexIndex = fileNames.size(); + names.Index = argument; + } + fileNames.push_back(argument); + } + std::size_t startIndex = std::max(3, std::max(tocIndex, indexIndex) + 1); + if (startIndex < 11) { + if (startIndex < fileNames.size()) { + names.Start = fileNames[startIndex]; + } + if (startIndex + 1 < fileNames.size()) { + names.Home = fileNames[startIndex + 1]; + } + } + stringsStream->close(); + } + if (names.TOC.empty()) { + for (RecordMap::const_iterator it = myRecords.begin(); it != myRecords.end(); ++it) { + if (ZLStringUtil::stringEndsWith(it->first, ".hhc")) { + names.TOC = it->first; + break; + } + } + } + if (names.empty()) { + for (RecordMap::const_iterator it = myRecords.begin(); it != myRecords.end(); ++it) { + if ((ZLStringUtil::stringEndsWith(it->first, ".htm")) || + (ZLStringUtil::stringEndsWith(it->first, ".html"))) { + names.Start = it->first; + break; + } + } + } + + return names; +} + +const std::string CHMFileInfo::filePath() const { + return myFilePath; +} diff --git a/reader/src/formats/chm/CHMFile.h b/reader/src/formats/chm/CHMFile.h new file mode 100644 index 0000000..d98bd84 --- /dev/null +++ b/reader/src/formats/chm/CHMFile.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __CHMFILE_H__ +#define __CHMFILE_H__ + +#include <string> +#include <map> +#include <vector> + +#include <shared_ptr.h> +#include <ZLInputStream.h> + +class ZLFile; + +class LZXDecompressor; + +class CHMFileInfo { + +public: + struct FileNames { + std::string TOC; + std::string Index; + std::string Start; + std::string Home; + + bool empty() const; + }; + +public: + CHMFileInfo(const ZLFile &file); + bool init(ZLInputStream &stream); + // We assume that base exists and is already open + shared_ptr<ZLInputStream> entryStream(shared_ptr<ZLInputStream> base, const std::string &name) const; + // We assume that base exists and is already open + FileNames sectionNames(shared_ptr<ZLInputStream> base) const; + const std::string filePath() const; + +private: + bool moveToEntry(ZLInputStream &stream, const std::string &entryName); + +private: + unsigned long long mySection0Offset; + + struct RecordInfo { + RecordInfo(int section, int offset, int length) : Section(section), Offset(offset), Length(length) {} + std::size_t Section; + std::size_t Offset; + std::size_t Length; + }; + + typedef std::map<std::string,RecordInfo> RecordMap; + RecordMap myRecords; + std::vector<std::string> mySectionNames; + + struct SectionInfo { + std::size_t WindowSizeIndex; + std::size_t ResetInterval; + std::size_t Offset; + std::size_t Length; + std::size_t CompressedSize; + std::size_t UncompressedSize; + std::vector<std::size_t> ResetTable; + }; + std::vector<SectionInfo> mySectionInfos; + + const std::string myFilePath; + +private: + CHMFileInfo(const CHMFileInfo&); + const CHMFileInfo &operator = (const CHMFileInfo&); + +friend class CHMInputStream; +}; + +class CHMInputStream : public ZLInputStream { + +public: + CHMInputStream(shared_ptr<ZLInputStream> base, const CHMFileInfo::SectionInfo §ionInfo, std::size_t offset, std::size_t size); + ~CHMInputStream(); + + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + std::size_t do_read(char *buffer, std::size_t maxSize); + +private: + shared_ptr<ZLInputStream> myBase; + const CHMFileInfo::SectionInfo mySectionInfo; + std::size_t myBaseStartIndex; + std::size_t myBaseIndex; + std::size_t myBytesToSkip; + const std::size_t mySize; + + std::size_t myOffset; + bool myDoSkip; + + shared_ptr<LZXDecompressor> myDecompressor; + std::string myInData; + + unsigned char *myOutData; + std::size_t myOutDataOffset; + std::size_t myOutDataLength; +}; + +#endif /* __CHMFILE_H__ */ diff --git a/reader/src/formats/chm/CHMFileImage.cpp b/reader/src/formats/chm/CHMFileImage.cpp new file mode 100644 index 0000000..a2b58f0 --- /dev/null +++ b/reader/src/formats/chm/CHMFileImage.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> + +#include "CHMFileImage.h" + +CHMFileImage::CHMFileImage(shared_ptr<CHMFileInfo> info, const std::string &entry) : ZLStreamImage(ZLMimeType::IMAGE_AUTO, 0, 0), myInfo(info), myEntry(entry) { +} + +shared_ptr<ZLInputStream> CHMFileImage::inputStream() const { + shared_ptr<ZLInputStream> baseStream = ZLFile(myInfo->filePath()).inputStream(); + if (baseStream.isNull() || !baseStream->open()) { + return 0; + } + return myInfo->entryStream(baseStream, myEntry); +} diff --git a/reader/src/formats/chm/CHMFileImage.h b/reader/src/formats/chm/CHMFileImage.h new file mode 100644 index 0000000..bacb6aa --- /dev/null +++ b/reader/src/formats/chm/CHMFileImage.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __CHMFILEIMAGE_H__ +#define __CHMFILEIMAGE_H__ + +#include <ZLStreamImage.h> + +#include "CHMFile.h" + +class CHMFileImage : public ZLStreamImage { + +public: + CHMFileImage(shared_ptr<CHMFileInfo> info, const std::string &entry); + +private: + shared_ptr<ZLInputStream> inputStream() const; + +private: + shared_ptr<CHMFileInfo> myInfo; + std::string myEntry; +}; + +#endif /* __CHMFILEIMAGE_H__ */ diff --git a/reader/src/formats/chm/CHMPlugin.cpp b/reader/src/formats/chm/CHMPlugin.cpp new file mode 100644 index 0000000..9ea88e4 --- /dev/null +++ b/reader/src/formats/chm/CHMPlugin.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "CHMPlugin.h" +#include "CHMFile.h" +#include "CHMFileImage.h" +#include "CHMReferenceCollection.h" +#include "HHCReader.h" +#include "HHCReferenceCollector.h" +#include "../txt/PlainTextFormat.h" +#include "HtmlSectionReader.h" +#include "../util/MergedStream.h" +#include "../html/HtmlReaderStream.h" + +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +bool CHMPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "chm"; +} + +class CHMTextStream : public MergedStream { + +public: + CHMTextStream(CHMFileInfo &chmFile, shared_ptr<ZLInputStream> base); + +private: + void resetToStart(); + shared_ptr<ZLInputStream> nextStream(); + +private: + CHMFileInfo &myCHMFile; + shared_ptr<ZLInputStream> myBase; + std::vector<std::string> myEntryNames; + std::size_t myIndex; +}; + +CHMTextStream::CHMTextStream(CHMFileInfo &chmFile, shared_ptr<ZLInputStream> base) : myCHMFile(chmFile), myBase(base) { +} + +void CHMTextStream::resetToStart() { + myIndex = 0; + + if (!myEntryNames.empty()) { + return; + } + + CHMFileInfo::FileNames names = myCHMFile.sectionNames(myBase); + if (names.empty()) { + return; + } + + CHMReferenceCollection referenceCollection; + + referenceCollection.addReference(names.Start, false); + referenceCollection.addReference(names.Home, false); + + shared_ptr<ZLInputStream> tocStream = myCHMFile.entryStream(myBase, names.TOC); + if (!tocStream.isNull() && tocStream->open()) { + referenceCollection.setPrefix(names.TOC); + HHCReferenceCollector(referenceCollection).readDocument(*tocStream); + } + + while (referenceCollection.containsNonProcessedReferences()) { + myEntryNames.push_back(referenceCollection.nextReference()); + } +} + +shared_ptr<ZLInputStream> CHMTextStream::nextStream() { + while (myIndex < myEntryNames.size()) { + shared_ptr<ZLInputStream> stream = myCHMFile.entryStream(myBase, myEntryNames[myIndex++]); + if (!stream.isNull()) { + return new HtmlReaderStream(stream, 50000); + } + } + return 0; +} + +bool CHMPlugin::readMetaInfo(Book &book) const { + const ZLFile &file = book.file(); + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull() || !stream->open()) { + return false; + } + + CHMFileInfo chmFile(file); + if (!chmFile.init(*stream)) { + return false; + } + + CHMFileInfo::FileNames names = chmFile.sectionNames(stream); + if (names.empty()) { + return false; + } + + /* + shared_ptr<ZLInputStream> entryStream = chmFile.entryStream(stream, names.Start); + if (entryStream.isNull()) { + entryStream = chmFile.entryStream(stream, names.Home); + } + if (entryStream.isNull()) { + entryStream = chmFile.entryStream(stream, names.TOC); + } + / * + if (entryStream.isNull()) { + chmFile.entryStream(stream, names.Index); + } + * / + if (entryStream.isNull()) { + return false; + } + */ + + CHMTextStream textStream(chmFile, stream); + detectEncodingAndLanguage(book, textStream); + if (book.encoding().empty()) { + return false; + } + + return true; +} + +bool CHMPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +class CHMHyperlinkMatcher : public BookModel::HyperlinkMatcher { + +public: + BookModel::Label match(const std::map<std::string,BookModel::Label> &lMap, const std::string &id) const; +}; + +BookModel::Label CHMHyperlinkMatcher::match(const std::map<std::string,BookModel::Label> &lMap, const std::string &id) const { + std::map<std::string,BookModel::Label>::const_iterator it = lMap.find(id); + if (it != lMap.end()) { + return it->second; + } + std::size_t index = id.find('#'); + if (index != std::string::npos) { + it = lMap.find(id.substr(0, index)); + } + return (it != lMap.end()) ? it->second : BookModel::Label(0, -1); +} + +bool CHMPlugin::readModel(BookModel &model) const { + model.setHyperlinkMatcher(new CHMHyperlinkMatcher()); + + const Book &book = *model.book(); + const ZLFile &file = book.file(); + + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull() || !stream->open()) { + return false; + } + + shared_ptr<CHMFileInfo> info = new CHMFileInfo(file); + if (!info->init(*stream)) { + return false; + } + + CHMFileInfo::FileNames names = info->sectionNames(stream); + if (names.empty()) { + return false; + } + + CHMReferenceCollection referenceCollection; + + referenceCollection.addReference(names.Start, false); + referenceCollection.addReference(names.Home, false); + + const std::string &encoding = book.encoding(); + + shared_ptr<ZLInputStream> tocStream = info->entryStream(stream, names.TOC); + HHCReader hhcReader(referenceCollection, model, encoding); + if (!tocStream.isNull() && tocStream->open()) { + referenceCollection.setPrefix(names.TOC); + hhcReader.readDocument(*tocStream); + } + + /* + if (!tocStream.isNull() && tocStream->open()) { + std::string buf; + buf.append(tocStream->sizeOfOpened(), '\0'); + tocStream->read((char*)buf.data(), buf.length()); + std::cerr << "[ " << names.TOC << " ]\n" << buf << "\n"; + } + */ + + int contentCounter = 0; + PlainTextFormat format(file); + HtmlSectionReader reader(model, format, encoding, info, referenceCollection); + while (referenceCollection.containsNonProcessedReferences()) { + const std::string fileName = referenceCollection.nextReference(); + if (ZLStringUtil::stringEndsWith(fileName, ".jpg") || + ZLStringUtil::stringEndsWith(fileName, ".gif")) { + std::string lowerCasedFileName = ZLUnicodeUtil::toLower(fileName); + BookReader bookReader(model); + bookReader.setMainTextModel(); + bookReader.addHyperlinkLabel(lowerCasedFileName); + bookReader.pushKind(REGULAR); + bookReader.beginParagraph(); + bookReader.addImageReference(lowerCasedFileName); + bookReader.addImage(fileName, new CHMFileImage(info, fileName)); + bookReader.endParagraph(); + bookReader.insertEndOfTextParagraph(); + } else { + shared_ptr<ZLInputStream> entryStream = info->entryStream(stream, fileName); + if (!entryStream.isNull() && entryStream->open()) { + /* + std::string buf; + buf.append(entryStream->sizeOfOpened(), '\0'); + entryStream->read((char*)buf.data(), buf.length()); + std::cerr << "[ " << fileName << " ]\n" << buf << "\n"; + entryStream->open(); + */ + reader.setSectionName(fileName); + reader.readDocument(*entryStream); + ++contentCounter; + } + } + } + if (contentCounter == 0) { + return false; + } + + hhcReader.setReferences(); + + + return true; +} diff --git a/reader/src/formats/chm/CHMPlugin.h b/reader/src/formats/chm/CHMPlugin.h new file mode 100644 index 0000000..0d38e62 --- /dev/null +++ b/reader/src/formats/chm/CHMPlugin.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __CHMPLUGIN_H__ +#define __CHMPLUGIN_H__ + +#include "../FormatPlugin.h" + +class CHMPlugin : public FormatPlugin { + +public: + CHMPlugin(); + ~CHMPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +inline CHMPlugin::CHMPlugin() {} +inline CHMPlugin::~CHMPlugin() {} +inline bool CHMPlugin::providesMetaInfo() const { return false; } + +#endif /* __CHMPLUGIN_H__ */ diff --git a/reader/src/formats/chm/CHMReferenceCollection.cpp b/reader/src/formats/chm/CHMReferenceCollection.cpp new file mode 100644 index 0000000..f29dd28 --- /dev/null +++ b/reader/src/formats/chm/CHMReferenceCollection.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "CHMReferenceCollection.h" +#include "../util/MiscUtil.h" + +std::string CHMReferenceCollection::fullReference(const std::string &prefix, std::string reference) { + reference = MiscUtil::decodeHtmlURL(reference); + if ((reference.length() > 0) && (reference[0] == '/')) { + return reference; + } + const int index = reference.rfind("::"); + if (index != -1) { + return reference.substr(index + 2); + } + + int counter = 0; + while (reference.substr(counter * 3, 3) == "../") { + ++counter; + } + + int slashIndex = prefix.length() - 1; + for (int i = 0; (i < counter) && (slashIndex > 0); ++i) { + slashIndex = prefix.rfind('/', slashIndex - 1); + } + return prefix.substr(0, slashIndex + 1) + reference.substr(counter * 3); +} + +CHMReferenceCollection::CHMReferenceCollection() : myPrefix("/") { +} + +const std::string &CHMReferenceCollection::addReference(const std::string &reference, bool doConvert) { + if (reference.empty()) { + return reference; + } + std::string fullRef = doConvert ? fullReference(myPrefix, reference) : MiscUtil::decodeHtmlURL(reference); + + const int index = fullRef.find('#'); + if (index == -1) { + fullRef = ZLUnicodeUtil::toLower(fullRef); + } else { + fullRef = ZLUnicodeUtil::toLower(fullRef.substr(0, index)); + } + std::set<std::string>::const_iterator it = myReferences.find(fullRef); + if (it != myReferences.end()) { + return *it; + } + + myReferences.insert(fullRef); + myReferenceQueue.push(fullRef); + return myReferenceQueue.back(); +} + +bool CHMReferenceCollection::containsNonProcessedReferences() const { + return !myReferenceQueue.empty(); +} + +const std::string CHMReferenceCollection::nextReference() { + if (myReferenceQueue.empty()) { + return ""; + } + const std::string front = myReferenceQueue.front(); + myReferenceQueue.pop(); + return front; +} + +void CHMReferenceCollection::setPrefix(const std::string &fileName) { + myPrefix = MiscUtil::decodeHtmlURL(fileName.substr(0, fileName.rfind('/') + 1)); +} + +const std::string &CHMReferenceCollection::prefix() const { + return myPrefix; +} diff --git a/reader/src/formats/chm/CHMReferenceCollection.h b/reader/src/formats/chm/CHMReferenceCollection.h new file mode 100644 index 0000000..6a53c45 --- /dev/null +++ b/reader/src/formats/chm/CHMReferenceCollection.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __CHMREFERENCECOLLECTION_H__ +#define __CHMREFERENCECOLLECTION_H__ + +#include <string> +#include <set> +#include <queue> + +class CHMReferenceCollection { + +public: + static std::string fullReference(const std::string &prefix, std::string reference); + +public: + CHMReferenceCollection(); + const std::string &addReference(const std::string &reference, bool doConvert); + bool containsNonProcessedReferences() const; + const std::string nextReference(); + void setPrefix(const std::string &fileName); + const std::string &prefix() const; + +private: + std::string myPrefix; + std::set<std::string> myReferences; + std::queue<std::string> myReferenceQueue; + +private: + CHMReferenceCollection(const CHMReferenceCollection&); + const CHMReferenceCollection &operator = (const CHMReferenceCollection&); +}; + +#endif /* __CHMREFERENCECOLLECTION_H__ */ diff --git a/reader/src/formats/chm/E8Decoder.cpp b/reader/src/formats/chm/E8Decoder.cpp new file mode 100644 index 0000000..53b9335 --- /dev/null +++ b/reader/src/formats/chm/E8Decoder.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LZXDecompressor.h" + +void LZXDecompressor::E8Decoder::reset(unsigned int fileSize) { + myFileSize = fileSize; + myFramesCounter = 0; + myPosition = 0; +} + +void LZXDecompressor::E8Decoder::decode(unsigned char *buffer, const std::size_t size) { + if (myFramesCounter >= 32768) { + return; + } + ++myFramesCounter; + if (myFileSize == 0) { + return; + } + + myPosition += size; + + if (size <= 10) { + return; + } + + const unsigned char *end = buffer + size - 10; + + for (unsigned char *ptr = buffer; ptr < end; ) { + if (*ptr == 0xE8) { + int absoluteOffset = + ptr[1] + (ptr[2] << 8) + (ptr[3] << 16) + (ptr[4] << 24); + int relativeOffset = + (absoluteOffset >= 0) ? + absoluteOffset - (ptr - buffer) : absoluteOffset + myFileSize; + ptr[1] = (unsigned char)relativeOffset; + ptr[2] = (unsigned char)(relativeOffset >> 8); + ptr[3] = (unsigned char)(relativeOffset >> 16); + ptr[4] = (unsigned char)(relativeOffset >> 24); + ptr += 5; + } else { + ++ptr; + } + } +} diff --git a/reader/src/formats/chm/HHCReader.cpp b/reader/src/formats/chm/HHCReader.cpp new file mode 100644 index 0000000..4fd3105 --- /dev/null +++ b/reader/src/formats/chm/HHCReader.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "HHCReader.h" +#include "CHMReferenceCollection.h" + +HHCReader::HHCReader(CHMReferenceCollection &collection, BookModel &model, const std::string &encoding) : HtmlReader(encoding), myReferenceCollection(collection), myBookReader(model) { +} + +HHCReader::~HHCReader() { +} + +void HHCReader::startDocumentHandler() { + myBookReader.setMainTextModel(); +} + +void HHCReader::endDocumentHandler() { + std::string tmp0; + myText.swap(tmp0); + std::string tmp1; + myReference.swap(tmp1); +} + +static const std::string UL = "UL"; +static const std::string LI = "LI"; +static const std::string OBJECT = "OBJECT"; +static const std::string PARAM = "PARAM"; +static const std::string NAME = "NAME"; +static const std::string VALUE = "VALUE"; +static const std::string NAME_VALUE = "Name"; +static const std::string LOCAL_VALUE = "Local"; + +static bool isFirstChild = false; + +bool HHCReader::tagHandler(const HtmlTag &tag) { + if (tag.Start) { + if (tag.Name == UL) { + isFirstChild = true; + } else if (tag.Name == LI) { + } else if (tag.Name == OBJECT) { + myText.erase(); + myReference.erase(); + } else if (tag.Name == PARAM) { + std::string name; + std::string value; + for (std::vector<HtmlAttribute>::const_iterator it = tag.Attributes.begin(); it != tag.Attributes.end(); ++it) { + if (it->Name == NAME) { + name = it->Value; + } else if (it->Name == VALUE) { + value = it->Value; + } + } + if (name == NAME_VALUE) { + myText = value; + } else if (name == LOCAL_VALUE) { + myReference = myReferenceCollection.addReference(value, true); + } + } + } else { + if (tag.Name == UL) { + myBookReader.endContentsParagraph(); + } else if (tag.Name == OBJECT) { + if (!myText.empty() || !myReference.empty()) { + if (!isFirstChild) { + myBookReader.endContentsParagraph(); + } else { + isFirstChild = false; + } + myBookReader.beginContentsParagraph(); + if (myText.empty()) { + myText = "..."; + } + myBookReader.addContentsData(myText.empty() ? "..." : myText); + myReferenceVector.push_back(ZLUnicodeUtil::toLower(myReference)); + } + } + } + return true; +} + +bool HHCReader::characterDataHandler(const char*, std::size_t, bool) { + return true; +} + +void HHCReader::setReferences() { + for (std::size_t i = 0; i < myReferenceVector.size(); ++i) { + myBookReader.setReference(i, myBookReader.model().label(myReferenceVector[i]).ParagraphNumber); + } +} diff --git a/reader/src/formats/chm/HHCReader.h b/reader/src/formats/chm/HHCReader.h new file mode 100644 index 0000000..c0e4cef --- /dev/null +++ b/reader/src/formats/chm/HHCReader.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HHCREADER_H__ +#define __HHCREADER_H__ + +#include <vector> + +#include "../html/HtmlReader.h" +#include "../../bookmodel/BookModel.h" +#include "../../bookmodel/BookReader.h" + +class CHMReferenceCollection; + +class HHCReader : public HtmlReader { + +public: + HHCReader(CHMReferenceCollection &collection, BookModel &model, const std::string &encoding); + ~HHCReader(); + + void setReferences(); + +private: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char*, std::size_t, bool); + +private: + CHMReferenceCollection &myReferenceCollection; + + std::string myText; + std::string myReference; + + BookReader myBookReader; + + std::vector<std::string> myReferenceVector; +}; + +#endif /* __HHCREADER_H__ */ diff --git a/reader/src/formats/chm/HHCReferenceCollector.cpp b/reader/src/formats/chm/HHCReferenceCollector.cpp new file mode 100644 index 0000000..6abcef2 --- /dev/null +++ b/reader/src/formats/chm/HHCReferenceCollector.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "HHCReferenceCollector.h" +#include "CHMReferenceCollection.h" + +HHCReferenceCollector::HHCReferenceCollector(CHMReferenceCollection &collection) : HtmlReader("US-ASCII"), myReferenceCollection(collection) { +} + +void HHCReferenceCollector::startDocumentHandler() { +} + +void HHCReferenceCollector::endDocumentHandler() { +} + +static const std::string PARAM = "PARAM"; +static const std::string NAME = "NAME"; +static const std::string VALUE = "VALUE"; +static const std::string NAME_VALUE = "Name"; +static const std::string LOCAL_VALUE = "Local"; + +bool HHCReferenceCollector::tagHandler(const HtmlTag &tag) { + if (tag.Start) { + if (tag.Name == PARAM) { + std::string name; + std::string value; + for (std::vector<HtmlAttribute>::const_iterator it = tag.Attributes.begin(); it != tag.Attributes.end(); ++it) { + if (it->Name == NAME) { + name = it->Value; + } else if (it->Name == VALUE) { + value = it->Value; + } + } + if (name == LOCAL_VALUE) { + myReferenceCollection.addReference(value, true); + } + } + } + return true; +} + +bool HHCReferenceCollector::characterDataHandler(const char*, std::size_t, bool) { + return true; +} diff --git a/reader/src/formats/chm/HHCReferenceCollector.h b/reader/src/formats/chm/HHCReferenceCollector.h new file mode 100644 index 0000000..20e58d1 --- /dev/null +++ b/reader/src/formats/chm/HHCReferenceCollector.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HHCREFERENCECOLLECTOR_H__ +#define __HHCREFERENCECOLLECTOR_H__ + +#include <vector> + +#include "../html/HtmlReader.h" + +class CHMReferenceCollection; + +class HHCReferenceCollector : public HtmlReader { + +public: + HHCReferenceCollector(CHMReferenceCollection &collection); + +private: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char*, std::size_t, bool); + +private: + CHMReferenceCollection &myReferenceCollection; +}; + +#endif /* __HHCREFERENCECOLLECTOR_H__ */ diff --git a/reader/src/formats/chm/HtmlSectionReader.cpp b/reader/src/formats/chm/HtmlSectionReader.cpp new file mode 100644 index 0000000..9973e14 --- /dev/null +++ b/reader/src/formats/chm/HtmlSectionReader.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "HtmlSectionReader.h" +#include "CHMReferenceCollection.h" +#include "CHMFileImage.h" +#include "../util/MiscUtil.h" +#include "../html/HtmlTagActions.h" + +class HtmlSectionHrefTagAction : public HtmlHrefTagAction { + +public: + HtmlSectionHrefTagAction(HtmlSectionReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlSectionImageTagAction : public HtmlTagAction { + +public: + HtmlSectionImageTagAction(HtmlSectionReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +shared_ptr<HtmlTagAction> HtmlSectionReader::createAction(const std::string &tag) { + if (tag == "IMG") { + return new HtmlSectionImageTagAction(*this); + } else if (tag == "A") { + return new HtmlSectionHrefTagAction(*this); + } + return HtmlBookReader::createAction(tag); +} + +HtmlSectionReader::HtmlSectionReader(BookModel &model, const PlainTextFormat &format, const std::string &encoding, shared_ptr<CHMFileInfo> info, CHMReferenceCollection &collection) : HtmlBookReader("", model, format, encoding), myInfo(info), myReferenceCollection(collection) { + setBuildTableOfContent(false); +} + +void HtmlSectionReader::setSectionName(const std::string §ionName) { + myCurrentSectionName = ZLUnicodeUtil::toLower(sectionName); + myReferenceCollection.setPrefix(myCurrentSectionName); +} + +void HtmlSectionReader::startDocumentHandler() { + HtmlBookReader::startDocumentHandler(); + myBookReader.addHyperlinkLabel(ZLUnicodeUtil::toLower(myCurrentSectionName)); +} + +void HtmlSectionReader::endDocumentHandler() { + HtmlBookReader::endDocumentHandler(); + myBookReader.insertEndOfTextParagraph(); +} + +HtmlSectionHrefTagAction::HtmlSectionHrefTagAction(HtmlSectionReader &reader) : HtmlHrefTagAction(reader) { +} + +void HtmlSectionHrefTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + HtmlSectionReader &reader = (HtmlSectionReader&)myReader; + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "NAME") { + bookReader().addHyperlinkLabel(ZLUnicodeUtil::toLower(reader.myCurrentSectionName + '#' + tag.Attributes[i].Value)); + } else if ((hyperlinkType() == REGULAR) && (tag.Attributes[i].Name == "HREF")) { + const std::string &value = tag.Attributes[i].Value; + if (!value.empty()) { + FBTextKind referenceType = MiscUtil::referenceType(value); + if (referenceType != INTERNAL_HYPERLINK) { + bookReader().addHyperlinkControl(referenceType, value); + setHyperlinkType(referenceType); + } else { + const int index = value.find('#'); + std::string sectionName = (index == -1) ? value : value.substr(0, index); + sectionName = ZLUnicodeUtil::toLower(MiscUtil::decodeHtmlURL(sectionName)); + if (sectionName.empty()) { + sectionName = reader.myCurrentSectionName; + } else { + sectionName = reader.myReferenceCollection.addReference(sectionName, true); + } + bookReader().addHyperlinkControl( + INTERNAL_HYPERLINK, ZLUnicodeUtil::toLower((index == -1) ? sectionName : (sectionName + value.substr(index))) + ); + setHyperlinkType(INTERNAL_HYPERLINK); + } + } + } + } + } else if (hyperlinkType() != REGULAR) { + bookReader().addControl(hyperlinkType(), false); + setHyperlinkType(REGULAR); + } +} + +HtmlSectionImageTagAction::HtmlSectionImageTagAction(HtmlSectionReader &reader) : HtmlTagAction(reader) { +} + +void HtmlSectionImageTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + //bookReader().endParagraph(); + HtmlSectionReader &reader = (HtmlSectionReader&)myReader; + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "SRC") { + std::string fileName = MiscUtil::decodeHtmlURL(tag.Attributes[i].Value); + fileName = CHMReferenceCollection::fullReference(reader.myReferenceCollection.prefix(), fileName); + fileName = ZLUnicodeUtil::toLower(fileName); + bookReader().addImageReference(fileName); + bookReader().addImage(fileName, new CHMFileImage(reader.myInfo, fileName)); + break; + } + } + //bookReader().beginParagraph(); + } +} diff --git a/reader/src/formats/chm/HtmlSectionReader.h b/reader/src/formats/chm/HtmlSectionReader.h new file mode 100644 index 0000000..424c178 --- /dev/null +++ b/reader/src/formats/chm/HtmlSectionReader.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLSECTIONREADER_H__ +#define __HTMLSECTIONREADER_H__ + +#include "../html/HtmlBookReader.h" +#include "CHMFile.h" + +class CHMReferenceCollection; + +class HtmlSectionReader : public HtmlBookReader { + +public: + HtmlSectionReader(BookModel &model, const PlainTextFormat &format, const std::string &encoding, shared_ptr<CHMFileInfo> info, CHMReferenceCollection &collection); + void setSectionName(const std::string §ionName); + +private: + void startDocumentHandler(); + void endDocumentHandler(); + +private: + shared_ptr<HtmlTagAction> createAction(const std::string &tag); + +private: + shared_ptr<CHMFileInfo> myInfo; + CHMReferenceCollection &myReferenceCollection; + std::string myCurrentSectionName; + +friend class HtmlSectionHrefTagAction; +friend class HtmlSectionImageTagAction; +}; + +#endif /* __HTMLSECTIONREADER_H__ */ diff --git a/reader/src/formats/chm/HuffmanDecoder.cpp b/reader/src/formats/chm/HuffmanDecoder.cpp new file mode 100644 index 0000000..db8718f --- /dev/null +++ b/reader/src/formats/chm/HuffmanDecoder.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include "HuffmanDecoder.h" + +HuffmanDecoder::HuffmanDecoder() : myMaxBitsNumber(0) { +} + +void HuffmanDecoder::reset() { + CodeLengths.clear(); +} + +bool HuffmanDecoder::buildTable() { + myMaxBitsNumber = 0; + for (unsigned short symbol = 0; symbol < CodeLengths.size(); symbol++) { + myMaxBitsNumber = std::max(CodeLengths[symbol], myMaxBitsNumber); + } + if (myMaxBitsNumber > 16) { + return false; + } + + unsigned int tableSize = 1 << myMaxBitsNumber; + mySymbols.clear(); + mySymbols.reserve(tableSize); + + for (unsigned char i = 1; i <= myMaxBitsNumber; ++i) { + for (unsigned short symbol = 0; symbol < CodeLengths.size(); symbol++) { + if (CodeLengths[symbol] == i) { + mySymbols.insert(mySymbols.end(), 1 << (myMaxBitsNumber - i), symbol); + if (mySymbols.size() > tableSize) { + return false; + } + } + } + } + + if (mySymbols.size() < tableSize) { + mySymbols.insert(mySymbols.end(), tableSize - mySymbols.size(), 0); + } + + return true; +} diff --git a/reader/src/formats/chm/HuffmanDecoder.h b/reader/src/formats/chm/HuffmanDecoder.h new file mode 100644 index 0000000..bd9f700 --- /dev/null +++ b/reader/src/formats/chm/HuffmanDecoder.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HUFFMANDECODER_H__ +#define __HUFFMANDECODER_H__ + +#include <vector> + +#include "BitStream.h" + +class HuffmanDecoder { + +public: + HuffmanDecoder(); + + bool buildTable(); + void reset(); + + unsigned int getSymbol(BitStream &stream) const; + +private: + unsigned char myMaxBitsNumber; + std::vector<unsigned short> mySymbols; + std::vector<unsigned char> CodeLengths; + HuffmanDecoder(const HuffmanDecoder&); + const HuffmanDecoder &operator = (const HuffmanDecoder&); + +friend class LZXDecompressor; +}; + +inline unsigned int HuffmanDecoder::getSymbol(BitStream &stream) const { + unsigned int symbol = mySymbols[stream.peek(myMaxBitsNumber)]; + stream.remove(CodeLengths[symbol]); + return symbol; +} + +#endif /* __HUFFMANDECODER_H__ */ diff --git a/reader/src/formats/chm/LZXDecompressor.cpp b/reader/src/formats/chm/LZXDecompressor.cpp new file mode 100644 index 0000000..38b4311 --- /dev/null +++ b/reader/src/formats/chm/LZXDecompressor.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include "LZXDecompressor.h" + +static unsigned int slotNumber(int windowSizeIndex) { + if (windowSizeIndex == 20) { + return 42; + } else if (windowSizeIndex == 21) { + return 50; + } else { + return 2 * windowSizeIndex; + } +} + +LZXDecompressor::LZXDecompressor(int windowSizeIndex) : myWindow(1 << windowSizeIndex, 0), mySlotNumber(slotNumber(windowSizeIndex)) { + reset(); +} + +void LZXDecompressor::reset() { + myCurrentBlockType = UNKNOWNN; + myReadHeader = true; + + myState.WindowIterator = myWindow.begin(); + myState.R0 = 1; + myState.R1 = 1; + myState.R2 = 1; + + myMainTree.reset(); + myLengthTree.reset(); + + myBlockBytesLeft = 0; + + myE8Decoder.reset(0); +} + +static bool fill(std::vector<unsigned char> &data, std::vector<unsigned char>::iterator &it, int num, unsigned char value) { + if (data.end() - it < num) { + return false; + } + std::vector<unsigned char>::iterator end = it + num; + while (it != end) { + *it++ = value; + } + return true; +} + +bool LZXDecompressor::readLengths(HuffmanDecoder &decoder, std::size_t from, std::size_t size) { + HuffmanDecoder preTree; + preTree.CodeLengths.reserve(20); + for (int i = 0; i < 20; i++) { + preTree.CodeLengths.push_back(myBitStream.get(4)); + } + if (!preTree.buildTable()) { + return false; + } + + std::vector<unsigned char> &lengths = decoder.CodeLengths; + if (lengths.size() < from + size) { + lengths.insert(lengths.end(), from + size - lengths.size(), 0); + } + std::vector<unsigned char>::iterator start = lengths.begin() + from; + std::vector<unsigned char>::iterator end = start + size; + for (std::vector<unsigned char>::iterator it = start; it != end; ) { + int z = preTree.getSymbol(myBitStream); + if (z == 17) { + if (!fill(lengths, it, myBitStream.get(4) + 4, 0)) { + return false; + } + } else if (z == 18) { + if (!fill(lengths, it, myBitStream.get(5) + 20, 0)) { + return false; + } + } else if (z == 19) { + unsigned int num = myBitStream.get(1) + 4; + z = *it - preTree.getSymbol(myBitStream); + if (!fill(lengths, it, num, (z < 0) ? z + 17 : z)) { + return false; + } + } else { + z = *it - z; + *it++ = (z < 0) ? z + 17 : z; + } + } + + return true; +} + +static const unsigned int basePosition[51] = { + 0, 1, 2, 3, 4, 6, 8, 12, + 16, 24, 32, 48, 64, 96, 128, 192, + 256, 384, 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, + 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, + 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936, + 1835008, 1966080, 2097152 +}; + +bool LZXDecompressor::decodeBytes(DecodingState &state, std::size_t bytesToDecode) { + if (myCurrentBlockType == UNCOMPRESSED) { + if (!myBitStream.getBytesDirect(&*state.WindowIterator, bytesToDecode)) { + return false; + } + state.WindowIterator += bytesToDecode; + return true; + } + + while (bytesToDecode > 0) { + int symbol = myMainTree.getSymbol(myBitStream); + if (symbol < 256) { + *state.WindowIterator++ = symbol; + --bytesToDecode; + continue; + } + + std::size_t length = symbol % 8; + if (length == 7) { + length += myLengthTree.getSymbol(myBitStream); + } + length += 2; + if (length > bytesToDecode) { + return false; + } + + std::size_t offset = (symbol - 256) / 8; + switch (offset) { + case 0: + offset = state.R0; + break; + case 1: + offset = state.R1; + state.R1 = state.R0; + state.R0 = offset; + break; + case 2: + offset = state.R2; + state.R2 = state.R0; + state.R0 = offset; + break; + default: + if ((myCurrentBlockType == VERBATIM) && (offset == 3)) { + offset = 1; + } else { + if (offset > 50) { + return false; + } + const int positionFooterBits = std::max(0, std::min((int)offset / 2 - 1, 17)); + offset = basePosition[offset] - 2; + if ((myCurrentBlockType == VERBATIM) || (positionFooterBits == 1) || (positionFooterBits == 2)) { + offset += myBitStream.get(positionFooterBits); + } else if (positionFooterBits == 3) { + offset += myAlignedOffsetTree.getSymbol(myBitStream); + } else if (positionFooterBits > 3) { + offset += 8 * myBitStream.get(positionFooterBits - 3); + offset += myAlignedOffsetTree.getSymbol(myBitStream); + } else { + offset = 1; + } + } + state.R2 = state.R1; + state.R1 = state.R0; + state.R0 = offset; + break; + } + + if ((state.WindowIterator - myWindow.begin()) + myWindow.size() < offset) { + return false; + } + if (myWindow.size() >= offset + (myWindow.end() - state.WindowIterator)) { + offset += myWindow.size(); + if (myWindow.size() >= offset + (myWindow.end() - state.WindowIterator)) { + return false; + } + } + std::vector<unsigned char>::iterator srcIt = state.WindowIterator + (myWindow.size() - offset); + for (std::size_t i = 0; i < length; ++i) { + if (srcIt == myWindow.end()) { + srcIt -= myWindow.size(); + } + *state.WindowIterator++ = *srcIt++; + } + bytesToDecode -= length; + } + return true; +} + +bool LZXDecompressor::decompress(const std::string &data, unsigned char *outBuffer, const std::size_t outSize) { + myBitStream.setData(data); + + if (myReadHeader) { + if (myBitStream.get(1) == 1) { + myE8Decoder.reset(myBitStream.get(32)); + } + myReadHeader = false; + } + + DecodingState state = myState; + + for (std::size_t bytesToWrite = outSize; bytesToWrite > 0; ) { + if (myBlockBytesLeft == 0) { + if (myCurrentBlockType == UNCOMPRESSED) { + if (myBlockSize & 1) { + myBitStream.remove(8); + } + myBitStream.reset(); + } + + myCurrentBlockType = (BlockType)myBitStream.get(3); + myBlockSize = myBitStream.get(24); + myBlockBytesLeft = myBlockSize; + + switch (myCurrentBlockType) { + case UNCOMPRESSED: + myBitStream.reset(); + state.R0 = myBitStream.get4BytesDirect(); + state.R1 = myBitStream.get4BytesDirect(); + state.R2 = myBitStream.get4BytesDirect(); + break; + + case ALIGNED: + myAlignedOffsetTree.CodeLengths.clear(); + for (int i = 0; i < 8; i++) { + myAlignedOffsetTree.CodeLengths.push_back(myBitStream.get(3)); + } + if (!myAlignedOffsetTree.buildTable()) { + return false; + } + // no break; it's not a mistake + + case VERBATIM: + if (!readLengths(myMainTree, 0, 256) || + !readLengths(myMainTree, 256, 8 * mySlotNumber) || + !readLengths(myLengthTree, 0, 249) || + !myMainTree.buildTable() || + !myLengthTree.buildTable()) { + return false; + } + break; + + default: + return false; + } + } + + while ((myBlockBytesLeft > 0) && (bytesToWrite > 0)) { + std::size_t bytesToDecode = std::min(myBlockBytesLeft, bytesToWrite); + if (state.WindowIterator + bytesToDecode > myWindow.end()) { + return false; + } + + if (!decodeBytes(state, bytesToDecode)) { + return false; + } + + bytesToWrite -= bytesToDecode; + myBlockBytesLeft -= bytesToDecode; + } + } + + std::vector<unsigned char>::iterator jt = + (state.WindowIterator != myWindow.begin()) ? state.WindowIterator : myWindow.end(); + std::memcpy(outBuffer, &*(jt - outSize), outSize); + + myState = state; + + myE8Decoder.decode(outBuffer, outSize); + + return true; +} diff --git a/reader/src/formats/chm/LZXDecompressor.h b/reader/src/formats/chm/LZXDecompressor.h new file mode 100644 index 0000000..dac9e1f --- /dev/null +++ b/reader/src/formats/chm/LZXDecompressor.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LZXDECOMPRESSOR_H__ +#define __LZXDECOMPRESSOR_H__ + +#include <string> +#include <vector> + +#include "BitStream.h" +#include "HuffmanDecoder.h" + +class LZXDecompressor { + +public: + LZXDecompressor(int windowSizeIndex); + void reset(); + + bool decompress(const std::string &data, unsigned char *outBuffer, const std::size_t outSize); + +private: + struct DecodingState { + std::vector<unsigned char>::iterator WindowIterator; + unsigned int R0; + unsigned int R1; + unsigned int R2; + }; + + bool readLengths(HuffmanDecoder &decoder, std::size_t from, std::size_t size); + bool decodeBytes(DecodingState &state, std::size_t bytesToDecode); + +private: + enum BlockType { + UNKNOWNN = 0, + VERBATIM = 1, + ALIGNED = 2, + UNCOMPRESSED = 3 + }; + + BlockType myCurrentBlockType; + bool myReadHeader; + + std::vector<unsigned char> myWindow; + + DecodingState myState; + + std::size_t myBlockSize; + std::size_t myBlockBytesLeft; + + const unsigned int mySlotNumber; + HuffmanDecoder myMainTree; + HuffmanDecoder myLengthTree; + HuffmanDecoder myAlignedOffsetTree; + + BitStream myBitStream; + + class E8Decoder { + + public: + void reset(unsigned int fileSize); + void decode(unsigned char *buffer, const std::size_t size); + + private: + unsigned int myFramesCounter; + unsigned int myFileSize; + unsigned int myPosition; + }; + + E8Decoder myE8Decoder; +}; + +#endif /* __LZXDECOMPRESSOR_H__ */ diff --git a/reader/src/formats/css/StyleSheetParser.cpp b/reader/src/formats/css/StyleSheetParser.cpp new file mode 100644 index 0000000..33dc900 --- /dev/null +++ b/reader/src/formats/css/StyleSheetParser.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> +#include <cstring> + +#include <ZLStringUtil.h> +#include <ZLInputStream.h> +#include <ZLLogger.h> + +#include "StyleSheetParser.h" + +StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) { + //ZLLogger::Instance().registerClass("CSS"); +} + +void StyleSheetTableParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) { + std::string s = selector; + ZLStringUtil::stripWhiteSpaces(s); + + if (s.empty()) { + return; + } + + if (s[0] == '@') { + processAtRule(s, map); + return; + } + + const std::vector<std::string> ids = ZLStringUtil::split(s, ","); + for (std::vector<std::string>::const_iterator it = ids.begin(); it != ids.end(); ++it) { + std::string id = *it; + ZLStringUtil::stripWhiteSpaces(id); + if (!id.empty()) { + const std::size_t index = id.find('.'); + if (index == std::string::npos) { + myTable.addMap(id, std::string(), map); + } else { + myTable.addMap(id.substr(0, index), id.substr(index + 1), map); + } + } + } +} + +void StyleSheetTableParser::processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map) { + (void)map; + if (name == "@font-face") { + } +} + +shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseString(const char *text) { + myReadState = WAITING_FOR_ATTRIBUTE; + parse(text, std::strlen(text), true); + shared_ptr<ZLTextStyleEntry> control = StyleSheetTable::createControl(myMap); + reset(); + return control; +} + +StyleSheetParser::StyleSheetParser() { + reset(); +} + +StyleSheetParser::~StyleSheetParser() { +} + +void StyleSheetParser::reset() { + myWord.erase(); + myAttributeName.erase(); + myReadState = WAITING_FOR_SELECTOR; + myInsideComment = false; + mySelectorString.erase(); + myMap.clear(); +} + +void StyleSheetParser::parse(ZLInputStream &stream) { + if (stream.open()) { + char *buffer = new char[1024]; + while (true) { + int len = stream.read(buffer, 1024); + if (len == 0) { + break; + } + parse(buffer, len); + } + delete[] buffer; + stream.close(); + } +} + +void StyleSheetParser::parse(const char *text, int len, bool final) { + const char *start = text; + const char *end = text + len; + for (const char *ptr = start; ptr != end; ++ptr) { + if (std::isspace(*ptr)) { + if (start != ptr) { + myWord.append(start, ptr - start); + } + processWord(myWord); + myWord.erase(); + start = ptr + 1; + } else if (isControlSymbol(*ptr)) { + if (start != ptr) { + myWord.append(start, ptr - start); + } + processWord(myWord); + myWord.erase(); + processControl(*ptr); + start = ptr + 1; + } + } + if (start < end) { + myWord.append(start, end - start); + if (final) { + processWord(myWord); + myWord.erase(); + } + } +} + +bool StyleSheetParser::isControlSymbol(const char symbol) { + switch (myReadState) { + default: + case WAITING_FOR_SELECTOR: + return false; + case SELECTOR: + return symbol == '{' || symbol == ';'; + case WAITING_FOR_ATTRIBUTE: + return symbol == '}' || symbol == ':'; + case ATTRIBUTE_NAME: + return symbol == ':'; + case ATTRIBUTE_VALUE: + return symbol == '}' || symbol == ';'; + } +} + +void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) { +} + +void StyleSheetParser::processAtRule(const std::string&, const StyleSheetTable::AttributeMap&) { +} + +void StyleSheetParser::processControl(const char control) { + switch (myReadState) { + case WAITING_FOR_SELECTOR: + break; + case SELECTOR: + switch (control) { + case '{': + myReadState = WAITING_FOR_ATTRIBUTE; + break; + case ';': + myReadState = WAITING_FOR_SELECTOR; + mySelectorString.erase(); + break; + } + break; + case WAITING_FOR_ATTRIBUTE: + if (control == '}') { + myReadState = WAITING_FOR_SELECTOR; + storeData(mySelectorString, myMap); + mySelectorString.erase(); + myMap.clear(); + } + break; + case ATTRIBUTE_NAME: + if (control == ':') { + myReadState = ATTRIBUTE_VALUE; + } + break; + case ATTRIBUTE_VALUE: + if (control == ';') { + myReadState = WAITING_FOR_ATTRIBUTE; + } else if (control == '}') { + myReadState = WAITING_FOR_SELECTOR; + storeData(mySelectorString, myMap); + mySelectorString.erase(); + myMap.clear(); + } + break; + } +} + +void StyleSheetParser::processWord(std::string &word) { + while (!word.empty()) { + int index = word.find(myInsideComment ? "*/" : "/*"); + if (!myInsideComment) { + if (index == -1) { + processWordWithoutComments(word); + } else if (index > 0) { + processWordWithoutComments(word.substr(0, index)); + } + } + if (index == -1) { + break; + } + myInsideComment = !myInsideComment; + word.erase(0, index + 2); + } +} + +void StyleSheetParser::processWordWithoutComments(const std::string &word) { + switch (myReadState) { + case WAITING_FOR_SELECTOR: + myReadState = SELECTOR; + mySelectorString = word; + break; + case SELECTOR: + mySelectorString += ' ' + word; + break; + case WAITING_FOR_ATTRIBUTE: + myReadState = ATTRIBUTE_NAME; + // go through + case ATTRIBUTE_NAME: + myAttributeName = word; + myMap[myAttributeName].clear(); + break; + case ATTRIBUTE_VALUE: + { + const std::size_t l = word.length(); + if (l >= 2 && (word[0] == '"' || word[0] == '\'') && word[0] == word[l - 1]) { + myMap[myAttributeName].push_back(word.substr(1, l - 2)); + } else { + myMap[myAttributeName].push_back(word); + } + break; + } + } +} diff --git a/reader/src/formats/css/StyleSheetParser.h b/reader/src/formats/css/StyleSheetParser.h new file mode 100644 index 0000000..8949823 --- /dev/null +++ b/reader/src/formats/css/StyleSheetParser.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __STYLESHEETPARSER_H__ +#define __STYLESHEETPARSER_H__ + +#include "StyleSheetTable.h" + +class ZLInputStream; + +class StyleSheetParser { + +protected: + StyleSheetParser(); + +public: + virtual ~StyleSheetParser(); + void reset(); + void parse(ZLInputStream &stream); + void parse(const char *text, int len, bool final = false); + +protected: + virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); + virtual void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map); + +private: + bool isControlSymbol(const char symbol); + void processWord(std::string &word); + void processWordWithoutComments(const std::string &word); + void processControl(const char control); + +private: + std::string myWord; + std::string myAttributeName; + enum { + WAITING_FOR_SELECTOR, + SELECTOR, + WAITING_FOR_ATTRIBUTE, + ATTRIBUTE_NAME, + ATTRIBUTE_VALUE, + } myReadState; + bool myInsideComment; + std::string mySelectorString; + StyleSheetTable::AttributeMap myMap; + +friend class StyleSheetSingleStyleParser; +}; + +class StyleSheetTableParser : public StyleSheetParser { + +public: + StyleSheetTableParser(StyleSheetTable &table); + +private: + void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); + void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map); + +private: + StyleSheetTable &myTable; +}; + +class StyleSheetSingleStyleParser : public StyleSheetParser { + +public: + shared_ptr<ZLTextStyleEntry> parseString(const char *text); +}; + +#endif /* __STYLESHEETPARSER_H__ */ diff --git a/reader/src/formats/css/StyleSheetTable.cpp b/reader/src/formats/css/StyleSheetTable.cpp new file mode 100644 index 0000000..fe45a85 --- /dev/null +++ b/reader/src/formats/css/StyleSheetTable.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLLogger.h> + +#include "StyleSheetTable.h" + +bool StyleSheetTable::isEmpty() const { + return myControlMap.empty() && myPageBreakBeforeMap.empty() && myPageBreakAfterMap.empty(); +} + +void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map) { + if ((!tag.empty() || !aClass.empty()) && !map.empty()) { + Key key(tag, aClass); + myControlMap[key] = createControl(map); + const std::vector<std::string> &pbb = values(map, "page-break-before"); + if (!pbb.empty()) { + if ((pbb[0] == "always") || + (pbb[0] == "left") || + (pbb[0] == "right")) { + myPageBreakBeforeMap[key] = true; + } else if (pbb[0] == "avoid") { + myPageBreakBeforeMap[key] = false; + } + } + const std::vector<std::string> &pba = values(map, "page-break-after"); + if (!pba.empty()) { + if ((pba[0] == "always") || + (pba[0] == "left") || + (pba[0] == "right")) { + myPageBreakAfterMap[key] = true; + } else if (pba[0] == "avoid") { + myPageBreakAfterMap[key] = false; + } + } + } +} + +static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) { + if (ZLStringUtil::stringEndsWith(toParse, "%")) { + unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT; + size = std::atoi(toParse.c_str()); + return true; + } else if (ZLStringUtil::stringEndsWith(toParse, "em")) { + unit = ZLTextStyleEntry::SIZE_UNIT_EM_100; + size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0)); + return true; + } else if (ZLStringUtil::stringEndsWith(toParse, "ex")) { + unit = ZLTextStyleEntry::SIZE_UNIT_EX_100; + size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0)); + return true; + } else if (ZLStringUtil::stringEndsWith(toParse, "px")) { + unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL; + size = std::atoi(toParse.c_str()); + return true; + } else if (ZLStringUtil::stringEndsWith(toParse, "pt")) { + unit = ZLTextStyleEntry::SIZE_UNIT_POINT; + size = std::atoi(toParse.c_str()); + return true; + } + return false; +} + +void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Feature featureId, const AttributeMap &map, const std::string &attributeName) { + StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName); + if (it == map.end()) { + return; + } + const std::vector<std::string> &values = it->second; + if (!values.empty() && !values[0].empty()) { + short size; + ZLTextStyleEntry::SizeUnit unit; + if (parseLength(values[0], size, unit)) { + entry.setLength(featureId, size, unit); + } + } +} + +bool StyleSheetTable::doBreakBefore(const std::string &tag, const std::string &aClass) const { + std::map<Key,bool>::const_iterator it = myPageBreakBeforeMap.find(Key(tag, aClass)); + if (it != myPageBreakBeforeMap.end()) { + return it->second; + } + + it = myPageBreakBeforeMap.find(Key("", aClass)); + if (it != myPageBreakBeforeMap.end()) { + return it->second; + } + + it = myPageBreakBeforeMap.find(Key(tag, "")); + if (it != myPageBreakBeforeMap.end()) { + return it->second; + } + + return false; +} + +bool StyleSheetTable::doBreakAfter(const std::string &tag, const std::string &aClass) const { + std::map<Key,bool>::const_iterator it = myPageBreakAfterMap.find(Key(tag, aClass)); + if (it != myPageBreakAfterMap.end()) { + return it->second; + } + + it = myPageBreakAfterMap.find(Key("", aClass)); + if (it != myPageBreakAfterMap.end()) { + return it->second; + } + + it = myPageBreakAfterMap.find(Key(tag, "")); + if (it != myPageBreakAfterMap.end()) { + return it->second; + } + + return false; +} + +shared_ptr<ZLTextStyleEntry> StyleSheetTable::control(const std::string &tag, const std::string &aClass) const { + std::map<Key,shared_ptr<ZLTextStyleEntry> >::const_iterator it = + myControlMap.find(Key(tag, aClass)); + return (it != myControlMap.end()) ? it->second : 0; +} + +const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map, const std::string &name) { + const AttributeMap::const_iterator it = map.find(name); + if (it != map.end()) { + return it->second; + } + static const std::vector<std::string> emptyVector; + return emptyVector; +} + +shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &styles) { + shared_ptr<ZLTextStyleEntry> entry = new ZLTextStyleEntry(ZLTextStyleEntry::STYLE_CSS_ENTRY); + + const std::vector<std::string> &alignment = values(styles, "text-align"); + if (!alignment.empty()) { + if (alignment[0] == "justify") { + entry->setAlignmentType(ALIGN_JUSTIFY); + } else if (alignment[0] == "left") { + entry->setAlignmentType(ALIGN_LEFT); + } else if (alignment[0] == "right") { + entry->setAlignmentType(ALIGN_RIGHT); + } else if (alignment[0] == "center") { + entry->setAlignmentType(ALIGN_CENTER); + } + } + + const std::vector<std::string> &deco = values(styles, "text-decoration"); + for (std::vector<std::string>::const_iterator it = deco.begin(); it != deco.end(); ++it) { + if (*it == "underline") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_UNDERLINED, true); + } else if (*it == "line-through") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_STRIKEDTHROUGH, true); + } else if (*it == "none") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_UNDERLINED, false); + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_STRIKEDTHROUGH, false); + } + } + + const std::vector<std::string> &bold = values(styles, "font-weight"); + if (!bold.empty()) { + //ZLLogger::Instance().println(ZLLogger::DEFAULT_CLASS, "bold: " + bold[0]); + int num = -1; + if (bold[0] == "bold") { + num = 700; + } else if (bold[0] == "normal") { + num = 400; + } else if (bold[0] == "bolder") { + // TODO: implement + } else if (bold[0] == "lighter") { + // TODO: implement + } else { + num = ZLStringUtil::stringToInteger(bold[0], -1); + } + if (num != -1) { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_BOLD, num >= 600); + } + } + + const std::vector<std::string> &italic = values(styles, "font-style"); + if (!italic.empty()) { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_ITALIC, italic[0] == "italic"); + } + + const std::vector<std::string> &variant = values(styles, "font-variant"); + if (!variant.empty()) { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps"); + } + + const std::vector<std::string> &fontFamily = values(styles, "font-family"); + if (!fontFamily.empty() && !fontFamily[0].empty()) { + entry->setFontFamily(fontFamily[0]); + //ZLLogger::Instance().println(ZLLogger::DEFAULT_CLASS, "font family: " + fontFamily[0]); + } + + const std::vector<std::string> &fontSize = values(styles, "font-size"); + if (!fontSize.empty()) { + //TODO implement FONT_MODIFIER_INHERIT, SMALLER and LARGER support + bool doSetFontSize = true; + short size = 100; + ZLTextStyleEntry::SizeUnit unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT; + if (fontSize[0] == "xx-small") { + size = 58; + } else if (fontSize[0] == "x-small") { + size = 69; + } else if (fontSize[0] == "small") { + size = 83; + } else if (fontSize[0] == "medium") { + size = 100; + } else if (fontSize[0] == "large") { + size = 120; + } else if (fontSize[0] == "x-large") { + size = 144; + } else if (fontSize[0] == "xx-large") { + size = 173; + } else if (fontSize[0] == "inherit") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_INHERIT, true); + doSetFontSize = false; + } else if (fontSize[0] == "smaller") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_SMALLER, true); + doSetFontSize = false; + } else if (fontSize[0] == "larger") { + entry->setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_LARGER, true); + doSetFontSize = false; + } else if (!parseLength(fontSize[0], size, unit)) { + doSetFontSize = false; + } + if (doSetFontSize) { + entry->setLength(ZLTextStyleEntry::LENGTH_FONT_SIZE, size, unit); + } + } + + setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left"); + setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right"); + setLength(*entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent"); + setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top"); + setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top"); + setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom"); + setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom"); + + return entry; +} + +void StyleSheetTable::clear() { + myControlMap.clear(); + myPageBreakBeforeMap.clear(); + myPageBreakAfterMap.clear(); +} diff --git a/reader/src/formats/css/StyleSheetTable.h b/reader/src/formats/css/StyleSheetTable.h new file mode 100644 index 0000000..54236fb --- /dev/null +++ b/reader/src/formats/css/StyleSheetTable.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __STYLESHEETTABLE_H__ +#define __STYLESHEETTABLE_H__ + +#include <string> +#include <map> +#include <vector> + +#include <shared_ptr.h> + +#include <ZLTextParagraph.h> +#include <ZLTextStyleEntry.h> + +class StyleSheetTable { + +public: + typedef std::map<std::string,std::vector<std::string> > AttributeMap; + static shared_ptr<ZLTextStyleEntry> createControl(const AttributeMap &map); + +private: + void addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map); + + static void setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Feature featureId, const AttributeMap &map, const std::string &attributeName); + static const std::vector<std::string> &values(const AttributeMap &map, const std::string &name); + +public: + bool isEmpty() const; + bool doBreakBefore(const std::string &tag, const std::string &aClass) const; + bool doBreakAfter(const std::string &tag, const std::string &aClass) const; + shared_ptr<ZLTextStyleEntry> control(const std::string &tag, const std::string &aClass) const; + + void clear(); + +private: + struct Key { + Key(const std::string &tag, const std::string &aClass); + + const std::string TagName; + const std::string ClassName; + + bool operator < (const Key &key) const; + }; + + std::map<Key,shared_ptr<ZLTextStyleEntry> > myControlMap; + std::map<Key,bool> myPageBreakBeforeMap; + std::map<Key,bool> myPageBreakAfterMap; + +friend class StyleSheetTableParser; +}; + +inline StyleSheetTable::Key::Key(const std::string &tag, const std::string &aClass) : TagName(tag), ClassName(aClass) { +} + +inline bool StyleSheetTable::Key::operator < (const StyleSheetTable::Key &key) const { + return (TagName < key.TagName) || ((TagName == key.TagName) && (ClassName < key.ClassName)); +} + +#endif /* __STYLESHEETTABLE_H__ */ diff --git a/reader/src/formats/doc/DocBookReader.cpp b/reader/src/formats/doc/DocBookReader.cpp new file mode 100644 index 0000000..99f471a --- /dev/null +++ b/reader/src/formats/doc/DocBookReader.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <vector> +#include <string> + +#include <ZLInputStream.h> +#include <ZLLogger.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLFileImage.h> + +#include "DocBookReader.h" +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +#include "OleStorage.h" +#include "OleMainStream.h" + +DocBookReader::DocBookReader(BookModel &model, const std::string &encoding) : + myModelReader(model), + myPictureCounter(0), + myEncoding(encoding) { + myReadState = READ_TEXT; +} + +bool DocBookReader::readBook() { + const ZLFile &file = myModelReader.model().book()->file(); + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull() || !stream->open()) { + return false; + } + myModelReader.setMainTextModel(); + myModelReader.pushKind(REGULAR); + myModelReader.beginParagraph(); + + if (!readDocument(stream, true)) { + return false; + } + + myModelReader.insertEndOfTextParagraph(); + return true; +} + +void DocBookReader::handleChar(ZLUnicodeUtil::Ucs2Char ucs2char) { + if (myReadState == READ_FIELD && myReadFieldState == READ_FIELD_INFO) { + myFieldInfoBuffer.push_back(ucs2char); + return; + } + if (myReadState == READ_FIELD && myReadFieldState == DONT_READ_FIELD_TEXT) { + return; + } + if (myReadState == READ_FIELD && myReadFieldState == READ_FIELD_TEXT && ucs2char == WORD_HORIZONTAL_TAB) { + //to remove pagination from TOC (from doc saved in OpenOffice) + myReadFieldState = DONT_READ_FIELD_TEXT; + return; + } + std::string utf8String; + ZLUnicodeUtil::Ucs2String ucs2String; + ucs2String.push_back(ucs2char); + ZLUnicodeUtil::ucs2ToUtf8(utf8String, ucs2String); + if (!myModelReader.paragraphIsOpen()) { + myModelReader.beginParagraph(); + } + myModelReader.addData(utf8String); +} + +void DocBookReader::handleHardLinebreak() { + if (myModelReader.paragraphIsOpen()) { + myModelReader.endParagraph(); + } + myModelReader.beginParagraph(); + if (!myCurrentStyleEntry.isNull()) { + myModelReader.addStyleEntry(*myCurrentStyleEntry); + } + for (std::size_t i = 0; i < myKindStack.size(); ++i) { + myModelReader.addControl(myKindStack.at(i), true); + } +} + +void DocBookReader::handleParagraphEnd() { + if (myModelReader.paragraphIsOpen()) { + myModelReader.endParagraph(); + } + myModelReader.beginParagraph(); + myCurrentStyleEntry = 0; +} + +void DocBookReader::handlePageBreak() { + if (myModelReader.paragraphIsOpen()) { + myModelReader.endParagraph(); + } + myCurrentStyleEntry = 0; + myModelReader.insertEndOfSectionParagraph(); + myModelReader.beginParagraph(); +} + +void DocBookReader::handleTableSeparator() { + handleChar(SPACE); + handleChar(VERTICAL_LINE); + handleChar(SPACE); +} + +void DocBookReader::handleTableEndRow() { + handleParagraphEnd(); +} + +void DocBookReader::handleFootNoteMark() { + //TODO implement +} + +void DocBookReader::handleStartField() { + if (myReadState == READ_FIELD) { //for nested fields + handleEndField(); + } + myReadState = READ_FIELD; + myReadFieldState = READ_FIELD_INFO; + myHyperlinkTypeState = NO_HYPERLINK; +} + +void DocBookReader::handleSeparatorField() { + static const std::string HYPERLINK = "HYPERLINK"; + static const std::string SEQUENCE = "SEQ"; +// static const std::string PAGE = "PAGE"; +// static const std::string PAGEREF = "PAGEREF"; +// static const std::string SHAPE = "SHAPE"; + static const std::string SPACE_DELIMETER = " "; + static const std::string LOCAL_LINK = "\\l"; + static const std::string QUOTE = "\""; + myReadFieldState = READ_FIELD_TEXT; + myHyperlinkTypeState = NO_HYPERLINK; + ZLUnicodeUtil::Ucs2String buffer = myFieldInfoBuffer; + myFieldInfoBuffer.clear(); + std::string utf8String; + ZLUnicodeUtil::ucs2ToUtf8(utf8String, buffer); + ZLUnicodeUtil::utf8Trim(utf8String); + if (utf8String.empty()) { + return; + } + std::vector<std::string> result = ZLStringUtil::split(utf8String, SPACE_DELIMETER); + //TODO split function can returns empty string, maybe fix it + std::vector<std::string> splitted; + for (std::size_t i = 0; i < result.size(); ++i) { + if (!result.at(i).empty()) { + splitted.push_back(result.at(i)); + } + } + + if (!splitted.empty() && splitted.at(0) == SEQUENCE) { + myReadFieldState = READ_FIELD_TEXT; + myHyperlinkTypeState = NO_HYPERLINK; + return; + } + + if (splitted.size() < 2 || splitted.at(0) != HYPERLINK) { + myReadFieldState = DONT_READ_FIELD_TEXT; + //to remove pagination from TOC and not hyperlink fields + return; + } + + if (splitted.at(1) == LOCAL_LINK) { + std::string link = parseLink(buffer); + if (!link.empty()) { + myModelReader.addHyperlinkControl(INTERNAL_HYPERLINK, link); + myHyperlinkTypeState = INT_HYPERLINK_INSERTED; + } + } else { + std::string link = parseLink(buffer, true); + if (!link.empty()) { + myModelReader.addHyperlinkControl(EXTERNAL_HYPERLINK, link); + myHyperlinkTypeState = EXT_HYPERLINK_INSERTED; + } + } +} + +void DocBookReader::handleEndField() { + myFieldInfoBuffer.clear(); + if (myReadState == READ_TEXT) { + return; + } + if (myHyperlinkTypeState == EXT_HYPERLINK_INSERTED) { + myModelReader.addControl(EXTERNAL_HYPERLINK, false); + } else if (myHyperlinkTypeState == INT_HYPERLINK_INSERTED) { + myModelReader.addControl(INTERNAL_HYPERLINK, false); + } + myReadState = READ_TEXT; + myHyperlinkTypeState = NO_HYPERLINK; + +} + +void DocBookReader::handleImage(const ZLFileImage::Blocks &blocks) { + std::string number; + ZLStringUtil::appendNumber(number, myPictureCounter++); + myModelReader.addImageReference(number); + ZLFile file(myModelReader.model().book()->file().path(), ZLMimeType::IMAGE_AUTO); + myModelReader.addImage(number, new ZLFileImage(file, blocks, ZLFileImage::ENCODING_NONE)); +} + +void DocBookReader::handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char) { + if (ucs2char == WORD_MINUS) { + handleChar(MINUS); + } else if (ucs2char == WORD_SOFT_HYPHEN) { + //skip + } else if (ucs2char == WORD_HORIZONTAL_TAB) { + handleChar(ucs2char); + } else { +// myTextBuffer.clear(); + } +} + +void DocBookReader::handleFontStyle(unsigned int fontStyle) { + if (myReadState == READ_FIELD && myReadFieldState == READ_FIELD_TEXT && myHyperlinkTypeState != NO_HYPERLINK) { + //to fix bug with hyperlink, that's only bold and doesn't looks like hyperlink + return; + } + while (!myKindStack.empty()) { + myModelReader.addControl(myKindStack.back(), false); + myKindStack.pop_back(); + } + if (fontStyle & OleMainStream::CharInfo::FONT_BOLD) { + myKindStack.push_back(BOLD); + } + if (fontStyle & OleMainStream::CharInfo::FONT_ITALIC) { + myKindStack.push_back(ITALIC); + } + for (std::size_t i = 0; i < myKindStack.size(); ++i) { + myModelReader.addControl(myKindStack.at(i), true); + } +} + +void DocBookReader::handleParagraphStyle(const OleMainStream::Style &styleInfo) { + if (styleInfo.HasPageBreakBefore) { + handlePageBreak(); + } + shared_ptr<ZLTextStyleEntry> entry = new ZLTextStyleEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + + switch (styleInfo.Alignment) { + default: // in that case, use default alignment type + break; + case OleMainStream::Style::ALIGNMENT_LEFT: + entry->setAlignmentType(ALIGN_LEFT); + break; + case OleMainStream::Style::ALIGNMENT_RIGHT: + entry->setAlignmentType(ALIGN_RIGHT); + break; + case OleMainStream::Style::ALIGNMENT_CENTER: + entry->setAlignmentType(ALIGN_CENTER); + break; + case OleMainStream::Style::ALIGNMENT_JUSTIFY: + entry->setAlignmentType(ALIGN_JUSTIFY); + break; + } + + //TODO in case, where style is heading, but size is small it works wrong + const ZLTextStyleEntry::SizeUnit unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT; + switch (styleInfo.StyleIdCurrent) { + default: + break; + case OleMainStream::Style::STYLE_H1: + entry->setLength(ZLTextStyleEntry::LENGTH_FONT_SIZE, 140, unit); + break; + case OleMainStream::Style::STYLE_H2: + entry->setLength(ZLTextStyleEntry::LENGTH_FONT_SIZE, 120, unit); + break; + case OleMainStream::Style::STYLE_H3: + entry->setLength(ZLTextStyleEntry::LENGTH_FONT_SIZE, 110, unit); + break; + } + myCurrentStyleEntry = entry; + myModelReader.addStyleEntry(*myCurrentStyleEntry); + + // we should have the same font style, as for the previous paragraph, + // if it has the same StyleIdCurrent + if (myCurrentStyleInfo.StyleIdCurrent != OleMainStream::Style::STYLE_INVALID && + myCurrentStyleInfo.StyleIdCurrent == styleInfo.StyleIdCurrent) { + for (std::size_t i = 0; i < myKindStack.size(); ++i) { + myModelReader.addControl(myKindStack.at(i), true); + } + } else { + myKindStack.clear(); + // fill by the fontstyle, that was got from Stylesheet + handleFontStyle(styleInfo.CurrentCharInfo.FontStyle); + } + myCurrentStyleInfo = styleInfo; +} + +void DocBookReader::handleBookmark(const std::string &name) { + myModelReader.addHyperlinkLabel(name); +} + +std::string DocBookReader::parseLink(ZLUnicodeUtil::Ucs2String s, bool urlencode) { + //TODO add support for HYPERLINK like that: + // [0x13] HYPERLINK "http://site.ru/some text" \t "_blank" [0x14] text [0x15] + //Current implementation search for last QUOTE, so, it reads \t and _blank as part of link + //Last quote searching is need to handle link like that: + // [0x13] HYPERLINK "http://yandex.ru/yandsearch?text='some text' и "some text2"" [0x14] link text [0x15] + + static const ZLUnicodeUtil::Ucs2Char QUOTE = 0x22; + std::size_t i, first = 0; + //TODO maybe functions findFirstOf and findLastOf should be in ZLUnicodeUtil class + for (i = 0; i < s.size(); ++i) { + if (s.at(i) == QUOTE) { + first = i; + break; + } + } + if (i == s.size()) { + return std::string(); + } + std::size_t j, last = 0; + for (j = s.size(); j > 0 ; --j) { + if (s.at(j - 1) == QUOTE) { + last = j - 1; + break; + } + } + if (j == 0 || last == first) { + return std::string(); + } + + ZLUnicodeUtil::Ucs2String link; + for (std::size_t k = first + 1; k < last; ++k) { + ZLUnicodeUtil::Ucs2Char ch = s.at(k); + if (urlencode && ZLUnicodeUtil::isSpace(ch)) { + //TODO maybe implement function for encoding all signs in url, not only spaces and quotes + //TODO maybe add backslash support + link.push_back('%'); + link.push_back('2'); + link.push_back('0'); + } else if (urlencode && ch == QUOTE) { + link.push_back('%'); + link.push_back('2'); + link.push_back('2'); + } else { + link.push_back(ch); + } + } + std::string utf8String; + ZLUnicodeUtil::ucs2ToUtf8(utf8String, link); + return utf8String; +} + +void DocBookReader::footnotesStartHandler() { + handlePageBreak(); +} + +void DocBookReader::ansiDataHandler(const char *buffer, std::size_t len) { + if (myConverter.isNull()) { + // lazy converter initialization + ZLEncodingCollection &collection = ZLEncodingCollection::Instance(); + ZLEncodingConverterInfoPtr info = collection.info(myEncoding); + myConverter = info.isNull() ? collection.defaultConverter() : info->createConverter(); + } + std::string utf8String; + myConverter->convert(utf8String, buffer, buffer + len); + ZLUnicodeUtil::utf8ToUcs2(myBuffer, utf8String); +} + +void DocBookReader::ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol) { + myBuffer.push_back(symbol); +} diff --git a/reader/src/formats/doc/DocBookReader.h b/reader/src/formats/doc/DocBookReader.h new file mode 100644 index 0000000..d80fb8e --- /dev/null +++ b/reader/src/formats/doc/DocBookReader.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCBOOKREADER_H__ +#define __DOCBOOKREADER_H__ + +#include <vector> + +#include <shared_ptr.h> +#include <ZLFile.h> +#include <ZLTextStyleEntry.h> +#include <ZLEncodingConverter.h> + +#include "../../bookmodel/BookReader.h" + +#include "OleMainStream.h" +#include "OleStreamParser.h" + +class DocBookReader : public OleStreamParser { + +public: + DocBookReader(BookModel &model, const std::string &encoding); + ~DocBookReader(); + bool readBook(); + +private: + void ansiDataHandler(const char *buffer, std::size_t len); + void ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol); + void footnotesStartHandler(); + + void handleChar(ZLUnicodeUtil::Ucs2Char ucs2char); + void handleHardLinebreak(); + void handleParagraphEnd(); + void handlePageBreak(); + void handleTableSeparator(); + void handleTableEndRow(); + void handleFootNoteMark(); + void handleStartField(); + void handleSeparatorField(); + void handleEndField(); + void handleImage(const ZLFileImage::Blocks &blocks); + void handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char); + + //formatting: + void handleFontStyle(unsigned int fontStyle); + void handleParagraphStyle(const OleMainStream::Style &styleInfo); + void handleBookmark(const std::string &name); + +private: + static std::string parseLink(ZLUnicodeUtil::Ucs2String s, bool urlencode = false); + +private: + BookReader myModelReader; + + ZLUnicodeUtil::Ucs2String myFieldInfoBuffer; + + enum { + READ_FIELD, + READ_TEXT + } myReadState; + + enum { + READ_FIELD_TEXT, + DONT_READ_FIELD_TEXT, + READ_FIELD_INFO + } myReadFieldState; + + //maybe it should be flag? + enum { + NO_HYPERLINK, + EXT_HYPERLINK_INSERTED, + INT_HYPERLINK_INSERTED + } myHyperlinkTypeState; + + //formatting + std::vector<FBTextKind> myKindStack; + shared_ptr<ZLTextStyleEntry> myCurrentStyleEntry; + OleMainStream::Style myCurrentStyleInfo; + unsigned int myPictureCounter; + + const std::string myEncoding; + shared_ptr<ZLEncodingConverter> myConverter; +}; + +inline DocBookReader::~DocBookReader() {} + +#endif /* __DOCBOOKREADER_H__ */ diff --git a/reader/src/formats/doc/DocFloatImageReader.cpp b/reader/src/formats/doc/DocFloatImageReader.cpp new file mode 100644 index 0000000..8c308e4 --- /dev/null +++ b/reader/src/formats/doc/DocFloatImageReader.cpp @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLLogger.h> + +#include "OleUtil.h" +#include "OleStream.h" +#include "OleMainStream.h" + +#include "DocFloatImageReader.h" + +DocFloatImageReader::DocFloatImageReader(unsigned int off, unsigned int len, shared_ptr<OleStream> tableStream, shared_ptr<OleStream> mainStream) : + myTableStream(tableStream), + myMainStream(mainStream), + myOffset(off), + myLength(len) { +} + +void DocFloatImageReader::readAll() { + //OfficeArtContent structure is described at p.405-406 [MS-DOC] + if (!myTableStream->seek(myOffset, true)) { + ZLLogger::Instance().println("DocPlugin", "problems with reading float images"); + return; + } + + unsigned int count = 0; + + RecordHeader header; + while (count < myLength) { + count += readRecordHeader(header, myTableStream); + switch (header.type) { + case 0xF000: + count += readDggContainer(myItem, header.length, myTableStream, myMainStream); + break; + case 0xF002: + count += readDgContainer(myItem, header.length, myTableStream); + break; + default: + return; + break; + } + } +} + +ZLFileImage::Blocks DocFloatImageReader::getBlocksForShapeId(unsigned int shapeId) const { + FSPContainer container; + bool found = false; + for (std::size_t i = 0; !found && i < myItem.FSPs.size(); ++i) { + if (myItem.FSPs.at(i).fsp.shapeId == shapeId) { + found = true; + container = myItem.FSPs.at(i); + } + } + + if (!found || container.fopte.empty()) { + return ZLFileImage::Blocks(); + } + + for (std::size_t i = 0; i < container.fopte.size(); ++i) { + const FOPTE &fopte = container.fopte.at(i); + if (fopte.pId == 0x0104 && !fopte.isComplex) { //0x0104 specifies the BLIP, see p.420 [MS-ODRAW] + if (fopte.value <= myItem.blips.size() && fopte.value > 0) { + Blip blip = myItem.blips.at(fopte.value - 1); + return blip.blocks; + } + } + } + return ZLFileImage::Blocks(); +} + +unsigned int DocFloatImageReader::readRecordHeader(RecordHeader &header, shared_ptr<OleStream> stream) { + //OfficeArtRecordHeader structure is described at p.26 [MS-ODRAW] + char buffer[8]; + stream->read(buffer, 8); + unsigned int temp = OleUtil::getU2Bytes(buffer, 0); + header.version = temp & 0x000F; + header.instance = temp >> 4; + header.type = OleUtil::getU2Bytes(buffer, 2); + header.length = OleUtil::getU4Bytes(buffer, 4); + return 8; +} + +unsigned int DocFloatImageReader::readDggContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream) { + //OfficeArtDggContainer structure is described at p.50 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF001: + count += readBStoreContainer(item, header.length, stream, mainStream); + break; + default: + count += skipRecord(header, stream); + break; + } + } + + stream->seek(1, false); //skipping dgglbl (see p.406 [MS-DOC]) + ++count; + + return count; +} + +unsigned int DocFloatImageReader::readBStoreContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream) { + //OfficeArtBStoreContainer structure is described at p.58 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF007: + { + Blip blip; + count += readBStoreContainerFileBlock(blip, stream, mainStream); + item.blips.push_back(blip); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::skipRecord(const RecordHeader &header, shared_ptr<OleStream> stream) { + stream->seek(header.length, false); + return header.length; +} + +unsigned int DocFloatImageReader::readBStoreContainerFileBlock(Blip &blip, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream) { + //OfficeArtBStoreContainerFileBlock structure is described at p.59 [MS-ODRAW] + unsigned int count = readFBSE(blip.storeEntry, stream); + if (blip.storeEntry.offsetInDelay != (unsigned int)-1) { + if (mainStream->seek(blip.storeEntry.offsetInDelay, true)) { //see p.70 [MS-ODRAW] + //TODO maybe we should stop reading float images here + ZLLogger::Instance().println("DocPlugin", "DocFloatImageReader: problems with seeking for offset"); + return count; + } + } + RecordHeader header; + unsigned int count2 = readRecordHeader(header, mainStream); + switch (header.type) { + case OleMainStream::IMAGE_WMF: + case OleMainStream::IMAGE_EMF: + case OleMainStream::IMAGE_PICT: + count2 += skipRecord(header, mainStream); + break; + case OleMainStream::IMAGE_JPEG: + case OleMainStream::IMAGE_JPEG2: + case OleMainStream::IMAGE_PNG: + case OleMainStream::IMAGE_DIB: + case OleMainStream::IMAGE_TIFF: + count2 += readBlip(blip, header, mainStream); + break; + } + blip.type = header.type; + return count; +} + +unsigned int DocFloatImageReader::readBlip(Blip &blip, const RecordHeader &header, shared_ptr<OleStream> stream) { + //OfficeArtBlip structure is described at p.60-66 [MS-ODRAW] + stream->seek(16, false); //skipping rgbUid1 + unsigned int count = 16; + + bool addField = false; + switch (header.type) { + case OleMainStream::IMAGE_PNG: + if (header.instance == 0x6E1) { + addField = true; + } + break; + case OleMainStream::IMAGE_JPEG: + case OleMainStream::IMAGE_JPEG2: + if (header.instance == 0x46B || header.instance == 0x6E3) { + addField = true; + } + break; + case OleMainStream::IMAGE_DIB: + if (header.instance == 0x7A9) { + addField = true; + } + case OleMainStream::IMAGE_TIFF: + if (header.instance == 0x6E5) { + addField = true; + } + break; + } + + if (addField) { + stream->seek(16, false); //skipping rgbUid2 + count += 16; + } + stream->seek(1, false); //skipping tag + count += 1; + + blip.blocks = stream->getBlockPieceInfoList(stream->offset(), header.length - count); + count += header.length; + return count; +} + +unsigned int DocFloatImageReader::readFBSE(BlipStoreEntry &fbse, shared_ptr<OleStream> stream) { + //OfficeArtFBSE structure is described at p.68 [MS-ODRAW] + stream->seek(2, false); //skipping btWin32 and btMacOS + stream->seek(16, false); //skipping rgbUid + stream->seek(2, false); //skipping tag + fbse.size = read4Bytes(stream); + fbse.referenceCount = read4Bytes(stream); + fbse.offsetInDelay = read4Bytes(stream); + stream->seek(1, false); //skipping unused value + unsigned int lengthName = read1Byte(stream); //if it should be multiplied on 2? + stream->seek(2, false); // skipping unused values + if (lengthName > 0) { + stream->seek(lengthName, false); //skipping nameData + } + return 36 + lengthName; +} + +unsigned int DocFloatImageReader::readDgContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream) { + //OfficeArtDgContainer structure is described at p.52 [MS-ODRAW] + unsigned int count = 0; + + RecordHeader header; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF008: //skip OfficeArtFDG record, p. 82 [MS-ODRAW] + stream->seek(8, false); + count += 8; + break; + case 0xF003: + count += readSpgrContainer(item, header.length, stream); + break; + case 0xF004: + { + FSPContainer fspContainer; + count += readSpContainter(fspContainer, header.length, stream); + item.FSPs.push_back(fspContainer); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readSpgrContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream) { + //OfficeArtSpgrContainer structure is described at p.56 [MS-ODRAW] + unsigned count = 0; + RecordHeader header; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF003: + count += readSpgrContainer(item, header.length, stream); + break; + case 0xF004: + { + FSPContainer fspContainer; + count += readSpContainter(fspContainer, header.length, stream); + item.FSPs.push_back(fspContainer); + } + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readSpContainter(FSPContainer &item, unsigned int length, shared_ptr<OleStream> stream) { + //OfficeArtSpContainter structure is described at p.53-55 [MS-ODRAW] + RecordHeader header; + unsigned int count = 0; + while (count < length) { + count += readRecordHeader(header, stream); + switch (header.type) { + case 0xF009: //skip OfficeArtFSPGR record, p.74 [MS-ODRAW] + stream->seek(16, false); + count += 16; + break; + case 0xF00A: + count += readFSP(item.fsp, stream); + break; + case 0xF00B: + count += readArrayFOPTE(item.fopte, header.length, stream); + break; + case 0xF00E: //OfficeArtAnchor + case 0xF00F: //OfficeArtChildAnchor, p.75 [MS-ODRAW] + case 0xF010: //OfficeArtClientAnchor + stream->seek(4, false); + count += 4; + break; + case 0xF00C: + case 0xF11F: + case 0xF11D: + break; + default: + count += skipRecord(header, stream); + break; + } + } + return count; +} + +unsigned int DocFloatImageReader::readFSP(FSP &fsp, shared_ptr<OleStream> stream) { + //OfficeArtFSP structure is described at p.76 [MS-ODRAW] + fsp.shapeId = read4Bytes(stream); + stream->seek(4, false); + return 8; +} + +unsigned int DocFloatImageReader::readArrayFOPTE(std::vector<FOPTE> &fopteArray,unsigned int length, shared_ptr<OleStream> stream) { + //OfficeArtRGFOPTE structure is described at p.98 [MS-ODRAW] + unsigned int count = 0; + while (count < length) { + FOPTE fopte; + count += readFOPTE(fopte, stream); + fopteArray.push_back(fopte); + } + for (std::size_t i = 0; i < fopteArray.size(); ++i) { + if (fopteArray.at(i).isComplex) { + stream->seek(fopteArray.at(i).value, false); + count += fopteArray.at(i).value; + } + } + return count; +} + +unsigned int DocFloatImageReader::readFOPTE(FOPTE &fopte, shared_ptr<OleStream> stream) { + //OfficeArtFOPTE structure is described at p.32 [MS-ODRAW] + unsigned int dtemp; + dtemp = read2Bytes(stream); + fopte.pId = (dtemp & 0x3fff); + fopte.isBlipId = ((dtemp & 0x4000) >> 14) == 0x1; + fopte.isComplex = ((dtemp & 0x8000) >> 15) == 0x1; + fopte.value = read4Bytes(stream); + return 6; +} + +unsigned int DocFloatImageReader::read1Byte(shared_ptr<OleStream> stream) { + char b[1]; + if (stream->read(b, 1) != 1) { + return 0; + } + return OleUtil::getU1Byte(b, 0); +} + +unsigned int DocFloatImageReader::read2Bytes(shared_ptr<OleStream> stream) { + char b[2]; + if (stream->read(b, 2) != 2) { + return 0; + } + return OleUtil::getU2Bytes(b, 0); +} + +unsigned int DocFloatImageReader::read4Bytes(shared_ptr<OleStream> stream) { + char b[4]; + if (stream->read(b, 4) != 4) { + return 0; + } + return OleUtil::getU4Bytes(b, 0); +} diff --git a/reader/src/formats/doc/DocFloatImageReader.h b/reader/src/formats/doc/DocFloatImageReader.h new file mode 100644 index 0000000..d2d6c2e --- /dev/null +++ b/reader/src/formats/doc/DocFloatImageReader.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCFLOATIMAGEREADER_H__ +#define __DOCFLOATIMAGEREADER_H__ + +#include <ZLFileImage.h> + +class DocFloatImageReader { + +public: + struct BlipStoreEntry { // see p.68 [MS-ODRAW] + unsigned int size; // size of blip in stream + unsigned int referenceCount; // (cRef) reference count for the the blip + unsigned int offsetInDelay; // foDelay, file offset in the delay stream + }; + + struct Blip { //see p.59, p63-66 [MS-ODRAW] + BlipStoreEntry storeEntry; + unsigned int type; + ZLFileImage::Blocks blocks; + }; + + struct FSP { //see p.76-77 [MS-ODRAW] + unsigned int shapeId; //spid + }; + + struct FOPTE { //see p.98 and p.32 [MS-ODRAW] + unsigned int pId; //pid + bool isBlipId; //fBid + bool isComplex; //fComplex + unsigned int value; //op + }; + + struct FSPContainer { //see p.53-55 [MS-ODRAW] + FSP fsp; + std::vector<FOPTE> fopte; + }; + + struct OfficeArtContent { //see p.405-406 [MS-DOC] + std::vector<Blip> blips; //retrieved from OfficeArtDggContainer + std::vector<FSPContainer> FSPs; //retrieved from OfficeArtDgContainer + }; + + struct RecordHeader { //see p.26 [MS-ODRAW] + unsigned int version; + unsigned int instance; + unsigned int type; + unsigned int length; + }; + +public: + DocFloatImageReader(unsigned int off, unsigned int len, shared_ptr<OleStream> tableStream, shared_ptr<OleStream> mainStream); + +public: + void readAll(); + + ZLFileImage::Blocks getBlocksForShapeId(unsigned int shapeId) const; + +private: + static unsigned int readRecordHeader(RecordHeader &header, shared_ptr<OleStream> stream); + static unsigned int readDggContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream); + + static unsigned int readBStoreContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream); + static unsigned int readBStoreContainerFileBlock(Blip &blip, shared_ptr<OleStream> stream, shared_ptr<OleStream> mainStream); + static unsigned int readBlip(Blip &blip, const RecordHeader &header, shared_ptr<OleStream> stream); + static unsigned int readFBSE(BlipStoreEntry &fbse, shared_ptr<OleStream> stream); + + static unsigned int readFOPTE(FOPTE &fopte, shared_ptr<OleStream> stream); + static unsigned int readArrayFOPTE(std::vector<FOPTE> &fopte, unsigned int length, shared_ptr<OleStream> stream); + static unsigned int readFSP(FSP &fsp, shared_ptr<OleStream> stream); + static unsigned int readSpContainter(FSPContainer &item, unsigned int length, shared_ptr<OleStream> stream); + static unsigned int readSpgrContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream); + static unsigned int readDgContainer(OfficeArtContent &item, unsigned int length, shared_ptr<OleStream> stream); + + static unsigned int skipRecord(const RecordHeader &header, shared_ptr<OleStream> stream); + + static unsigned int read1Byte(shared_ptr<OleStream> stream); + static unsigned int read2Bytes(shared_ptr<OleStream> stream); + static unsigned int read4Bytes(shared_ptr<OleStream> stream); + +private: + shared_ptr<OleStream> myTableStream; + shared_ptr<OleStream> myMainStream; + unsigned int myOffset; + unsigned int myLength; + + OfficeArtContent myItem; +}; + +#endif /* __DOCFLOATIMAGEREADER_H__ */ diff --git a/reader/src/formats/doc/DocInlineImageReader.cpp b/reader/src/formats/doc/DocInlineImageReader.cpp new file mode 100644 index 0000000..69ce74f --- /dev/null +++ b/reader/src/formats/doc/DocInlineImageReader.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "OleUtil.h" +#include "OleMainStream.h" + +#include "DocInlineImageReader.h" + +DocInlineImageReader::DocInlineImageReader(shared_ptr<OleStream> dataStream) : + myDataStream(dataStream) { +} + +ZLFileImage::Blocks DocInlineImageReader::getImagePieceInfo(unsigned int dataPos) { + if (myDataStream.isNull()) { + return ZLFileImage::Blocks(); + } + if (!myDataStream->seek(dataPos, true)) { + return ZLFileImage::Blocks(); + } + + //reading PICF structure (see p. 421 [MS-DOC]) + unsigned int picfHeaderSize = 4 + 2 + 8; //record length, headerLength and storage format + char headerBuffer[picfHeaderSize]; + if (myDataStream->read(headerBuffer, picfHeaderSize) != picfHeaderSize) { + return ZLFileImage::Blocks(); + } + unsigned int length = OleUtil::getU4Bytes(headerBuffer, 0); + unsigned int headerLength = OleUtil::getU2Bytes(headerBuffer, 4); + unsigned int formatType = OleUtil::getU2Bytes(headerBuffer, 6); + + if (formatType != 0x0064) { //external link to some file; see p.394 [MS-DOC] + //TODO implement + return ZLFileImage::Blocks(); + } + if (headerLength >= length) { + return ZLFileImage::Blocks(); + } + + //reading OfficeArtInlineSpContainer structure; see p.421 [MS-DOC] and p.56 [MS-ODRAW] + if (!myDataStream->seek(headerLength - picfHeaderSize, false)) { //skip header + return ZLFileImage::Blocks(); + } + + char buffer[8]; //for OfficeArtRecordHeader structure; see p.69 [MS-ODRAW] + bool found = false; + unsigned int curOffset = 0; + for (curOffset = headerLength; !found && curOffset + 8 <= length; curOffset += 8) { + if (myDataStream->read(buffer, 8) != 8) { + return ZLFileImage::Blocks(); + } + unsigned int recordInstance = OleUtil::getU2Bytes(buffer, 0) >> 4; + unsigned int recordType = OleUtil::getU2Bytes(buffer, 2); + unsigned int recordLen = OleUtil::getU4Bytes(buffer, 4); + + switch (recordType) { + case 0xF000: case 0xF001: case 0xF002: case 0xF003: case 0xF004: case 0xF005: + break; + case 0xF007: + { + myDataStream->seek(33, false); + char tmpBuf[1]; + myDataStream->read(tmpBuf, 1); + unsigned int nameLength = OleUtil::getU1Byte(tmpBuf, 0); + myDataStream->seek(nameLength * 2 + 2, false); + curOffset += 33 + 1 + nameLength * 2 + 2; + } + break; + case 0xF008: + myDataStream->seek(8, false); + curOffset += 8; + break; + case 0xF009: + myDataStream->seek(16, false); + curOffset += 16; + break; + case 0xF006: case 0xF00A: case 0xF00B: case 0xF00D: case 0xF00E: case 0xF00F: case 0xF010: case 0xF011: case 0xF122: + myDataStream->seek(recordLen, false); + curOffset += recordLen; + break; + case OleMainStream::IMAGE_EMF: + case OleMainStream::IMAGE_WMF: + case OleMainStream::IMAGE_PICT: + //TODO implement + return ZLFileImage::Blocks(); + case OleMainStream::IMAGE_JPEG: + case OleMainStream::IMAGE_JPEG2: + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x46B || recordInstance == 0x6E3) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::IMAGE_PNG: + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x6E1) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::IMAGE_DIB: // DIB = BMP without 14-bytes header + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x7A9) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case OleMainStream::IMAGE_TIFF: + myDataStream->seek(17, false); + curOffset += 17; + if (recordInstance == 0x6E5) { + myDataStream->seek(16, false); + curOffset += 16; + } + found = true; + break; + case 0xF00C: + default: + return ZLFileImage::Blocks(); + } + } + + if (!found) { + return ZLFileImage::Blocks(); + } + return myDataStream->getBlockPieceInfoList(dataPos + curOffset, length - curOffset); +} diff --git a/reader/src/formats/doc/DocInlineImageReader.h b/reader/src/formats/doc/DocInlineImageReader.h new file mode 100644 index 0000000..9dab9ae --- /dev/null +++ b/reader/src/formats/doc/DocInlineImageReader.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCINLINEIMAGEREADER_H__ +#define __DOCINLINEIMAGEREADER_H__ + +#include <vector> + +#include "OleStream.h" + +class DocInlineImageReader { + +public: + DocInlineImageReader(shared_ptr<OleStream> dataStream); + ZLFileImage::Blocks getImagePieceInfo(unsigned int dataPos); + +private: + shared_ptr<OleStream> myDataStream; +}; + +#endif /* __DOCINLINEIMAGEREADER_H__ */ diff --git a/reader/src/formats/doc/DocMetaInfoReader.cpp b/reader/src/formats/doc/DocMetaInfoReader.cpp new file mode 100644 index 0000000..37b39c2 --- /dev/null +++ b/reader/src/formats/doc/DocMetaInfoReader.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "../../library/Book.h" + +#include "DocMetaInfoReader.h" + +DocMetaInfoReader::DocMetaInfoReader(Book &book) : myBook(book) { + myBook.removeAllAuthors(); + myBook.setTitle(std::string()); + myBook.setLanguage(std::string()); + myBook.removeAllTags(); +} + +bool DocMetaInfoReader::readMetaInfo() { + myBook.removeAllAuthors(); + myBook.setTitle(myBook.file().name(true)); + myBook.removeAllTags(); + return true; +} diff --git a/reader/src/formats/doc/DocMetaInfoReader.h b/reader/src/formats/doc/DocMetaInfoReader.h new file mode 100644 index 0000000..db26d29 --- /dev/null +++ b/reader/src/formats/doc/DocMetaInfoReader.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCMETAINFOREADER_H__ +#define __DOCMETAINFOREADER_H__ + +#include <string> + +class Book; + +class DocMetaInfoReader { + +public: + DocMetaInfoReader(Book &book); + ~DocMetaInfoReader(); + bool readMetaInfo(); + + /* + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + */ + +private: + Book &myBook; +}; + +inline DocMetaInfoReader::~DocMetaInfoReader() {} + +#endif /* __DOCMETAINFOREADER_H__ */ diff --git a/reader/src/formats/doc/DocPlugin.cpp b/reader/src/formats/doc/DocPlugin.cpp new file mode 100644 index 0000000..ef6f511 --- /dev/null +++ b/reader/src/formats/doc/DocPlugin.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> +#include <ZLLogger.h> +#include <ZLImage.h> +#include <ZLEncodingConverter.h> + +#include "DocPlugin.h" +#include "DocMetaInfoReader.h" +#include "DocBookReader.h" +#include "DocStreams.h" +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +DocPlugin::DocPlugin() { +} + +DocPlugin::~DocPlugin() { +} + +bool DocPlugin::providesMetaInfo() const { + return true; +} + +const std::string DocPlugin::supportedFileType() const { + return "doc"; +} + +bool DocPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "doc"; +} + +bool DocPlugin::readMetaInfo(Book &book) const { + if (!DocMetaInfoReader(book).readMetaInfo()) { + return false; + } + + shared_ptr<ZLInputStream> stream = new DocAnsiStream(book.file(), 50000); + if (!detectEncodingAndLanguage(book, *stream)) { + stream = new DocUcs2Stream(book.file(), 50000); + detectLanguage(book, *stream, ZLEncodingConverter::UTF8, true); + } + + return true; +} + +bool DocPlugin::readLanguageAndEncoding(Book &/*book*/) const { + return true; +} + +bool DocPlugin::readModel(BookModel &model) const { + return DocBookReader(model, model.book()->encoding()).readBook(); +} diff --git a/reader/src/formats/doc/DocPlugin.h b/reader/src/formats/doc/DocPlugin.h new file mode 100644 index 0000000..93b1803 --- /dev/null +++ b/reader/src/formats/doc/DocPlugin.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCPLUGIN_H__ +#define __DOCPLUGIN_H__ + +#include "../FormatPlugin.h" + +class DocPlugin : public FormatPlugin { + +public: + DocPlugin(); + ~DocPlugin(); + bool providesMetaInfo() const; + + const std::string supportedFileType() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +#endif /* __DOCPLUGIN_H__ */ diff --git a/reader/src/formats/doc/DocStreams.cpp b/reader/src/formats/doc/DocStreams.cpp new file mode 100644 index 0000000..b21e15a --- /dev/null +++ b/reader/src/formats/doc/DocStreams.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cstdlib> +#include <string> + +#include "DocStreams.h" +#include "OleStreamReader.h" + +class DocReader : public OleStreamReader { + +public: + DocReader(char *buffer, std::size_t maxSize); + ~DocReader(); + std::size_t readSize() const; + +private: + bool readStream(OleMainStream &stream); + void ansiDataHandler(const char *buffer, std::size_t len); + void ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol); + void footnotesStartHandler(); + +protected: + char *myBuffer; + const std::size_t myMaxSize; + std::size_t myActualSize; +}; + +class DocAnsiReader : public DocReader { + +public: + DocAnsiReader(char *buffer, std::size_t maxSize); + ~DocAnsiReader(); + +private: + void ansiDataHandler(const char *buffer, std::size_t len); +}; + +class DocUcs2Reader : public DocReader { + +public: + DocUcs2Reader(char *buffer, std::size_t maxSize); + ~DocUcs2Reader(); + +private: + void ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol); +}; + +DocReader::DocReader(char *buffer, std::size_t maxSize) : myBuffer(buffer), myMaxSize(maxSize), myActualSize(0) { +} + +DocReader::~DocReader() { +} + +bool DocReader::readStream(OleMainStream &stream) { + // TODO make 2 optmizations: + // 1) If another piece is too big, reading of next piece can be stopped if some size parameter will be specified + // (it can be transfered as a parameter (with default 0 value, that means no need to use it) to readNextPiece method) + // 2) We can specify as a parameter for readNextPiece, what kind of piece should be read next (ANSI or not ANSI). + // As type of piece is known already, there's no necessary to read other pieces. + while (myActualSize < myMaxSize) { + if (!readNextPiece(stream)) { + break; + } + } + return true; +} + +void DocReader::ansiDataHandler(const char*, std::size_t) { +} + +void DocReader::ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char) { +} + +void DocReader::footnotesStartHandler() { +} + +std::size_t DocReader::readSize() const { + return myActualSize; +} + +DocAnsiReader::DocAnsiReader(char *buffer, std::size_t maxSize) : DocReader(buffer, maxSize) { +} + +DocAnsiReader::~DocAnsiReader() { +} + +void DocAnsiReader::ansiDataHandler(const char *buffer, std::size_t dataLength) { + if (myActualSize < myMaxSize) { + const std::size_t len = std::min(dataLength, myMaxSize - myActualSize); + std::strncpy(myBuffer + myActualSize, buffer, len); + myActualSize += len; + } +} + +DocUcs2Reader::DocUcs2Reader(char *buffer, std::size_t maxSize) : DocReader(buffer, maxSize) { +} + +DocUcs2Reader::~DocUcs2Reader() { +} + +void DocUcs2Reader::ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol) { + if (myActualSize < myMaxSize) { + char buffer[4]; + const std::size_t dataLength = ZLUnicodeUtil::ucs2ToUtf8(buffer, symbol); + const std::size_t len = std::min(dataLength, myMaxSize - myActualSize); + std::strncpy(myBuffer + myActualSize, buffer, len); + myActualSize += len; + } +} + +DocStream::DocStream(const ZLFile& file, std::size_t maxSize) : myFile(file), myBuffer(0), mySize(maxSize) { +} + +DocStream::~DocStream() { + close(); +} + +bool DocStream::open() { + if (mySize != 0) { + myBuffer = new char[mySize]; + } + shared_ptr<DocReader> reader = createReader(myBuffer, mySize); + shared_ptr<ZLInputStream> stream = myFile.inputStream(); + if (stream.isNull() || !stream->open()) { + return false; + } + if (!reader->readDocument(stream, false)) { + return false; + } + mySize = reader->readSize(); + myOffset = 0; + return true; +} + +std::size_t DocStream::read(char *buffer, std::size_t maxSize) { + maxSize = std::min(maxSize, mySize - myOffset); + if (buffer != 0 && myBuffer != 0) { + std::memcpy(buffer, myBuffer + myOffset, maxSize); + } + myOffset += maxSize; + return maxSize; +} + +void DocStream::close() { + if (myBuffer != 0) { + delete[] myBuffer; + myBuffer = 0; + } +} + +void DocStream::seek(int offset, bool absoluteOffset) { + if (!absoluteOffset) { + offset += myOffset; + } + myOffset = std::min(mySize, (std::size_t)std::max(0, offset)); +} + +std::size_t DocStream::offset() const { + return myOffset; +} + +std::size_t DocStream::sizeOfOpened() { + return mySize; +} + +DocAnsiStream::DocAnsiStream(const ZLFile& file, std::size_t maxSize) : DocStream(file, maxSize) { +} + +DocAnsiStream::~DocAnsiStream() { +} + +shared_ptr<DocReader> DocAnsiStream::createReader(char *buffer, std::size_t maxSize) { + return new DocAnsiReader(buffer, maxSize); +} + +DocUcs2Stream::DocUcs2Stream(const ZLFile& file, std::size_t maxSize) : DocStream(file, maxSize) { +} + +DocUcs2Stream::~DocUcs2Stream() { +} + +shared_ptr<DocReader> DocUcs2Stream::createReader(char *buffer, std::size_t maxSize) { + return new DocUcs2Reader(buffer, maxSize); +} diff --git a/reader/src/formats/doc/DocStreams.h b/reader/src/formats/doc/DocStreams.h new file mode 100644 index 0000000..4b1538a --- /dev/null +++ b/reader/src/formats/doc/DocStreams.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCSTREAMS_H__ +#define __DOCSTREAMS_H__ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +class DocReader; + +class DocStream : public ZLInputStream { + +public: + DocStream(const ZLFile& file, std::size_t maxSize); + ~DocStream(); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +protected: + virtual shared_ptr<DocReader> createReader(char *buffer, std::size_t maxSize) = 0; + +private: + const ZLFile myFile; + char *myBuffer; + std::size_t mySize; + std::size_t myOffset; +}; + +class DocAnsiStream : public DocStream { + +public: + DocAnsiStream(const ZLFile& file, std::size_t maxSize); + ~DocAnsiStream(); + +private: + shared_ptr<DocReader> createReader(char *buffer, std::size_t maxSize); +}; + +class DocUcs2Stream : public DocStream { + +public: + DocUcs2Stream(const ZLFile& file, std::size_t maxSize); + ~DocUcs2Stream(); + +private: + shared_ptr<DocReader> createReader(char *buffer, std::size_t maxSize); +}; + +#endif /* __DOCSTREAMS_H__ */ diff --git a/reader/src/formats/doc/OleMainStream.cpp b/reader/src/formats/doc/OleMainStream.cpp new file mode 100644 index 0000000..fe829e6 --- /dev/null +++ b/reader/src/formats/doc/OleMainStream.cpp @@ -0,0 +1,1085 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <string> + +#include <ZLLogger.h> +#include <ZLUnicodeUtil.h> + +#include "OleUtil.h" +#include "OleStorage.h" + +#include "DocInlineImageReader.h" + +#include "OleMainStream.h" + +OleMainStream::Style::Style() : + StyleIdCurrent(STYLE_INVALID), + StyleIdNext(STYLE_INVALID), + HasPageBreakBefore(false), + BeforeParagraphIndent(0), + AfterParagraphIndent(0), + LeftIndent(0), + FirstLineIndent(0), + RightIndent(0), + Alignment(ALIGNMENT_DEFAULT) { +} + +OleMainStream::CharInfo::CharInfo() : FontStyle(FONT_REGULAR), FontSize(20) { +} + +OleMainStream::SectionInfo::SectionInfo() : CharPosition(0), IsNewPage(true) { +} + +OleMainStream::InlineImageInfo::InlineImageInfo() : DataPosition(0) { +} + +OleMainStream::FloatImageInfo::FloatImageInfo() : ShapeId(0) { +} + +OleMainStream::OleMainStream(shared_ptr<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> stream) : OleStream(storage, oleEntry, stream) { +} + +bool OleMainStream::open(bool doReadFormattingData) { + if (OleStream::open() == false) { + return false; + } + + static const std::size_t HEADER_SIZE = 768; //size of data in header of main stream + char headerBuffer[HEADER_SIZE]; + seek(0, true); + + if (read(headerBuffer, HEADER_SIZE) != HEADER_SIZE) { + return false; + } + + bool result = readFIB(headerBuffer); + if (!result) { + return false; + } + + // determining table stream number + unsigned int tableNumber = (OleUtil::getU2Bytes(headerBuffer, 0xA) & 0x0200) ? 1 : 0; + std::string tableName = tableNumber == 0 ? "0" : "1"; + tableName += "Table"; + OleEntry tableEntry; + result = myStorage->getEntryByName(tableName, tableEntry); + + if (!result) { + // cant't find table stream (that can be only in case if file format is below Word 7/8), so building simple table stream + // TODO: CHECK may be not all old documents have ANSI + ZLLogger::Instance().println("DocPlugin", "cant't find table stream, building own simple piece table, that includes all charachters"); + Piece piece = {myStartOfText, myEndOfText - myStartOfText, true, Piece::PIECE_TEXT, 0}; + myPieces.push_back(piece); + return true; + } + + result = readPieceTable(headerBuffer, tableEntry); + + if (!result) { + ZLLogger::Instance().println("DocPlugin", "error during reading piece table"); + return false; + } + + if (!doReadFormattingData) { + return true; + } + + OleEntry dataEntry; + if (myStorage->getEntryByName("Data", dataEntry)) { + myDataStream = new OleStream(myStorage, dataEntry, myBaseStream); + } + + //result of reading following structures doesn't check, because all these + //problems can be ignored, and document can be showed anyway, maybe with wrong formatting + readBookmarks(headerBuffer, tableEntry); + readStylesheet(headerBuffer, tableEntry); + //readSectionsInfoTable(headerBuffer, tableEntry); //it isn't used now + readParagraphStyleTable(headerBuffer, tableEntry); + readCharInfoTable(headerBuffer, tableEntry); + readFloatingImages(headerBuffer, tableEntry); + return true; +} + +const OleMainStream::Pieces &OleMainStream::getPieces() const { + return myPieces; +} + +const OleMainStream::CharInfoList &OleMainStream::getCharInfoList() const { + return myCharInfoList; +} + +const OleMainStream::StyleInfoList &OleMainStream::getStyleInfoList() const { + return myStyleInfoList; +} + +const OleMainStream::BookmarksList &OleMainStream::getBookmarks() const { + return myBookmarks; +} + +const OleMainStream::InlineImageInfoList &OleMainStream::getInlineImageInfoList() const { + return myInlineImageInfoList; +} + +const OleMainStream::FloatImageInfoList &OleMainStream::getFloatImageInfoList() const { + return myFloatImageInfoList; +} + +ZLFileImage::Blocks OleMainStream::getFloatImage(unsigned int shapeId) const { + if (myFLoatImageReader.isNull()) { + return ZLFileImage::Blocks(); + } + return myFLoatImageReader->getBlocksForShapeId(shapeId); +} + +ZLFileImage::Blocks OleMainStream::getInlineImage(unsigned int dataPosition) const { + if (myDataStream.isNull()) { + return ZLFileImage::Blocks(); + } + DocInlineImageReader imageReader(myDataStream); + return imageReader.getImagePieceInfo(dataPosition); +} + +bool OleMainStream::readFIB(const char *headerBuffer) { + int flags = OleUtil::getU2Bytes(headerBuffer, 0xA); //offset for flags + + if (flags & 0x0004) { //flag for complex format + ZLLogger::Instance().println("DocPlugin", "This was fast-saved. Some information is lost"); + //lostInfo = (flags & 0xF0) >> 4); + } + + if (flags & 0x1000) { //flag for using extending charset + ZLLogger::Instance().println("DocPlugin", "File uses extended character set (get_word8_char)"); + } else { + ZLLogger::Instance().println("DocPlugin", "File uses get_8bit_char character set"); + } + + if (flags & 0x100) { //flag for encrypted files + ZLLogger::Instance().println("DocPlugin", "File is encrypted"); + // Encryption key = %08lx ; NumUtil::get4Bytes(header, 14) + return false; + } + + unsigned int charset = OleUtil::getU2Bytes(headerBuffer, 0x14); //offset for charset number + if (charset && charset != 0x100) { //0x100 = default charset + ZLLogger::Instance().println("DocPlugin", "Using not default character set %d"); + } else { + ZLLogger::Instance().println("DocPlugin", "Using default character set"); + } + + myStartOfText = OleUtil::get4Bytes(headerBuffer, 0x18); //offset for start of text value + myEndOfText = OleUtil::get4Bytes(headerBuffer, 0x1c); //offset for end of text value + return true; +} + +void OleMainStream::splitPieces(const Pieces &s, Pieces &dest1, Pieces &dest2, Piece::PieceType type1, Piece::PieceType type2, int boundary) { + Pieces source = s; + dest1.clear(); + dest2.clear(); + + int sumLength = 0; + std::size_t i = 0; + for (i = 0; i < source.size(); ++i) { + Piece piece = source.at(i); + if (piece.Length + sumLength >= boundary) { + Piece piece2 = piece; + + piece.Length = boundary - sumLength; + piece.Type = type1; + + piece2.Type = type2; + piece2.Offset += piece.Length * 2; + piece2.Length -= piece.Length; + + if (piece.Length > 0) { + dest1.push_back(piece); + } + if (piece2.Length > 0) { + dest2.push_back(piece2); + } + ++i; + break; + } + sumLength += piece.Length; + piece.Type = type1; + dest1.push_back(piece); + } + for (; i < source.size(); ++i) { + Piece piece = source.at(i); + piece.Type = type2; + dest2.push_back(piece); + } + +} + +std::string OleMainStream::getPiecesTableBuffer(const char *headerBuffer, OleStream &tableStream) { + unsigned int clxOffset = OleUtil::getU4Bytes(headerBuffer, 0x01A2); //offset for CLX structure + unsigned int clxLength = OleUtil::getU4Bytes(headerBuffer, 0x01A6); //offset for value of CLX structure length + + //1 step : loading CLX table from table stream + char *clxBuffer = new char[clxLength]; + if (!tableStream.seek(clxOffset, true)) { + ZLLogger::Instance().println("DocPlugin", "getPiecesTableBuffer -- error for seeking to CLX structure"); + return std::string(); + } + if (tableStream.read(clxBuffer, clxLength) != clxLength) { + ZLLogger::Instance().println("DocPlugin", "getPiecesTableBuffer -- CLX structure length is invalid"); + return std::string(); + } + std::string clx(clxBuffer, clxLength); + delete[] clxBuffer; + + //2 step: searching for pieces table buffer at CLX + //(determines it by 0x02 as start symbol) + std::size_t from = 0; + std::size_t i; + std::string pieceTableBuffer; + while ((i = clx.find_first_of(0x02, from)) != std::string::npos) { + if (clx.size() < i + 1 + 4) { + ZLLogger::Instance().println("DocPlugin", "getPiecesTableBuffer -- CLX structure has invalid format"); + return std::string(); + } + unsigned int pieceTableLength = OleUtil::getU4Bytes(clx.c_str(), i + 1); + pieceTableBuffer = std::string(clx, i + 1 + 4); + if (pieceTableBuffer.length() != pieceTableLength) { + from = i + 1; + continue; + } + break; + } + return pieceTableBuffer; +} + + +bool OleMainStream::readPieceTable(const char *headerBuffer, const OleEntry &tableEntry) { + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string piecesTableBuffer = getPiecesTableBuffer(headerBuffer, tableStream); + + if (piecesTableBuffer.empty()) { + return false; + } + + //getting count of Character Positions for different types of subdocuments in Main Stream + int ccpText = OleUtil::get4Bytes(headerBuffer, 0x004C); //text + int ccpFtn = OleUtil::get4Bytes(headerBuffer, 0x0050); //footnote subdocument + int ccpHdd = OleUtil::get4Bytes(headerBuffer, 0x0054); //header subdocument + int ccpMcr = OleUtil::get4Bytes(headerBuffer, 0x0058); //macro subdocument + int ccpAtn = OleUtil::get4Bytes(headerBuffer, 0x005C); //comment subdocument + int ccpEdn = OleUtil::get4Bytes(headerBuffer, 0x0060); //endnote subdocument + int ccpTxbx = OleUtil::get4Bytes(headerBuffer, 0x0064); //textbox subdocument + int ccpHdrTxbx = OleUtil::get4Bytes(headerBuffer, 0x0068); //textbox subdocument of the header + int lastCP = ccpFtn + ccpHdd + ccpMcr + ccpAtn + ccpEdn + ccpTxbx + ccpHdrTxbx; + if (lastCP != 0) { + ++lastCP; + } + lastCP += ccpText; + + //getting the CP (character positions) and CP descriptors + std::vector<int> cp; //array of character positions for pieces + unsigned int j = 0; + for (j = 0; ; j += 4) { + if (piecesTableBuffer.size() < j + 4) { + ZLLogger::Instance().println("DocPlugin", "invalid piece table, cp ends not with a lastcp"); + break; + } + int curCP = OleUtil::get4Bytes(piecesTableBuffer.c_str(), j); + cp.push_back(curCP); + if (curCP == lastCP) { + break; + } + } + + if (cp.size() < 2) { + ZLLogger::Instance().println("DocPlugin", "invalid piece table, < 2 pieces"); + return false; + } + + std::vector<std::string> descriptors; + for (std::size_t k = 0; k < cp.size() - 1; ++k) { + //j + 4, because it should be taken after CP in PiecesTable Buffer + //k * 8, because it should be taken 8 byte for each descriptor + std::size_t substrFrom = j + 4 + k * 8; + if (piecesTableBuffer.size() < substrFrom + 8) { + ZLLogger::Instance().println("DocPlugin", "invalid piece table, problems with descriptors reading"); + break; + } + descriptors.push_back(piecesTableBuffer.substr(substrFrom, 8)); + } + + //filling the Pieces vector + std::size_t minValidSize = std::min(cp.size() - 1, descriptors.size()); + if (minValidSize == 0) { + ZLLogger::Instance().println("DocPlugin", "invalid piece table, there are no pieces"); + return false; + } + + for (std::size_t i = 0; i < minValidSize; ++i) { + //4byte integer with offset and ANSI flag + int fcValue = OleUtil::get4Bytes(descriptors.at(i).c_str(), 0x2); //offset for piece structure + Piece piece; + piece.IsANSI = (fcValue & 0x40000000) == 0x40000000; //ansi flag + piece.Offset = fcValue & 0x3FFFFFFF; //gettting offset for current piece + piece.Length = cp.at(i + 1) - cp.at(i); + myPieces.push_back(piece); + } + + //split pieces into different types + Pieces piecesText, piecesFootnote, piecesOther; + splitPieces(myPieces, piecesText, piecesFootnote, Piece::PIECE_TEXT, Piece::PIECE_FOOTNOTE, ccpText); + splitPieces(piecesFootnote, piecesFootnote, piecesOther, Piece::PIECE_FOOTNOTE, Piece::PIECE_OTHER, ccpFtn); + + myPieces.clear(); + for (std::size_t i = 0; i < piecesText.size(); ++i) { + myPieces.push_back(piecesText.at(i)); + } + for (std::size_t i = 0; i < piecesFootnote.size(); ++i) { + myPieces.push_back(piecesFootnote.at(i)); + } + for (std::size_t i = 0; i < piecesOther.size(); ++i) { + myPieces.push_back(piecesOther.at(i)); + } + + //converting length and offset depending on isANSI + for (std::size_t i = 0; i < myPieces.size(); ++i) { + Piece &piece = myPieces.at(i); + if (!piece.IsANSI) { + piece.Length *= 2; + } else { + piece.Offset /= 2; + } + } + + //filling startCP field + unsigned int curStartCP = 0; + for (std::size_t i = 0; i < myPieces.size(); ++i) { + Piece &piece = myPieces.at(i); + piece.startCP = curStartCP; + if (piece.IsANSI) { + curStartCP += piece.Length; + } else { + curStartCP += piece.Length / 2; + } + } + return true; +} + +bool OleMainStream::readBookmarks(const char *headerBuffer, const OleEntry &tableEntry) { + //SttbfBkmk structure is a table of bookmark name strings + unsigned int beginNamesInfo = OleUtil::getU4Bytes(headerBuffer, 0x142); // address of SttbfBkmk structure + std::size_t namesInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x146); // length of SttbfBkmk structure + + if (namesInfoLength == 0) { + return true; //there's no bookmarks + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginNamesInfo, namesInfoLength, tableStream)) { + return false; + } + + unsigned int recordsNumber = OleUtil::getU2Bytes(buffer.c_str(), 0x2); //count of records + + std::vector<std::string> names; + unsigned int offset = 0x6; //initial offset + for (unsigned int i = 0; i < recordsNumber; ++i) { + if (buffer.size() < offset + 2) { + ZLLogger::Instance().println("DocPlugin", "problmes with reading bookmarks names"); + break; + } + unsigned int length = OleUtil::getU2Bytes(buffer.c_str(), offset) * 2; //length of string in bytes + ZLUnicodeUtil::Ucs2String name; + for (unsigned int j = 0; j < length; j+=2) { + char ch1 = buffer.at(offset + 2 + j); + char ch2 = buffer.at(offset + 2 + j + 1); + ZLUnicodeUtil::Ucs2Char ucs2Char = (unsigned int)ch1 | ((unsigned int)ch2 << 8); + name.push_back(ucs2Char); + } + std::string utf8Name; + ZLUnicodeUtil::ucs2ToUtf8(utf8Name, name); + names.push_back(utf8Name); + offset += length + 2; + } + + //plcfBkmkf structure is table recording beginning CPs of bookmarks + unsigned int beginCharPosInfo = OleUtil::getU4Bytes(headerBuffer, 0x14A); // address of plcfBkmkf structure + std::size_t charPosInfoLen = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x14E); // length of plcfBkmkf structure + + if (charPosInfoLen == 0) { + return true; //there's no bookmarks + } + + if (!readToBuffer(buffer, beginCharPosInfo, charPosInfoLen, tableStream)) { + return false; + } + + static const unsigned int BKF_SIZE = 4; + std::size_t size = calcCountOfPLC(charPosInfoLen, BKF_SIZE); + std::vector<unsigned int> charPage; + for (std::size_t index = 0, offset = 0; index < size; ++index, offset += 4) { + charPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); + } + + for (std::size_t i = 0; i < names.size(); ++i) { + if (i >= charPage.size()) { + break; //for the case if something in these structures goes wrong, to not to lose all bookmarks + } + Bookmark bookmark; + bookmark.CharPosition = charPage.at(i); + bookmark.Name = names.at(i); + myBookmarks.push_back(bookmark); + } + + return true; +} + +bool OleMainStream::readStylesheet(const char *headerBuffer, const OleEntry &tableEntry) { + //STSH structure is a stylesheet + unsigned int beginStshInfo = OleUtil::getU4Bytes(headerBuffer, 0xa2); // address of STSH structure + std::size_t stshInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xa6); // length of STSH structure + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + char *buffer = new char[stshInfoLength]; + if (!tableStream.seek(beginStshInfo, true)) { + ZLLogger::Instance().println("DocPlugin", "problems with reading STSH structure"); + return false; + } + if (tableStream.read(buffer, stshInfoLength) != stshInfoLength) { + ZLLogger::Instance().println("DocPlugin", "problems with reading STSH structure, invalid length"); + return false; + } + + std::size_t stdCount = (std::size_t)OleUtil::getU2Bytes(buffer, 2); + std::size_t stdBaseInFile = (std::size_t)OleUtil::getU2Bytes(buffer, 4); + myStyleSheet.resize(stdCount); + + std::vector<bool> isFilled; + isFilled.resize(stdCount, false); + + std::size_t stdLen = 0; + bool styleSheetWasChanged = false; + do { //make it in while loop, because some base style can be after their successors + styleSheetWasChanged = false; + for (std::size_t index = 0, offset = 2 + (std::size_t)OleUtil::getU2Bytes(buffer, 0); index < stdCount; index++, offset += 2 + stdLen) { + stdLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset); + if (isFilled.at(index)) { + continue; + } + + if (stdLen == 0) { + //if record is empty, left it default + isFilled[index] = true; + continue; + } + + Style styleInfo = myStyleSheet.at(index); + + const unsigned int styleAndBaseType = OleUtil::getU2Bytes(buffer, offset + 4); + const unsigned int styleType = styleAndBaseType % 16; + const unsigned int baseStyleId = styleAndBaseType / 16; + if (baseStyleId == Style::STYLE_NIL || baseStyleId == Style::STYLE_USER) { + //if based on nil or user style, left default + } else { + int baseStyleIndex = getStyleIndex(baseStyleId, isFilled, myStyleSheet); + if (baseStyleIndex < 0) { + //this base style is not filled yet, so pass it at some time + continue; + } + styleInfo = myStyleSheet.at(baseStyleIndex); + styleInfo.StyleIdCurrent = Style::STYLE_INVALID; + } + + // parse STD structure + unsigned int tmp = OleUtil::getU2Bytes(buffer, offset + 6); + unsigned int upxCount = tmp % 16; + styleInfo.StyleIdNext = tmp / 16; + + //adding current style + myStyleSheet[index] = styleInfo; + isFilled[index] = true; + styleSheetWasChanged = true; + + std::size_t pos = 2 + stdBaseInFile; + std::size_t nameLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); + nameLen = nameLen * 2 + 2; //from Unicode characters to bytes + Unicode null charachter length + pos += 2 + nameLen; + if (pos % 2 != 0) { + ++pos; + } + if (pos >= stdLen) { + continue; + } + std::size_t upxLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); + if (pos + upxLen > stdLen) { + //UPX length too large + continue; + } + //for style info styleType must be equal 1 + if (styleType == 1 && upxCount >= 1) { + if (upxLen >= 2) { + styleInfo.StyleIdCurrent = OleUtil::getU2Bytes(buffer, offset + pos + 2); + getStyleInfo(0, buffer + offset + pos + 4, upxLen - 2, styleInfo); + myStyleSheet[index] = styleInfo; + } + pos += 2 + upxLen; + if (pos % 2 != 0) { + ++pos; + } + upxLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); + } + if (upxLen == 0 || pos + upxLen > stdLen) { + //too small/too large + continue; + } + //for char info styleType can be equal 1 or 2 + if ((styleType == 1 && upxCount >= 2) || (styleType == 2 && upxCount >= 1)) { + CharInfo charInfo; + getCharInfo(0, Style::STYLE_INVALID, buffer + offset + pos + 2, upxLen, charInfo); + styleInfo.CurrentCharInfo = charInfo; + myStyleSheet[index] = styleInfo; + } + } + } while (styleSheetWasChanged); + delete[] buffer; + return true; +} + +bool OleMainStream::readCharInfoTable(const char *headerBuffer, const OleEntry &tableEntry) { + //PlcfbteChpx structure is table with formatting for particular run of text + unsigned int beginCharInfo = OleUtil::getU4Bytes(headerBuffer, 0xfa); // address of PlcfbteChpx structure + std::size_t charInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xfe); // length of PlcfbteChpx structure + if (charInfoLength < 4) { + return false; + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginCharInfo, charInfoLength, tableStream)) { + return false; + } + + static const unsigned int CHPX_SIZE = 4; + std::size_t size = calcCountOfPLC(charInfoLength, CHPX_SIZE); + std::vector<unsigned int> charBlocks; + for (std::size_t index = 0, offset = (size + 1) * 4; index < size; ++index, offset += CHPX_SIZE) { + charBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); + } + + char *formatPageBuffer = new char[OleStorage::BBD_BLOCK_SIZE]; + for (std::size_t index = 0; index < charBlocks.size(); ++index) { + seek(charBlocks.at(index) * OleStorage::BBD_BLOCK_SIZE, true); + if (read(formatPageBuffer, OleStorage::BBD_BLOCK_SIZE) != OleStorage::BBD_BLOCK_SIZE) { + return false; + } + unsigned int crun = OleUtil::getU1Byte(formatPageBuffer, 0x1ff); //offset with crun (count of 'run of text') + for (unsigned int index2 = 0; index2 < crun; ++index2) { + unsigned int offset = OleUtil::getU4Bytes(formatPageBuffer, index2 * 4); + unsigned int chpxOffset = 2 * OleUtil::getU1Byte(formatPageBuffer, (crun + 1) * 4 + index2); + unsigned int len = OleUtil::getU1Byte(formatPageBuffer, chpxOffset); + unsigned int charPos = 0; + if (!offsetToCharPos(offset, charPos, myPieces)) { + continue; + } + unsigned int styleId = getStyleIdByCharPos(charPos, myStyleInfoList); + + CharInfo charInfo = getStyleFromStylesheet(styleId, myStyleSheet).CurrentCharInfo; + if (chpxOffset != 0) { + getCharInfo(chpxOffset, styleId, formatPageBuffer + 1, len - 1, charInfo); + } + myCharInfoList.push_back(CharPosToCharInfo(charPos, charInfo)); + + if (chpxOffset != 0) { + InlineImageInfo pictureInfo; + if (getInlineImageInfo(chpxOffset, formatPageBuffer + 1, len - 1, pictureInfo)) { + myInlineImageInfoList.push_back(CharPosToInlineImageInfo(charPos, pictureInfo)); + } + } + + } + } + delete[] formatPageBuffer; + return true; +} + +bool OleMainStream::readFloatingImages(const char *headerBuffer, const OleEntry &tableEntry) { + //Plcspa structure is a table with information for FSPA (File Shape Address) + unsigned int beginPicturesInfo = OleUtil::getU4Bytes(headerBuffer, 0x01DA); // address of Plcspa structure + if (beginPicturesInfo == 0) { + return true; //there's no office art objects + } + unsigned int picturesInfoLength = OleUtil::getU4Bytes(headerBuffer, 0x01DE); // length of Plcspa structure + if (picturesInfoLength < 4) { + return false; + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginPicturesInfo, picturesInfoLength, tableStream)) { + return false; + } + + static const unsigned int SPA_SIZE = 26; + std::size_t size = calcCountOfPLC(picturesInfoLength, SPA_SIZE); + + std::vector<unsigned int> picturesBlocks; + for (std::size_t index = 0, tOffset = 0; index < size; ++index, tOffset += 4) { + picturesBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); + } + + for (std::size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += SPA_SIZE) { + unsigned int spid = OleUtil::getU4Bytes(buffer.c_str(), tOffset); + FloatImageInfo info; + unsigned int charPos = picturesBlocks.at(index); + info.ShapeId = spid; + myFloatImageInfoList.push_back(CharPosToFloatImageInfo(charPos, info)); + } + + //DggInfo structure is office art object table data + unsigned int beginOfficeArtContent = OleUtil::getU4Bytes(headerBuffer, 0x22A); // address of DggInfo structure + if (beginOfficeArtContent == 0) { + return true; //there's no office art objects + } + unsigned int officeArtContentLength = OleUtil::getU4Bytes(headerBuffer, 0x022E); // length of DggInfo structure + if (officeArtContentLength < 4) { + return false; + } + + shared_ptr<OleStream> newTableStream = new OleStream(myStorage, tableEntry, myBaseStream); + shared_ptr<OleStream> newMainStream = new OleStream(myStorage, myOleEntry, myBaseStream); + if (newTableStream->open() && newMainStream->open()) { + myFLoatImageReader = new DocFloatImageReader(beginOfficeArtContent, officeArtContentLength, newTableStream, newMainStream); + myFLoatImageReader->readAll(); + } + return true; +} + +bool OleMainStream::readParagraphStyleTable(const char *headerBuffer, const OleEntry &tableEntry) { + //PlcBtePapx structure is table with formatting for all paragraphs + unsigned int beginParagraphInfo = OleUtil::getU4Bytes(headerBuffer, 0x102); // address of PlcBtePapx structure + std::size_t paragraphInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x106); // length of PlcBtePapx structure + if (paragraphInfoLength < 4) { + return false; + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginParagraphInfo, paragraphInfoLength, tableStream)) { + return false; + } + + static const unsigned int PAPX_SIZE = 4; + std::size_t size = calcCountOfPLC(paragraphInfoLength, PAPX_SIZE); + + std::vector<unsigned int> paragraphBlocks; + for (std::size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += PAPX_SIZE) { + paragraphBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); + } + + char *formatPageBuffer = new char[OleStorage::BBD_BLOCK_SIZE]; + for (std::size_t index = 0; index < paragraphBlocks.size(); ++index) { + seek(paragraphBlocks.at(index) * OleStorage::BBD_BLOCK_SIZE, true); + if (read(formatPageBuffer, OleStorage::BBD_BLOCK_SIZE) != OleStorage::BBD_BLOCK_SIZE) { + return false; + } + const unsigned int paragraphsCount = OleUtil::getU1Byte(formatPageBuffer, 0x1ff); //offset with 'cpara' value (count of paragraphs) + for (unsigned int index2 = 0; index2 < paragraphsCount; ++index2) { + const unsigned int offset = OleUtil::getU4Bytes(formatPageBuffer, index2 * 4); + unsigned int papxOffset = OleUtil::getU1Byte(formatPageBuffer, (paragraphsCount + 1) * 4 + index2 * 13) * 2; + if (papxOffset <= 0) { + continue; + } + unsigned int len = OleUtil::getU1Byte(formatPageBuffer, papxOffset) * 2; + if (len == 0) { + ++papxOffset; + len = OleUtil::getU1Byte(formatPageBuffer, papxOffset) * 2; + } + + const unsigned int styleId = OleUtil::getU2Bytes(formatPageBuffer, papxOffset + 1); + Style styleInfo = getStyleFromStylesheet(styleId, myStyleSheet); + + if (len >= 3) { + getStyleInfo(papxOffset, formatPageBuffer + 3, len - 3, styleInfo); + } + + unsigned int charPos = 0; + if (!offsetToCharPos(offset, charPos, myPieces)) { + continue; + } + myStyleInfoList.push_back(CharPosToStyle(charPos, styleInfo)); + } + } + delete[] formatPageBuffer; + return true; +} + +bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEntry &tableEntry) { + //PlcfSed structure is a section table + unsigned int beginOfText = OleUtil::getU4Bytes(headerBuffer, 0x18); //address of text's begin in main stream + unsigned int beginSectInfo = OleUtil::getU4Bytes(headerBuffer, 0xca); //address if PlcfSed structure + + std::size_t sectInfoLen = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xce); //length of PlcfSed structure + if (sectInfoLen < 4) { + return false; + } + + OleStream tableStream(myStorage, tableEntry, myBaseStream); + std::string buffer; + if (!readToBuffer(buffer, beginSectInfo, sectInfoLen, tableStream)) { + return false; + } + + static const unsigned int SED_SIZE = 12; + std::size_t decriptorsCount = calcCountOfPLC(sectInfoLen, SED_SIZE); + + //saving the section offsets (in character positions) + std::vector<unsigned int> charPos; + for (std::size_t index = 0, tOffset = 0; index < decriptorsCount; ++index, tOffset += 4) { + unsigned int ulTextOffset = OleUtil::getU4Bytes(buffer.c_str(), tOffset); + charPos.push_back(beginOfText + ulTextOffset); + } + + //saving sepx offsets + std::vector<unsigned int> sectPage; + for (std::size_t index = 0, tOffset = (decriptorsCount + 1) * 4; index < decriptorsCount; ++index, tOffset += SED_SIZE) { + sectPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset + 2)); + } + + //reading the section properties + char tmpBuffer[2]; + for (std::size_t index = 0; index < sectPage.size(); ++index) { + if (sectPage.at(index) == 0xffffffffUL) { //check for invalid record, to make default section info + SectionInfo sectionInfo; + sectionInfo.CharPosition = charPos.at(index); + mySectionInfoList.push_back(sectionInfo); + continue; + } + //getting number of bytes to read + if (!seek(sectPage.at(index), true)) { + continue; + } + if (read(tmpBuffer, 2) != 2) { + continue; + } + std::size_t bytes = 2 + (std::size_t)OleUtil::getU2Bytes(tmpBuffer, 0); + + if (!seek(sectPage.at(index), true)) { + continue; + } + char *formatPageBuffer = new char[bytes]; + if (read(formatPageBuffer, bytes) != bytes) { + delete[] formatPageBuffer; + continue; + } + SectionInfo sectionInfo; + sectionInfo.CharPosition = charPos.at(index); + getSectionInfo(formatPageBuffer + 2, bytes - 2, sectionInfo); + mySectionInfoList.push_back(sectionInfo); + delete[] formatPageBuffer; + } + return true; +} + +void OleMainStream::getStyleInfo(unsigned int papxOffset, const char *grpprlBuffer, unsigned int bytes, Style &styleInfo) { + int tmp, toDelete, toAdd; + unsigned int offset = 0; + while (bytes >= offset + 2) { + unsigned int curPrlLength = 0; + switch (OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset)) { + case 0x2403: + styleInfo.Alignment = (Style::AlignmentType)OleUtil::getU1Byte(grpprlBuffer, papxOffset + offset + 2); + break; + case 0x4610: + styleInfo.LeftIndent += OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + if (styleInfo.LeftIndent < 0) { + styleInfo.LeftIndent = 0; + } + break; + case 0xc60d: // ChgTabsPapx + case 0xc615: // ChgTabs + tmp = OleUtil::get1Byte(grpprlBuffer, papxOffset + offset + 2); + if (tmp < 2) { + curPrlLength = 1; + break; + } + toDelete = OleUtil::getU1Byte(grpprlBuffer, papxOffset + offset + 3); + if (tmp < 2 + 2 * toDelete) { + curPrlLength = 1; + break; + } + toAdd = OleUtil::getU1Byte(grpprlBuffer, papxOffset + offset + 4 + 2 * toDelete); + if (tmp < 2 + 2 * toDelete + 2 * toAdd) { + curPrlLength = 1; + break; + } + break; + case 0x840e: + styleInfo.RightIndent = (int)OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + break; + case 0x840f: + styleInfo.LeftIndent = (int)OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + break; + case 0x8411: + styleInfo.FirstLineIndent = (int)OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + break; + case 0xa413: + styleInfo.BeforeParagraphIndent = OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + break; + case 0xa414: + styleInfo.AfterParagraphIndent = OleUtil::getU2Bytes(grpprlBuffer, papxOffset + offset + 2); + break; + case 0x2407: + styleInfo.HasPageBreakBefore = OleUtil::getU1Byte(grpprlBuffer, papxOffset + offset + 2) == 0x01; + break; + default: + break; + } + if (curPrlLength == 0) { + curPrlLength = getPrlLength(grpprlBuffer, papxOffset + offset); + } + offset += curPrlLength; + } + +} + +void OleMainStream::getCharInfo(unsigned int chpxOffset, unsigned int /*styleId*/, const char *grpprlBuffer, unsigned int bytes, CharInfo &charInfo) { + unsigned int sprm = 0; //single propery modifier + unsigned int offset = 0; + while (bytes >= offset + 2) { + switch (OleUtil::getU2Bytes(grpprlBuffer, chpxOffset + offset)) { + case 0x0835: //bold + sprm = OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2); + switch (sprm) { + case UNSET: + charInfo.FontStyle &= ~CharInfo::FONT_BOLD; + break; + case SET: + charInfo.FontStyle |= CharInfo::FONT_BOLD; + break; + case UNCHANGED: + break; + case NEGATION: + charInfo.FontStyle ^= CharInfo::FONT_BOLD; + break; + default: + break; + } + break; + case 0x0836: //italic + sprm = OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2); + switch (sprm) { + case UNSET: + charInfo.FontStyle &= ~CharInfo::FONT_ITALIC; + break; + case SET: + charInfo.FontStyle |= CharInfo::FONT_ITALIC; + break; + case UNCHANGED: + break; + case NEGATION: + charInfo.FontStyle ^= CharInfo::FONT_ITALIC; + break; + default: + break; + } + break; + case 0x4a43: //size of font + charInfo.FontSize = OleUtil::getU2Bytes(grpprlBuffer, chpxOffset + offset + 2); + break; + default: + break; + } + offset += getPrlLength(grpprlBuffer, chpxOffset + offset); + } + +} + +void OleMainStream::getSectionInfo(const char *grpprlBuffer, std::size_t bytes, SectionInfo §ionInfo) { + unsigned int tmp; + std::size_t offset = 0; + while (bytes >= offset + 2) { + switch (OleUtil::getU2Bytes(grpprlBuffer, offset)) { + case 0x3009: //new page + tmp = OleUtil::getU1Byte(grpprlBuffer, offset + 2); + sectionInfo.IsNewPage = (tmp != 0 && tmp != 1); + break; + default: + break; + } + offset += getPrlLength(grpprlBuffer, offset); + } +} + +bool OleMainStream::getInlineImageInfo(unsigned int chpxOffset, const char *grpprlBuffer, unsigned int bytes, InlineImageInfo &pictureInfo) { + //p. 105 of [MS-DOC] documentation + unsigned int offset = 0; + bool isFound = false; + while (bytes >= offset + 2) { + switch (OleUtil::getU2Bytes(grpprlBuffer, chpxOffset + offset)) { + case 0x080a: // ole object, p.107 [MS-DOC] + if (OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2) == 0x01) { + return false; + } + break; + case 0x0806: // is not a picture, but a binary data? (sprmCFData, p.106 [MS-DOC]) + if (OleUtil::getU4Bytes(grpprlBuffer, chpxOffset + offset + 2) == 0x01) { + return false; + } + break; +// case 0x0855: // sprmCFSpec, p.117 [MS-DOC], MUST BE applied with a value of 1 (see p.105 [MS-DOC]) +// if (OleUtil::getU1Byte(grpprlBuffer, chpxOffset + offset + 2) != 0x01) { +// return false; +// } +// break; + case 0x6a03: // location p.105 [MS-DOC] + pictureInfo.DataPosition = OleUtil::getU4Bytes(grpprlBuffer, chpxOffset + offset + 2); + isFound = true; + break; + default: + break; + } + offset += getPrlLength(grpprlBuffer, chpxOffset + offset); + } + return isFound; +} + +OleMainStream::Style OleMainStream::getStyleFromStylesheet(unsigned int styleId, const StyleSheet &stylesheet) { + //TODO optimize it: StyleSheet can be map structure with styleId key + Style style; + if (styleId != Style::STYLE_INVALID && styleId != Style::STYLE_NIL && styleId != Style::STYLE_USER) { + for (std::size_t index = 0; index < stylesheet.size(); ++index) { + if (stylesheet.at(index).StyleIdCurrent == styleId) { + return stylesheet.at(index); + } + } + } + style.StyleIdCurrent = styleId; + return style; +} + +int OleMainStream::getStyleIndex(unsigned int styleId, const std::vector<bool> &isFilled, const StyleSheet &stylesheet) { + //TODO optimize it: StyleSheet can be map structure with styleId key + //in that case, this method will be excess + if (styleId == Style::STYLE_INVALID) { + return -1; + } + for (int index = 0; index < (int)stylesheet.size(); ++index) { + if (isFilled.at(index) && stylesheet.at(index).StyleIdCurrent == styleId) { + return index; + } + } + return -1; +} + +unsigned int OleMainStream::getStyleIdByCharPos(unsigned int charPos, const StyleInfoList &styleInfoList) { + unsigned int styleId = Style::STYLE_INVALID; + for (std::size_t i = 0; i < styleInfoList.size(); ++i) { + const Style &info = styleInfoList.at(i).second; + if (i == styleInfoList.size() - 1) { //if last + styleId = info.StyleIdCurrent; + break; + } + unsigned int curOffset = styleInfoList.at(i).first; + unsigned int nextOffset = styleInfoList.at(i + 1).first; + if (charPos >= curOffset && charPos < nextOffset) { + styleId = info.StyleIdCurrent; + break; + } + } + return styleId; +} + +bool OleMainStream::offsetToCharPos(unsigned int offset, unsigned int &charPos, const Pieces &pieces) { + if (pieces.empty()) { + return false; + } + if ((unsigned int)pieces.front().Offset > offset) { + charPos = 0; + return true; + } + if ((unsigned int)(pieces.back().Offset + pieces.back().Length) <= offset) { + return false; + } + + std::size_t pieceNumber = 0; + for (std::size_t i = 0; i < pieces.size(); ++i) { + if (i == pieces.size() - 1) { //if last + pieceNumber = i; + break; + } + unsigned int curOffset = pieces.at(i).Offset; + unsigned int nextOffset = pieces.at(i + 1).Offset; + if (offset >= curOffset && offset < nextOffset) { + pieceNumber = i; + break; + } + } + + const Piece &piece = pieces.at(pieceNumber); + unsigned int diffOffset = offset - piece.Offset; + if (!piece.IsANSI) { + diffOffset /= 2; + } + charPos = piece.startCP + diffOffset; + return true; +} + +bool OleMainStream::readToBuffer(std::string &result, unsigned int offset, std::size_t length, OleStream &stream) { + char *buffer = new char[length]; + stream.seek(offset, true); + if (stream.read(buffer, length) != length) { + return false; + } + result = std::string(buffer, length); + delete[] buffer; + return true; +} + +unsigned int OleMainStream::calcCountOfPLC(unsigned int totalSize, unsigned int elementSize) { + //calculates count of elements in PLC structure, formula from p.30 [MS-DOC] + return (totalSize - 4) / (4 + elementSize); +} + +unsigned int OleMainStream::getPrlLength(const char *grpprlBuffer, unsigned int byteNumber) { + unsigned int tmp; + unsigned int opCode = OleUtil::getU2Bytes(grpprlBuffer, byteNumber); + switch (opCode & 0xe000) { + case 0x0000: + case 0x2000: + return 3; + case 0x4000: + case 0x8000: + case 0xA000: + return 4; + case 0xE000: + return 5; + case 0x6000: + return 6; + case 0xC000: + //counting of info length + tmp = OleUtil::getU1Byte(grpprlBuffer, byteNumber + 2); + if (opCode == 0xc615 && tmp == 255) { + unsigned int del = OleUtil::getU1Byte(grpprlBuffer, byteNumber + 3); + unsigned int add = OleUtil::getU1Byte(grpprlBuffer, byteNumber + 4 + del * 4); + tmp = 2 + del * 4 + add * 3; + } + return 3 + tmp; + default: + return 1; + } +} diff --git a/reader/src/formats/doc/OleMainStream.h b/reader/src/formats/doc/OleMainStream.h new file mode 100644 index 0000000..378f037 --- /dev/null +++ b/reader/src/formats/doc/OleMainStream.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLEMAINSTREAM_H__ +#define __OLEMAINSTREAM_H__ + +#include <vector> +#include <string> + +#include "OleStream.h" +#include "DocFloatImageReader.h" + +class OleMainStream : public OleStream { + +public: + struct Piece { + enum PieceType { + PIECE_TEXT, + PIECE_FOOTNOTE, + PIECE_OTHER + }; + + int Offset; // TODO: maybe make it unsigned int + int Length; // TODO: maybe make it unsigned int + bool IsANSI; + PieceType Type; + unsigned int startCP; + }; + typedef std::vector<Piece> Pieces; + + struct CharInfo { + enum Font { + FONT_REGULAR = 0, + FONT_BOLD = 1 << 0, + FONT_ITALIC = 1 << 1, + FONT_UNDERLINE = 1 << 2, + FONT_CAPITALS = 1 << 3, + FONT_SMALL_CAPS = 1 << 4, + FONT_STRIKE = 1 << 5, + FONT_HIDDEN = 1 << 6, + FONT_MARKDEL = 1 << 7, + FONT_SUPERSCRIPT = 1 << 8, + FONT_SUBSCRIPT = 1 << 9 + }; + + unsigned int FontStyle; + unsigned int FontSize; + + CharInfo(); + }; + typedef std::pair<unsigned int, CharInfo> CharPosToCharInfo; + typedef std::vector<CharPosToCharInfo > CharInfoList; + + struct Style { + enum AlignmentType { + ALIGNMENT_LEFT = 0x00, + ALIGNMENT_CENTER = 0x01, + ALIGNMENT_RIGHT = 0x02, + ALIGNMENT_JUSTIFY = 0x03, + ALIGNMENT_DEFAULT // for case if alignment is not setted by word + }; + + // style Ids: + // (this is not full list of possible style ids, enum is used for using in switch-case) + enum StyleID { + STYLE_H1 = 0x1, + STYLE_H2 = 0x2, + STYLE_H3 = 0x3, + STYLE_USER = 0xFFE, + STYLE_NIL = 0xFFF, + STYLE_INVALID = 0xFFFF + }; + + unsigned int StyleIdCurrent; + unsigned int StyleIdNext; // Next style unless overruled + + bool HasPageBreakBefore; + unsigned int BeforeParagraphIndent; // Vertical indent before paragraph, pixels + unsigned int AfterParagraphIndent; // Vertical indent after paragraph, pixels + int LeftIndent; + int FirstLineIndent; + int RightIndent; + AlignmentType Alignment; + CharInfo CurrentCharInfo; + + Style(); + }; + + typedef std::pair<unsigned int, Style> CharPosToStyle; + typedef std::vector<CharPosToStyle> StyleInfoList; + typedef std::vector<Style> StyleSheet; + + struct SectionInfo { + unsigned int CharPosition; + bool IsNewPage; + + SectionInfo(); + }; + typedef std::vector<SectionInfo> SectionInfoList; + + struct Bookmark { + unsigned int CharPosition; + std::string Name; + }; + typedef std::vector<Bookmark> BookmarksList; + + struct InlineImageInfo { + unsigned int DataPosition; + + InlineImageInfo(); + }; + typedef std::pair<unsigned int, InlineImageInfo> CharPosToInlineImageInfo; + typedef std::vector<CharPosToInlineImageInfo> InlineImageInfoList; + + struct FloatImageInfo { + unsigned int ShapeId; + FloatImageInfo(); + }; + typedef std::pair<unsigned int, FloatImageInfo> CharPosToFloatImageInfo; + typedef std::vector<CharPosToFloatImageInfo> FloatImageInfoList; + + enum ImageType { //see p. 60 [MS-ODRAW] + IMAGE_EMF = 0xF01A, + IMAGE_WMF = 0xF01B, + IMAGE_PICT = 0xF01C, + IMAGE_JPEG = 0xF01D, + IMAGE_PNG = 0xF01E, + IMAGE_DIB = 0xF01F, + IMAGE_TIFF = 0xF029, + IMAGE_JPEG2 = 0xF02A + }; + +public: + OleMainStream(shared_ptr<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> stream); + +public: + bool open(bool doReadFormattingData); + const Pieces &getPieces() const; + const CharInfoList &getCharInfoList() const; + const StyleInfoList &getStyleInfoList() const; + const BookmarksList &getBookmarks() const; + const InlineImageInfoList &getInlineImageInfoList() const; + const FloatImageInfoList &getFloatImageInfoList() const; + + ZLFileImage::Blocks getFloatImage(unsigned int shapeId) const; + ZLFileImage::Blocks getInlineImage(unsigned int dataPos) const; + +private: + bool readFIB(const char *headerBuffer); + bool readPieceTable(const char *headerBuffer, const OleEntry &tableEntry); + bool readBookmarks(const char *headerBuffer, const OleEntry &tableEntry); + bool readStylesheet(const char *headerBuffer, const OleEntry &tableEntry); + bool readSectionsInfoTable(const char *headerBuffer, const OleEntry &tableEntry); + bool readParagraphStyleTable(const char *headerBuffer, const OleEntry &tableEntry); + bool readCharInfoTable(const char *headerBuffer, const OleEntry &tableEntry); + bool readFloatingImages(const char *headerBuffer, const OleEntry &tableEntry); + +private: //readPieceTable helpers methods + static std::string getPiecesTableBuffer(const char *headerBuffer, OleStream &tableStream); + static void splitPieces(const Pieces &source, Pieces &dest1, Pieces &dest2, Piece::PieceType type1, Piece::PieceType type2, int boundary); + +private: //formatting reader helpers methods + static unsigned int getPrlLength(const char *grpprlBuffer, unsigned int byteNumber); + static void getCharInfo(unsigned int chpxOffset, unsigned int styleId, const char *grpprlBuffer, unsigned int bytes, CharInfo &charInfo); + static void getStyleInfo(unsigned int papxOffset, const char *grpprlBuffer, unsigned int bytes, Style &styleInfo); + static void getSectionInfo(const char *grpprlBuffer, std::size_t bytes, SectionInfo §ionInfo); + static bool getInlineImageInfo(unsigned int chpxOffset, const char *grpprlBuffer, unsigned int bytes, InlineImageInfo &pictureInfo); + + static Style getStyleFromStylesheet(unsigned int styleId, const StyleSheet &stylesheet); + static int getStyleIndex(unsigned int styleId, const std::vector<bool> &isFilled, const StyleSheet &stylesheet); + static unsigned int getStyleIdByCharPos(unsigned int offset, const StyleInfoList &styleInfoList); + + static bool offsetToCharPos(unsigned int offset, unsigned int &charPos, const Pieces &pieces); + static bool readToBuffer(std::string &result, unsigned int offset, std::size_t length, OleStream &stream); + + static unsigned int calcCountOfPLC(unsigned int totalSize, unsigned int elementSize); + +private: + enum PrlFlag { + UNSET = 0, + SET = 1, + UNCHANGED = 128, + NEGATION = 129 + }; + +private: + int myStartOfText; + int myEndOfText; + + Pieces myPieces; + + StyleSheet myStyleSheet; + + CharInfoList myCharInfoList; + StyleInfoList myStyleInfoList; + SectionInfoList mySectionInfoList; + InlineImageInfoList myInlineImageInfoList; + FloatImageInfoList myFloatImageInfoList; + + BookmarksList myBookmarks; + + shared_ptr<OleStream> myDataStream; + + shared_ptr<DocFloatImageReader> myFLoatImageReader; +}; + +#endif /* __OLEMAINSTREAM_H__ */ diff --git a/reader/src/formats/doc/OleStorage.cpp b/reader/src/formats/doc/OleStorage.cpp new file mode 100644 index 0000000..a7ab81a --- /dev/null +++ b/reader/src/formats/doc/OleStorage.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLLogger.h> + +#include "OleStorage.h" +#include "OleUtil.h" + +#include <cstring> + +const std::size_t OleStorage::BBD_BLOCK_SIZE = 512; + +OleStorage::OleStorage() { + clear(); +} + +void OleStorage::clear() { + myInputStream = 0; + mySectorSize = 0; + myShortSectorSize = 0; + myStreamSize = 0; + myRootEntryIndex = -1; + + myDIFAT.clear(); + myBBD.clear(); + mySBD.clear(); + myProperties.clear(); + myEntries.clear(); +} + + + +bool OleStorage::init(shared_ptr<ZLInputStream> stream, std::size_t streamSize) { + clear(); + + myInputStream = stream; + myStreamSize = streamSize; + myInputStream->seek(0, true); + + char oleBuf[BBD_BLOCK_SIZE]; + std::size_t ret = myInputStream->read(oleBuf, BBD_BLOCK_SIZE); + if (ret != BBD_BLOCK_SIZE) { + clear(); + return false; + } + static const char OLE_SIGN[] = {(char)0xD0, (char)0xCF, (char)0x11, (char)0xE0, (char)0xA1, (char)0xB1, (char)0x1A, (char)0xE1, 0}; + if (std::strncmp(oleBuf, OLE_SIGN, 8) != 0) { + clear(); + return false; + } + mySectorSize = 1 << OleUtil::getU2Bytes(oleBuf, 0x1e); //offset for value of big sector size + myShortSectorSize = 1 << OleUtil::getU2Bytes(oleBuf, 0x20); //offset for value of small sector size + + if (readDIFAT(oleBuf) && readBBD(oleBuf) && readSBD(oleBuf) && readProperties(oleBuf) && readAllEntries()) { + return true; + } + clear(); + return false; +} + +bool OleStorage::readDIFAT(char *oleBuf) { + int difatBlock = OleUtil::get4Bytes(oleBuf, 0x44); //address for first difat sector + int difatSectorNumbers = OleUtil::get4Bytes(oleBuf, 0x48); //numbers of additional difat records + + //436 of difat records are stored in header, by offset 0x4c + for (unsigned int i = 0; i < 436; i += 4) { + myDIFAT.push_back(OleUtil::get4Bytes(oleBuf + 0x4c, i)); + } + + //for files > 6.78 mb we need read additional DIFAT fields + for (int i = 0; difatBlock > 0 && i < difatSectorNumbers; ++i) { + ZLLogger::Instance().println("DocPlugin", "Read additional data for DIFAT"); + char buffer[mySectorSize]; + myInputStream->seek(BBD_BLOCK_SIZE + difatBlock * mySectorSize, true); + if (myInputStream->read(buffer, mySectorSize) != mySectorSize) { + ZLLogger::Instance().println("DocPlugin", "Error read DIFAT!"); + return false; + } + for (unsigned int j = 0; j < (mySectorSize - 4); j += 4) { + myDIFAT.push_back(OleUtil::get4Bytes(buffer, j)); + } + difatBlock = OleUtil::get4Bytes(buffer, mySectorSize - 4); //next DIFAT block is pointed at the end of the sector + } + + //removing unusable DIFAT links + //0xFFFFFFFF means "free section" + while (!myDIFAT.empty() && myDIFAT.back() == (int)0xFFFFFFFF) { + myDIFAT.pop_back(); + } + return true; +} + +bool OleStorage::readBBD(char *oleBuf) { + char buffer[mySectorSize]; + unsigned int bbdNumberBlocks = OleUtil::getU4Bytes(oleBuf, 0x2c); //number of big blocks + + if (myDIFAT.size() < bbdNumberBlocks) { + //TODO maybe add check on myDIFAT == bbdNumberBlocks + ZLLogger::Instance().println("DocPlugin", "Wrong number of FAT blocks value"); + return false; + } + + for (unsigned int i = 0; i < bbdNumberBlocks; ++i) { + int bbdSector = myDIFAT.at(i); + if (bbdSector >= (int)(myStreamSize / mySectorSize) || bbdSector < 0) { + ZLLogger::Instance().println("DocPlugin", "Bad BBD entry!"); + return false; + } + myInputStream->seek(BBD_BLOCK_SIZE + bbdSector * mySectorSize, true); + if (myInputStream->read(buffer, mySectorSize) != mySectorSize) { + ZLLogger::Instance().println("DocPlugin", "Error during reading BBD!"); + return false; + } + for (unsigned int j = 0; j < mySectorSize; j += 4) { + myBBD.push_back(OleUtil::get4Bytes(buffer, j)); + } + } + return true; +} + +bool OleStorage::readSBD(char *oleBuf) { + int sbdCur = OleUtil::get4Bytes(oleBuf, 0x3c); //address of first small sector + int sbdCount = OleUtil::get4Bytes(oleBuf, 0x40); //count of small sectors + + if (sbdCur <= 0) { + ZLLogger::Instance().println("DocPlugin", "There's no SBD, don't read it"); + return true; + } + + char buffer[mySectorSize]; + for (int i = 0; i < sbdCount; ++i) { + if (i != 0) { + if (sbdCur < 0 || (unsigned int)sbdCur >= myBBD.size()) { + ZLLogger::Instance().println("DocPlugin", "error during parsing SBD"); + return false; + } + sbdCur = myBBD.at(sbdCur); + } + if (sbdCur <= 0) { + break; + } + myInputStream->seek(BBD_BLOCK_SIZE + sbdCur * mySectorSize, true); + if (myInputStream->read(buffer, mySectorSize) != mySectorSize) { + ZLLogger::Instance().println("DocPlugin", "reading error during parsing SBD"); + return false; + } + for (unsigned int j = 0; j < mySectorSize; j += 4) { + mySBD.push_back(OleUtil::get4Bytes(buffer, j)); + } + + } + return true; +} + +bool OleStorage::readProperties(char *oleBuf) { + int propCur = OleUtil::get4Bytes(oleBuf, 0x30); //offset for address of sector with first property + if (propCur < 0) { + ZLLogger::Instance().println("DocPlugin", "Wrong first directory sector location"); + return false; + } + + char buffer[mySectorSize]; + do { + myInputStream->seek(BBD_BLOCK_SIZE + propCur * mySectorSize, true); + if (myInputStream->read(buffer, mySectorSize) != mySectorSize) { + ZLLogger::Instance().println("DocPlugin", "Error during reading properties"); + return false; + } + for (unsigned int j = 0; j < mySectorSize; j += 128) { + myProperties.push_back(std::string(buffer + j, 128)); + } + if (propCur < 0 || (std::size_t)propCur >= myBBD.size()) { + break; + } + propCur = myBBD.at(propCur); + } while (propCur >= 0 && propCur < (int)(myStreamSize / mySectorSize)); + return true; +} + +bool OleStorage::readAllEntries() { + int propCount = myProperties.size(); + for (int i = 0; i < propCount; ++i) { + OleEntry entry; + bool result = readOleEntry(i, entry); + if (!result) { + break; + } + if (entry.type == OleEntry::ROOT_DIR) { + myRootEntryIndex = i; + } + myEntries.push_back(entry); + } + if (myRootEntryIndex < 0) { + return false; + } + return true; +} + +bool OleStorage::readOleEntry(int propNumber, OleEntry &e) { + static const std::string ROOT_ENTRY = "Root Entry"; + + std::string property = myProperties.at(propNumber); + + char oleType = property.at(0x42); //offset for Ole Type + if (oleType != 1 && oleType != 2 && oleType != 3 && oleType != 5) { + ZLLogger::Instance().println("DocPlugin", "entry -- not right ole type"); + return false; + } + + e.type = (OleEntry::Type)oleType; + + int nameLength = OleUtil::getU2Bytes(property.c_str(), 0x40); //offset for value entry's name length + e.name.clear(); + e.name.reserve(33); //max size of entry name + + if ((unsigned int)nameLength >= property.size()) { + return false; + } + for (int i = 0; i < nameLength; i+=2) { + char c = property.at(i); + if (c != 0) { + e.name += c; + } + } + + e.length = OleUtil::getU4Bytes(property.c_str(), 0x78); //offset for entry's length value + e.isBigBlock = e.length >= 0x1000 || e.name == ROOT_ENTRY; + + // Read sector chain + if (property.size() < 0x74 + 4) { + ZLLogger::Instance().println("DocPlugin", "problems with reading ole entry"); + return false; + } + int chainCur = OleUtil::get4Bytes(property.c_str(), 0x74); //offset for start block of entry + if (chainCur >= 0 && (chainCur <= (int)(myStreamSize / (e.isBigBlock ? mySectorSize : myShortSectorSize)))) { + //filling blocks with chains + do { + e.blocks.push_back((unsigned int)chainCur); + if (e.isBigBlock && (std::size_t)chainCur < myBBD.size()) { + chainCur = myBBD.at(chainCur); + } else if (!mySBD.empty() && (std::size_t)chainCur < mySBD.size()) { + chainCur = mySBD.at(chainCur); + } else { + chainCur = -1; + } + } while (chainCur > 0 && + chainCur < (int)(e.isBigBlock ? myBBD.size() : mySBD.size()) && + e.blocks.size() <= e.length / (e.isBigBlock ? mySectorSize : myShortSectorSize)); + } + e.length = std::min(e.length, (unsigned int)((e.isBigBlock ? mySectorSize : myShortSectorSize) * e.blocks.size())); + return true; +} + +bool OleStorage::countFileOffsetOfBlock(const OleEntry &e, unsigned int blockNumber, unsigned int &result) const { + //TODO maybe better syntax can be used? + if (e.blocks.size() <= (std::size_t)blockNumber) { + ZLLogger::Instance().println("DocPlugin", "countFileOffsetOfBlock can't be done, blockNumber is invalid"); + return false; + } + if (e.isBigBlock) { + result = BBD_BLOCK_SIZE + e.blocks.at(blockNumber) * mySectorSize; + } else { + unsigned int sbdPerSector = mySectorSize / myShortSectorSize; + unsigned int sbdSectorNumber = e.blocks.at(blockNumber) / sbdPerSector; + unsigned int sbdSectorMod = e.blocks.at(blockNumber) % sbdPerSector; + if (myEntries.at(myRootEntryIndex).blocks.size() <= (std::size_t)sbdSectorNumber) { + ZLLogger::Instance().println("DocPlugin", "countFileOffsetOfBlock can't be done, invalid sbd data"); + return false; + } + result = BBD_BLOCK_SIZE + myEntries.at(myRootEntryIndex).blocks.at(sbdSectorNumber) * mySectorSize + sbdSectorMod * myShortSectorSize; + } + return true; +} + +bool OleStorage::getEntryByName(std::string name, OleEntry &returnEntry) const { + //TODO fix the workaround for duplicates streams: now it takes a stream with max length + unsigned int maxLength = 0; + for (std::size_t i = 0; i < myEntries.size(); ++i) { + const OleEntry &entry = myEntries.at(i); + if (entry.name == name && entry.length >= maxLength) { + returnEntry = entry; + maxLength = entry.length; + } + } + return maxLength > 0; +} + + diff --git a/reader/src/formats/doc/OleStorage.h b/reader/src/formats/doc/OleStorage.h new file mode 100644 index 0000000..584ee94 --- /dev/null +++ b/reader/src/formats/doc/OleStorage.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLESTORAGE_H__ +#define __OLESTORAGE_H__ + +#include <algorithm> +#include <vector> +#include <string> + +#include <ZLInputStream.h> + +struct OleEntry { + enum Type { + DIR = 1, + STREAM = 2, + ROOT_DIR = 5, + LOCK_BYTES =3 + }; + + typedef std::vector<unsigned int> Blocks; + + std::string name; + unsigned int length; + Type type; + Blocks blocks; + bool isBigBlock; +}; + +class OleStorage { + +public: + static const std::size_t BBD_BLOCK_SIZE; + +public: + OleStorage(); + bool init(shared_ptr<ZLInputStream>, std::size_t streamSize); + void clear(); + const std::vector<OleEntry> &getEntries() const; + bool getEntryByName(std::string name, OleEntry &entry) const; + + unsigned int getSectorSize() const; + unsigned int getShortSectorSize() const; + +public: //TODO make private + bool countFileOffsetOfBlock(const OleEntry &e, unsigned int blockNumber, unsigned int &result) const; + +private: + bool readDIFAT(char *oleBuf); + bool readBBD(char *oleBuf); + bool readSBD(char *oleBuf); + bool readProperties(char *oleBuf); + + bool readAllEntries(); + bool readOleEntry(int propNumber, OleEntry &entry); + +private: + + shared_ptr<ZLInputStream> myInputStream; + unsigned int mySectorSize, myShortSectorSize; + + std::size_t myStreamSize; + std::vector<int> myDIFAT; //double-indirect file allocation table + std::vector<int> myBBD; //Big Block Depot + std::vector<int> mySBD; //Small Block Depot + std::vector<std::string> myProperties; + std::vector<OleEntry> myEntries; + int myRootEntryIndex; + +}; + +inline const std::vector<OleEntry> &OleStorage::getEntries() const { return myEntries; } +inline unsigned int OleStorage::getSectorSize() const { return mySectorSize; } +inline unsigned int OleStorage::getShortSectorSize() const { return myShortSectorSize; } + +#endif /* __OLESTORAGE_H__ */ diff --git a/reader/src/formats/doc/OleStream.cpp b/reader/src/formats/doc/OleStream.cpp new file mode 100644 index 0000000..8de1cc4 --- /dev/null +++ b/reader/src/formats/doc/OleStream.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLLogger.h> + +#include "OleStream.h" +#include "OleUtil.h" + +OleStream::OleStream(shared_ptr<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> stream) : + myStorage(storage), + myOleEntry(oleEntry), + myBaseStream(stream) { + myOleOffset = 0; +} + + +bool OleStream::open() { + if (myOleEntry.type != OleEntry::STREAM) { + return false; + } + return true; +} + +std::size_t OleStream::read(char *buffer, std::size_t maxSize) { + std::size_t length = maxSize; + std::size_t readedBytes = 0; + std::size_t bytesLeftInCurBlock; + unsigned int newFileOffset; + + unsigned int curBlockNumber, modBlock; + std::size_t toReadBlocks, toReadBytes; + + if (myOleOffset + length > myOleEntry.length) { + length = myOleEntry.length - myOleOffset; + } + + std::size_t sectorSize = (std::size_t)(myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + + curBlockNumber = myOleOffset / sectorSize; + if (curBlockNumber >= myOleEntry.blocks.size()) { + return 0; + } + modBlock = myOleOffset % sectorSize; + bytesLeftInCurBlock = sectorSize - modBlock; + if (bytesLeftInCurBlock < length) { + toReadBlocks = (length - bytesLeftInCurBlock) / sectorSize; + toReadBytes = (length - bytesLeftInCurBlock) % sectorSize; + } else { + toReadBlocks = toReadBytes = 0; + } + + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, newFileOffset)) { + return 0; + } + newFileOffset += modBlock; + + myBaseStream->seek(newFileOffset, true); + + readedBytes = myBaseStream->read(buffer, std::min(length, bytesLeftInCurBlock)); + for (std::size_t i = 0; i < toReadBlocks; ++i) { + if (++curBlockNumber >= myOleEntry.blocks.size()) { + break; + } + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, newFileOffset)) { + return readedBytes; + } + myBaseStream->seek(newFileOffset, true); + readedBytes += myBaseStream->read(buffer + readedBytes, std::min(length - readedBytes, sectorSize)); + } + if (toReadBytes > 0 && ++curBlockNumber < myOleEntry.blocks.size()) { + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, newFileOffset)) { + return readedBytes; + } + myBaseStream->seek(newFileOffset, true); + readedBytes += myBaseStream->read(buffer + readedBytes, toReadBytes); + } + myOleOffset += readedBytes; + return readedBytes; +} + +bool OleStream::eof() const { + return (myOleOffset >= myOleEntry.length); +} + + +void OleStream::close() { +} + +bool OleStream::seek(unsigned int offset, bool absoluteOffset) { + unsigned int newOleOffset = 0; + unsigned int newFileOffset; + + if (absoluteOffset) { + newOleOffset = offset; + } else { + newOleOffset = myOleOffset + offset; + } + + newOleOffset = std::min(newOleOffset, myOleEntry.length); + + unsigned int sectorSize = (myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + unsigned int blockNumber = newOleOffset / sectorSize; + if (blockNumber >= myOleEntry.blocks.size()) { + return false; + } + + unsigned int modBlock = newOleOffset % sectorSize; + if (!myStorage->countFileOffsetOfBlock(myOleEntry, blockNumber, newFileOffset)) { + return false; + } + newFileOffset += modBlock; + myBaseStream->seek(newFileOffset, true); + myOleOffset = newOleOffset; + return true; +} + +std::size_t OleStream::offset() { + return myOleOffset; +} + +ZLFileImage::Blocks OleStream::getBlockPieceInfoList(unsigned int offset, unsigned int size) const { + ZLFileImage::Blocks list; + unsigned int sectorSize = (myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + unsigned int curBlockNumber = offset / sectorSize; + if (curBlockNumber >= myOleEntry.blocks.size()) { + return list; + } + unsigned int modBlock = offset % sectorSize; + unsigned int startFileOffset = 0; + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, startFileOffset)) { + return ZLFileImage::Blocks(); + } + startFileOffset += modBlock; + + unsigned int bytesLeftInCurBlock = sectorSize - modBlock; + unsigned int toReadBlocks = 0, toReadBytes = 0; + if (bytesLeftInCurBlock < size) { + toReadBlocks = (size - bytesLeftInCurBlock) / sectorSize; + toReadBytes = (size - bytesLeftInCurBlock) % sectorSize; + } + + unsigned int readedBytes = std::min(size, bytesLeftInCurBlock); + list.push_back(ZLFileImage::Block(startFileOffset, readedBytes)); + + for (unsigned int i = 0; i < toReadBlocks; ++i) { + if (++curBlockNumber >= myOleEntry.blocks.size()) { + break; + } + unsigned int newFileOffset = 0; + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, newFileOffset)) { + return ZLFileImage::Blocks(); + } + unsigned int readbytes = std::min(size - readedBytes, sectorSize); + list.push_back(ZLFileImage::Block(newFileOffset, readbytes)); + readedBytes += readbytes; + } + if (toReadBytes > 0 && ++curBlockNumber < myOleEntry.blocks.size()) { + unsigned int newFileOffset = 0; + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, newFileOffset)) { + return ZLFileImage::Blocks(); + } + unsigned int readbytes = toReadBytes; + list.push_back(ZLFileImage::Block(newFileOffset, readbytes)); + readedBytes += readbytes; + } + + return concatBlocks(list); +} + +ZLFileImage::Blocks OleStream::concatBlocks(const ZLFileImage::Blocks &blocks) { + if (blocks.size() < 2) { + return blocks; + } + ZLFileImage::Blocks optList; + ZLFileImage::Block curBlock = blocks.at(0); + unsigned int nextOffset = curBlock.offset + curBlock.size; + for (std::size_t i = 1; i < blocks.size(); ++i) { + ZLFileImage::Block b = blocks.at(i); + if (b.offset == nextOffset) { + curBlock.size += b.size; + nextOffset += b.size; + } else { + optList.push_back(curBlock); + curBlock = b; + nextOffset = curBlock.offset + curBlock.size; + } + } + optList.push_back(curBlock); + return optList; +} + +std::size_t OleStream::fileOffset() { + //TODO maybe remove this method, it doesn't use at this time + std::size_t sectorSize = (std::size_t)(myOleEntry.isBigBlock ? myStorage->getSectorSize() : myStorage->getShortSectorSize()); + unsigned int curBlockNumber = myOleOffset / sectorSize; + if (curBlockNumber >= myOleEntry.blocks.size()) { + return 0; + } + unsigned int modBlock = myOleOffset % sectorSize; + unsigned int curOffset = 0; + if (!myStorage->countFileOffsetOfBlock(myOleEntry, curBlockNumber, curOffset)) { + return 0; //TODO maybe remove -1? + } + return curOffset + modBlock; +} diff --git a/reader/src/formats/doc/OleStream.h b/reader/src/formats/doc/OleStream.h new file mode 100644 index 0000000..861c7cb --- /dev/null +++ b/reader/src/formats/doc/OleStream.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLESTREAM_H__ +#define __OLESTREAM_H__ + +#include <ZLFileImage.h> + +#include "OleStorage.h" + +class OleStream { + +public: + OleStream(shared_ptr<OleStorage> storage, OleEntry oleEntry, shared_ptr<ZLInputStream> stream); + +public: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + +public: + bool seek(unsigned int offset, bool absoluteOffset); + std::size_t offset(); + +public: + ZLFileImage::Blocks getBlockPieceInfoList(unsigned int offset, unsigned int size) const; + static ZLFileImage::Blocks concatBlocks(const ZLFileImage::Blocks &blocks); + std::size_t fileOffset(); + +public: + bool eof() const; + +protected: + shared_ptr<OleStorage> myStorage; + + OleEntry myOleEntry; + shared_ptr<ZLInputStream> myBaseStream; + + unsigned int myOleOffset; +}; + +#endif /* __OLESTREAM_H__ */ diff --git a/reader/src/formats/doc/OleStreamParser.cpp b/reader/src/formats/doc/OleStreamParser.cpp new file mode 100644 index 0000000..0a9c62d --- /dev/null +++ b/reader/src/formats/doc/OleStreamParser.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +//#include <cctype> +//#include <cstring> + +#include <ZLLogger.h> + +#include "OleMainStream.h" +#include "OleUtil.h" +#include "OleStreamParser.h" + +//word's control chars: +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_FOOTNOTE_MARK = 0x0002; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_TABLE_SEPARATOR = 0x0007; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_HORIZONTAL_TAB = 0x0009; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_HARD_LINEBREAK = 0x000b; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_PAGE_BREAK = 0x000c; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_END_OF_PARAGRAPH = 0x000d; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_MINUS = 0x001e; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_SOFT_HYPHEN = 0x001f; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_START_FIELD = 0x0013; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_SEPARATOR_FIELD = 0x0014; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_END_FIELD = 0x0015; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::WORD_ZERO_WIDTH_UNBREAKABLE_SPACE = 0xfeff; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::INLINE_IMAGE = 0x0001; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::FLOAT_IMAGE = 0x0008; + +//unicode values: +const ZLUnicodeUtil::Ucs2Char OleStreamParser::NULL_SYMBOL = 0x0; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::FILE_SEPARATOR = 0x1c; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::LINE_FEED = 0x000a; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::SOFT_HYPHEN = 0xad; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::SPACE = 0x20; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::MINUS = 0x2D; +const ZLUnicodeUtil::Ucs2Char OleStreamParser::VERTICAL_LINE = 0x7C; + +OleStreamParser::OleStreamParser() { + myCurBufferPosition = 0; + + myCurCharPos = 0; + myNextStyleInfoIndex = 0; + myNextCharInfoIndex = 0; + myNextBookmarkIndex = 0; + myNextInlineImageInfoIndex = 0; + myNextFloatImageInfoIndex = 0; +} + +bool OleStreamParser::readStream(OleMainStream &oleMainStream) { + ZLUnicodeUtil::Ucs2Char ucs2char; + bool tabMode = false; + while (getUcs2Char(oleMainStream, ucs2char)) { + if (tabMode) { + tabMode = false; + if (ucs2char == WORD_TABLE_SEPARATOR) { + handleTableEndRow(); + continue; + } else { + handleTableSeparator(); + } + } + + if (ucs2char < 32) { + switch (ucs2char) { + case NULL_SYMBOL: + break; + case WORD_HARD_LINEBREAK: + handleHardLinebreak(); + break; + case WORD_END_OF_PARAGRAPH: + case WORD_PAGE_BREAK: + handleParagraphEnd(); + break; + case WORD_TABLE_SEPARATOR: + tabMode = true; + break; + case WORD_FOOTNOTE_MARK: + handleFootNoteMark(); + break; + case WORD_START_FIELD: + handleStartField(); + break; + case WORD_SEPARATOR_FIELD: + handleSeparatorField(); + break; + case WORD_END_FIELD: + handleEndField(); + break; + case INLINE_IMAGE: + case FLOAT_IMAGE: + break; + default: + handleOtherControlChar(ucs2char); + break; + } + } else if (ucs2char == WORD_ZERO_WIDTH_UNBREAKABLE_SPACE) { + continue; //skip + } else { + handleChar(ucs2char); + } + } + + return true; +} + +bool OleStreamParser::getUcs2Char(OleMainStream &stream, ZLUnicodeUtil::Ucs2Char &ucs2char) { + while (myCurBufferPosition >= myBuffer.size()) { + myBuffer.clear(); + myCurBufferPosition = 0; + if (!readNextPiece(stream)) { + return false; + } + } + ucs2char = myBuffer.at(myCurBufferPosition++); + processStyles(stream); + + switch (ucs2char) { + case INLINE_IMAGE: + processInlineImage(stream); + break; + case FLOAT_IMAGE: + processFloatImage(stream); + break; + } + ++myCurCharPos; + return true; +} + +void OleStreamParser::processInlineImage(OleMainStream &stream) { + const OleMainStream::InlineImageInfoList &imageInfoList = stream.getInlineImageInfoList(); + if (imageInfoList.empty()) { + return; + } + //seek to curCharPos, because not all entries are real pictures + while(myNextInlineImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextInlineImageInfoIndex).first < myCurCharPos) { + ++myNextInlineImageInfoIndex; + } + while (myNextInlineImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextInlineImageInfoIndex).first == myCurCharPos) { + OleMainStream::InlineImageInfo info = imageInfoList.at(myNextInlineImageInfoIndex).second; + ZLFileImage::Blocks list = stream.getInlineImage(info.DataPosition); + if (!list.empty()) { + handleImage(list); + } + ++myNextInlineImageInfoIndex; + } +} + +void OleStreamParser::processFloatImage(OleMainStream &stream) { + const OleMainStream::FloatImageInfoList &imageInfoList = stream.getFloatImageInfoList(); + if (imageInfoList.empty()) { + return; + } + //seek to curCharPos, because not all entries are real pictures + while(myNextFloatImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextFloatImageInfoIndex).first < myCurCharPos) { + ++myNextFloatImageInfoIndex; + } + while (myNextFloatImageInfoIndex < imageInfoList.size() && imageInfoList.at(myNextFloatImageInfoIndex).first == myCurCharPos) { + OleMainStream::FloatImageInfo info = imageInfoList.at(myNextFloatImageInfoIndex).second; + ZLFileImage::Blocks list = stream.getFloatImage(info.ShapeId); + if (!list.empty()) { + handleImage(list); + } + ++myNextFloatImageInfoIndex; + } +} + +void OleStreamParser::processStyles(OleMainStream &stream) { + const OleMainStream::StyleInfoList &styleInfoList = stream.getStyleInfoList(); + if (!styleInfoList.empty()) { + while (myNextStyleInfoIndex < styleInfoList.size() && styleInfoList.at(myNextStyleInfoIndex).first == myCurCharPos) { + OleMainStream::Style info = styleInfoList.at(myNextStyleInfoIndex).second; + handleParagraphStyle(info); + ++myNextStyleInfoIndex; + } + } + + const OleMainStream::CharInfoList &charInfoList = stream.getCharInfoList(); + if (!charInfoList.empty()) { + while (myNextCharInfoIndex < charInfoList.size() && charInfoList.at(myNextCharInfoIndex).first == myCurCharPos) { + OleMainStream::CharInfo info = charInfoList.at(myNextCharInfoIndex).second; + handleFontStyle(info.FontStyle); + ++myNextCharInfoIndex; + } + } + + const OleMainStream::BookmarksList &bookmarksList = stream.getBookmarks(); + if (!bookmarksList.empty()) { + while (myNextBookmarkIndex < bookmarksList.size() && bookmarksList.at(myNextBookmarkIndex).CharPosition == myCurCharPos) { + OleMainStream::Bookmark bookmark = bookmarksList.at(myNextBookmarkIndex); + handleBookmark(bookmark.Name); + ++myNextBookmarkIndex; + } + } +} diff --git a/reader/src/formats/doc/OleStreamParser.h b/reader/src/formats/doc/OleStreamParser.h new file mode 100644 index 0000000..1adec2f --- /dev/null +++ b/reader/src/formats/doc/OleStreamParser.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLESTREAMPARSER_H__ +#define __OLESTREAMPARSER_H__ + +#include <ZLUnicodeUtil.h> + +#include "OleMainStream.h" +#include "OleStreamReader.h" + +class OleStreamParser : public OleStreamReader { + +public: + //word's control chars: + static const ZLUnicodeUtil::Ucs2Char WORD_FOOTNOTE_MARK; + static const ZLUnicodeUtil::Ucs2Char WORD_TABLE_SEPARATOR; + static const ZLUnicodeUtil::Ucs2Char WORD_HORIZONTAL_TAB; + static const ZLUnicodeUtil::Ucs2Char WORD_HARD_LINEBREAK; + static const ZLUnicodeUtil::Ucs2Char WORD_PAGE_BREAK; + static const ZLUnicodeUtil::Ucs2Char WORD_END_OF_PARAGRAPH; + static const ZLUnicodeUtil::Ucs2Char WORD_MINUS; + static const ZLUnicodeUtil::Ucs2Char WORD_SOFT_HYPHEN; + static const ZLUnicodeUtil::Ucs2Char WORD_START_FIELD; + static const ZLUnicodeUtil::Ucs2Char WORD_SEPARATOR_FIELD; + static const ZLUnicodeUtil::Ucs2Char WORD_END_FIELD; + static const ZLUnicodeUtil::Ucs2Char WORD_ZERO_WIDTH_UNBREAKABLE_SPACE; + static const ZLUnicodeUtil::Ucs2Char INLINE_IMAGE; + static const ZLUnicodeUtil::Ucs2Char FLOAT_IMAGE; + + //unicode values: + static const ZLUnicodeUtil::Ucs2Char NULL_SYMBOL; + static const ZLUnicodeUtil::Ucs2Char FILE_SEPARATOR; + static const ZLUnicodeUtil::Ucs2Char LINE_FEED; + static const ZLUnicodeUtil::Ucs2Char SOFT_HYPHEN; + static const ZLUnicodeUtil::Ucs2Char SPACE; + static const ZLUnicodeUtil::Ucs2Char MINUS; + static const ZLUnicodeUtil::Ucs2Char VERTICAL_LINE; + +public: + OleStreamParser(); + +private: + bool readStream(OleMainStream &stream); + +protected: + virtual void handleChar(ZLUnicodeUtil::Ucs2Char ucs2char) = 0; + virtual void handleHardLinebreak() = 0; + virtual void handleParagraphEnd() = 0; + virtual void handlePageBreak() = 0; + virtual void handleTableSeparator() = 0; + virtual void handleTableEndRow() = 0; + virtual void handleFootNoteMark() = 0; + virtual void handleStartField() = 0; + virtual void handleSeparatorField() = 0; + virtual void handleEndField() = 0; + virtual void handleImage(const ZLFileImage::Blocks &blocks) = 0; + virtual void handleOtherControlChar(ZLUnicodeUtil::Ucs2Char ucs2char) = 0; + + virtual void handleFontStyle(unsigned int fontStyle) = 0; + virtual void handleParagraphStyle(const OleMainStream::Style &styleInfo) = 0; + virtual void handleBookmark(const std::string &name) = 0; + +private: + bool getUcs2Char(OleMainStream &stream, ZLUnicodeUtil::Ucs2Char &ucs2char); + void processInlineImage(OleMainStream &stream); + void processFloatImage(OleMainStream &stream); + void processStyles(OleMainStream &stream); + +private: +protected: + ZLUnicodeUtil::Ucs2String myBuffer; +private: + std::size_t myCurBufferPosition; + + unsigned int myCurCharPos; + + std::size_t myNextStyleInfoIndex; + std::size_t myNextCharInfoIndex; + std::size_t myNextBookmarkIndex; + std::size_t myNextInlineImageInfoIndex; + std::size_t myNextFloatImageInfoIndex; +}; + +#endif /* __OLESTREAMPARSER_H__ */ diff --git a/reader/src/formats/doc/OleStreamReader.cpp b/reader/src/formats/doc/OleStreamReader.cpp new file mode 100644 index 0000000..224489a --- /dev/null +++ b/reader/src/formats/doc/OleStreamReader.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLLogger.h> + +#include "OleMainStream.h" +#include "OleUtil.h" +#include "OleStreamReader.h" + +OleStreamReader::OleStreamReader() : myNextPieceNumber(0) { +} + +bool OleStreamReader::readDocument(shared_ptr<ZLInputStream> inputStream, bool doReadFormattingData) { + static const std::string WORD_DOCUMENT = "WordDocument"; + + shared_ptr<OleStorage> storage = new OleStorage; + + if (!storage->init(inputStream, inputStream->sizeOfOpened())) { + ZLLogger::Instance().println("DocPlugin", "Broken OLE file"); + return false; + } + + OleEntry wordDocumentEntry; + if (!storage->getEntryByName(WORD_DOCUMENT, wordDocumentEntry)) { + return false; + } + + OleMainStream oleStream(storage, wordDocumentEntry, inputStream); + if (!oleStream.open(doReadFormattingData)) { + ZLLogger::Instance().println("DocPlugin", "Cannot open OleMainStream"); + return false; + } + return readStream(oleStream); +} + +bool OleStreamReader::readNextPiece(OleMainStream &stream) { + const OleMainStream::Pieces &pieces = stream.getPieces(); + if (myNextPieceNumber >= pieces.size()) { + return false; + } + const OleMainStream::Piece &piece = pieces.at(myNextPieceNumber); + + if (piece.Type == OleMainStream::Piece::PIECE_FOOTNOTE) { + footnotesStartHandler(); + } else if (piece.Type == OleMainStream::Piece::PIECE_OTHER) { + return false; + } + + if (!stream.seek(piece.Offset, true)) { + //TODO maybe in that case we should take next piece? + return false; + } + char *textBuffer = new char[piece.Length]; + std::size_t readBytes = stream.read(textBuffer, piece.Length); + if (readBytes != (std::size_t)piece.Length) { + ZLLogger::Instance().println("DocPlugin", "not all bytes have been read from piece"); + } + + if (!piece.IsANSI) { + for (std::size_t i = 0; i < readBytes; i += 2) { + ucs2SymbolHandler(OleUtil::getU2Bytes(textBuffer, i)); + } + } else { + ansiDataHandler(textBuffer, readBytes); + } + ++myNextPieceNumber; + delete[] textBuffer; + + return true; +} diff --git a/reader/src/formats/doc/OleStreamReader.h b/reader/src/formats/doc/OleStreamReader.h new file mode 100644 index 0000000..2d2a0ae --- /dev/null +++ b/reader/src/formats/doc/OleStreamReader.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLESTREAMREADER_H__ +#define __OLESTREAMREADER_H__ + +#include <ZLUnicodeUtil.h> + +#include "OleMainStream.h" + +class OleStreamReader { + +public: + OleStreamReader(); + bool readDocument(shared_ptr<ZLInputStream> stream, bool doReadFormattingData); + +protected: + virtual bool readStream(OleMainStream &stream) = 0; + + bool readNextPiece(OleMainStream &stream); + + virtual void ansiDataHandler(const char *buffer, std::size_t len) = 0; + virtual void ucs2SymbolHandler(ZLUnicodeUtil::Ucs2Char symbol) = 0; + virtual void footnotesStartHandler() = 0; + +private: + std::size_t myNextPieceNumber; +}; + +#endif /* __OLESTREAMREADER_H__ */ diff --git a/reader/src/formats/doc/OleUtil.cpp b/reader/src/formats/doc/OleUtil.cpp new file mode 100644 index 0000000..2e8f685 --- /dev/null +++ b/reader/src/formats/doc/OleUtil.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "OleUtil.h" + +int OleUtil::get4Bytes(const char *buffer, unsigned int offset) { + const unsigned char *buf = (const unsigned char*)buffer; + return + (int)buf[offset] + | ((int)buf[offset+1] << 8) + | ((int)buf[offset+2] << 16) + | ((int)buf[offset+3] << 24); +} + +unsigned int OleUtil::getU4Bytes(const char *buffer, unsigned int offset) { + const unsigned char *buf = (const unsigned char*)buffer; + return + (unsigned int)buf[offset] + | ((unsigned int)buf[offset+1] << 8) + | ((unsigned int)buf[offset+2] << 16) + | ((unsigned int)buf[offset+3] << 24); +} + +unsigned int OleUtil::getU2Bytes(const char *buffer, unsigned int offset) { + const unsigned char *buf = (const unsigned char*)buffer; + return + (unsigned int)buf[offset] + | ((unsigned int)buf[offset+1] << 8); +} + +unsigned int OleUtil::getU1Byte(const char *buffer, unsigned int offset) { + const unsigned char *buf = (const unsigned char*)buffer; + return (unsigned int)buf[offset]; +} + +int OleUtil::get1Byte(const char *buffer, unsigned int offset) { + const unsigned char *buf = (const unsigned char*)buffer; + return (int)buf[offset]; +} + + + diff --git a/reader/src/formats/doc/OleUtil.h b/reader/src/formats/doc/OleUtil.h new file mode 100644 index 0000000..531c769 --- /dev/null +++ b/reader/src/formats/doc/OleUtil.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OLEUTIL_H__ +#define __OLEUTIL_H__ + +class OleUtil { +public: + static int get4Bytes(const char *buffer, unsigned int offset); + static unsigned int getU4Bytes(const char *buffer, unsigned int offset); + static unsigned int getU2Bytes(const char *buffer, unsigned int offset); + static unsigned int getU1Byte(const char *buffer, unsigned int offset); + static int get1Byte(const char *buffer, unsigned int offset); +}; + +#endif /* __OLEUTIL_H__ */ diff --git a/reader/src/formats/docbook/DocBookBookReader.cpp b/reader/src/formats/docbook/DocBookBookReader.cpp new file mode 100644 index 0000000..eada90c --- /dev/null +++ b/reader/src/formats/docbook/DocBookBookReader.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "DocBookBookReader.h" + +#include "../../bookmodel/BookModel.h" +#include "../../model/Paragraph.h" + +DocBookBookReader::DocBookBookReader(BookModel &model) : BookReader(model) { + setMainTextModel(); + + myReadText = false; +} + +void DocBookBookReader::characterDataHandler(const char *text, std::size_t len) { + addDataToBuffer(text, len); +} + +void DocBookBookReader::startElementHandler(int tag, const char **) { + switch (tag) { + case _SECT1: + myReadText = true; + pushKind(REGULAR); + beginContentsParagraph(); + break; + case _PARA: + if (myReadText) { + beginParagraph(); + } + break; + case _TITLE: + enterTitle(); + pushKind(SECTION_TITLE); + if (myReadText) { + beginParagraph(); + } + break; + case _EMPHASIS: + addControl(EMPHASIS, true); + break; + case _CITETITLE: + addControl(CITE, true); + break; + case _ULINK: + case _EMAIL: + addControl(CODE, true); + break; + case _BLOCKQUOTE: + pushKind(STRONG); + break; + default: + break; + } +} + +void DocBookBookReader::endElementHandler(int tag) { + switch (tag) { + case _SECT1: + myReadText = false; + popKind(); + endContentsParagraph(); + insertEndOfSectionParagraph(); + break; + case _PARA: + endParagraph(); + break; + case _TITLE: + endParagraph(); + popKind(); + endContentsParagraph(); + exitTitle(); + break; + case _EMPHASIS: + addControl(EMPHASIS, false); + break; + case _CITETITLE: + addControl(CITE, false); + break; + case _ULINK: + case _EMAIL: + addControl(CODE, false); + break; + case _BLOCKQUOTE: + popKind(); + break; + default: + break; + } +} + +void DocBookBookReader::readBook(shared_ptr<ZLInputStream> stream) { + readDocument(stream); +} diff --git a/reader/src/formats/docbook/DocBookBookReader.h b/reader/src/formats/docbook/DocBookBookReader.h new file mode 100644 index 0000000..c226184 --- /dev/null +++ b/reader/src/formats/docbook/DocBookBookReader.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCBOOKBOOKREADER_H__ +#define __DOCBOOKBOOKREADER_H__ + +#include "DocBookReader.h" +#include "../../bookmodel/BookReader.h" + +class BookModel; + +class DocBookBookReader : public BookReader, public DocBookReader { + +public: + DocBookBookReader(BookModel &model); + ~DocBookBookReader(); + void readBook(shared_ptr<ZLInputStream> stream); + + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + bool myReadText; +}; + +inline DocBookBookReader::~DocBookBookReader() {} + +#endif /* __DOCBOOKBOOKREADER_H__ */ diff --git a/reader/src/formats/docbook/DocBookDescriptionReader.cpp b/reader/src/formats/docbook/DocBookDescriptionReader.cpp new file mode 100644 index 0000000..bcd4ae4 --- /dev/null +++ b/reader/src/formats/docbook/DocBookDescriptionReader.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> +#include <ZLUnicodeUtil.h> + +#include "DocBookDescriptionReader.h" + +#include "../../library/Book.h" +#include "../../library/Author.h" + +DocBookDescriptionReader::DocBookDescriptionReader(Book &book) : myBook(book) { + myReadTitle = false; + myReadAuthor = false; + for (int i = 0; i < 3; ++i) { + myReadAuthorName[i] = false; + } + myBook.setLanguage("en"); + myDepth = 0; +} + +void DocBookDescriptionReader::characterDataHandler(const char *text, std::size_t len) { + if (myReadTitle) { + myBook.setTitle(myBook.title() + std::string(text, len)); + } else { + for (int i = 0; i < 3; ++i) { + if (myReadAuthorName[i]) { + myAuthorNames[i].append(text, len); + break; + } + } + } +} + +void DocBookDescriptionReader::startElementHandler(int tag, const char **) { + ++myDepth; + switch (tag) { + case _SECT1: + myReturnCode = true; + myDoBreak = true; + break; + case _TITLE: + if (myDepth == 2) { + myReadTitle = true; + } + break; + case _AUTHOR: + if (myDepth == 3) { + myReadAuthor = true; + } + break; + case _FIRSTNAME: + if (myReadAuthor) { + myReadAuthorName[0] = true; + } + break; + case _OTHERNAME: + if (myReadAuthor) { + myReadAuthorName[1] = true; + } + break; + case _SURNAME: + if (myReadAuthor) { + myReadAuthorName[2] = true; + } + break; + default: + break; + } +} + +void DocBookDescriptionReader::endElementHandler(int tag) { + --myDepth; + switch (tag) { + case _TITLE: + myReadTitle = false; + break; + case _AUTHOR: { + ZLUnicodeUtil::utf8Trim(myAuthorNames[0]); + ZLUnicodeUtil::utf8Trim(myAuthorNames[1]); + ZLUnicodeUtil::utf8Trim(myAuthorNames[2]); + std::string fullName = myAuthorNames[0]; + if (!fullName.empty() && !myAuthorNames[1].empty()) { + fullName += ' '; + } + fullName += myAuthorNames[1]; + if (!fullName.empty() && !myAuthorNames[2].empty()) { + fullName += ' '; + } + fullName += myAuthorNames[2]; + shared_ptr<Author> author = Author::create(fullName, myAuthorNames[2]); + if (!author.isNull()) { + myBook.authors().add( author ); + } + } + myAuthorNames[0].erase(); + myAuthorNames[1].erase(); + myAuthorNames[2].erase(); + myReadAuthor = false; + break; + case _FIRSTNAME: + myReadAuthorName[0] = false; + break; + case _OTHERNAME: + myReadAuthorName[1] = false; + break; + case _SURNAME: + myReadAuthorName[2] = false; + break; + default: + break; + } +} + +bool DocBookDescriptionReader::readMetaInfo(shared_ptr<ZLInputStream> stream) { + bool code = readDocument(stream); + if (myBook.authors().empty()) { + myBook.authors().push_back( new Author() ); + } + return code; +} diff --git a/reader/src/formats/docbook/DocBookDescriptionReader.h b/reader/src/formats/docbook/DocBookDescriptionReader.h new file mode 100644 index 0000000..d9f4aa3 --- /dev/null +++ b/reader/src/formats/docbook/DocBookDescriptionReader.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCBOOKDESCRIPTIONREADER_H__ +#define __DOCBOOKDESCRIPTIONREADER_H__ + +#include <string> + +#include "DocBookReader.h" + +class Book; + +class DocBookDescriptionReader : public DocBookReader { + +public: + DocBookDescriptionReader(Book &book); + ~DocBookDescriptionReader(); + bool readMetaInfo(shared_ptr<ZLInputStream> stream); + + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + Book &myBook; + + bool myReturnCode; + + bool myReadTitle; + bool myReadAuthor; + bool myReadAuthorName[3]; + + std::string myAuthorNames[3]; + + int myDepth; +}; + +inline DocBookDescriptionReader::~DocBookDescriptionReader() {} + +#endif /* __DOCBOOKDESCRIPTIONREADER_H__ */ diff --git a/reader/src/formats/docbook/DocBookPlugin.cpp b/reader/src/formats/docbook/DocBookPlugin.cpp new file mode 100644 index 0000000..1b890a6 --- /dev/null +++ b/reader/src/formats/docbook/DocBookPlugin.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "DocBookPlugin.h" +#include "DocBookDescriptionReader.h" +#include "DocBookBookReader.h" +#include "../../library/Book.h" + +bool DocBookPlugin::acceptsFile(const std::string &extension) const { + return extension == "xml"; +} + +bool DocBookPlugin::readMetaInfo(Book &book) const { + return DocBookDescriptionReader(book).readMetaInfo(ZLFile(path).inputStream()); +} + +bool DocBookPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +bool DocBookPlugin::readModel(BookModel &model) const { + return DocBookBookReader(model).readDocument(ZLFile(book.fileName()).inputStream()); +} diff --git a/reader/src/formats/docbook/DocBookPlugin.h b/reader/src/formats/docbook/DocBookPlugin.h new file mode 100644 index 0000000..324b2be --- /dev/null +++ b/reader/src/formats/docbook/DocBookPlugin.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCBOOKPLUGIN_H__ +#define __DOCBOOKPLUGIN_H__ + +#include "../FormatPlugin.h" + +class DocBookPlugin : public FormatPlugin { + +public: + DocBookPlugin(); + ~DocBookPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const std::string &extension) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +inline DocBookPlugin::DocBookPlugin() {} +inline DocBookPlugin::~DocBookPlugin() {} +inline bool DocBookPlugin::providesMetaInfo() const { return true; } + +#endif /* __DOCBOOKPLUGIN_H__ */ diff --git a/reader/src/formats/docbook/DocBookReader.cpp b/reader/src/formats/docbook/DocBookReader.cpp new file mode 100644 index 0000000..73c17d1 --- /dev/null +++ b/reader/src/formats/docbook/DocBookReader.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLDir.h> + +#include "DocBookReader.h" + +static const DocBookReader::Tag TAGS[] = { + {"article", DocBookReader::_ARTICLE}, + {"title", DocBookReader::_TITLE}, + {"articleinfo", DocBookReader::_ARTICLEINFO}, + {"author", DocBookReader::_AUTHOR}, + {"firstname", DocBookReader::_FIRSTNAME}, + {"othername", DocBookReader::_OTHERNAME}, + {"surname", DocBookReader::_SURNAME}, + {"affiliation", DocBookReader::_AFFILIATION}, + {"orgname", DocBookReader::_ORGNAME}, + {"ulink", DocBookReader::_ULINK}, + {"address", DocBookReader::_ADDRESS}, + {"email", DocBookReader::_EMAIL}, + {"pubdate", DocBookReader::_PUBDATE}, + {"releaseinfo", DocBookReader::_RELEASEINFO}, + {"copyright", DocBookReader::_COPYRIGHT}, + {"year", DocBookReader::_YEAR}, + {"holder", DocBookReader::_HOLDER}, + {"legalnotice", DocBookReader::_LEGALNOTICE}, + {"para", DocBookReader::_PARA}, + {"revhistory", DocBookReader::_REVHISTORY}, + {"revision", DocBookReader::_REVISION}, + {"revnumber", DocBookReader::_REVNUMBER}, + {"date", DocBookReader::_DATE}, + {"authorinitials", DocBookReader::_AUTHORINITIALS}, + {"revremark", DocBookReader::_REVREMARK}, + {"abstract", DocBookReader::_ABSTRACT}, + {"sect1", DocBookReader::_SECT1}, + {"emphasis", DocBookReader::_EMPHASIS}, + {"blockquote", DocBookReader::_BLOCKQUOTE}, + {"citetitle", DocBookReader::_CITETITLE}, + {"link", DocBookReader::_LINK}, + {"foreignphrase", DocBookReader::_FOREIGNPHRASE}, + {"part", DocBookReader::_PART}, + {"preface", DocBookReader::_PREFACE}, + {"chapter", DocBookReader::_CHAPTER}, + {0, DocBookReader::_UNKNOWN} +}; + +const DocBookReader::Tag *DocBookReader::tags() const { + return TAGS; +} + +const std::vector<std::string> &DocBookReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("docbook"); +} diff --git a/reader/src/formats/docbook/DocBookReader.h b/reader/src/formats/docbook/DocBookReader.h new file mode 100644 index 0000000..a18f358 --- /dev/null +++ b/reader/src/formats/docbook/DocBookReader.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCBOOKREADER_H__ +#define __DOCBOOKREADER_H__ + +#include <ZLXMLReader.h> + +class DocBookReader : public ZLXMLReader { + +public: + static std::string DTDDirectory; + +public: + struct Tag { + const char *tagName; + int tagCode; + }; + +public: +//protected: + enum TagCode { + _ARTICLE, + _TITLE, + _ARTICLEINFO, + _AUTHOR, + _FIRSTNAME, + _OTHERNAME, + _SURNAME, + _AFFILIATION, + _ORGNAME, + _ULINK, + _ADDRESS, + _EMAIL, + _PUBDATE, + _RELEASEINFO, + _COPYRIGHT, + _YEAR, + _HOLDER, + _LEGALNOTICE, + _PARA, + _REVHISTORY, + _REVISION, + _REVNUMBER, + _DATE, + _AUTHORINITIALS, + _REVREMARK, + _ABSTRACT, + _SECT1, + _EMPHASIS, + _BLOCKQUOTE, + _CITETITLE, + _LINK, + _FOREIGNPHRASE, + _FIRSTTERM, + _FILENAME, + _ITEMIZEDLIST, + _LISTITEM, + _PART, + _PREFACE, + _CHAPTER, + _UNKNOWN + }; + +protected: + DocBookReader(); + +public: + ~DocBookReader(); + const Tag *tags() const; + +protected: + const std::vector<std::string> &externalDTDs() const; +}; + +inline DocBookReader::DocBookReader() {} +inline DocBookReader::~DocBookReader() {} + +#endif /* __DOCBOOKREADER_H__ */ diff --git a/reader/src/formats/dummy/DummyBookReader.cpp b/reader/src/formats/dummy/DummyBookReader.cpp new file mode 100644 index 0000000..2684ebf --- /dev/null +++ b/reader/src/formats/dummy/DummyBookReader.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "DummyBookReader.h" +#include "../../bookmodel/BookModel.h" + +DummyBookReader::DummyBookReader(BookModel &model) : myModelReader(model) { +} + +/* +void DummyBookReader::characterDataHandler(const char *text, std::size_t len) { +} + +void DummyBookReader::startElementHandler(int tag, const char **xmlattributes) { +} + +void DummyBookReader::endElementHandler(int tag) { +} +*/ + +bool DummyBookReader::readBook(shared_ptr<ZLInputStream> stream) { + //return readDocument(stream); + return true; +} diff --git a/reader/src/formats/dummy/DummyBookReader.h b/reader/src/formats/dummy/DummyBookReader.h new file mode 100644 index 0000000..ba6bcf8 --- /dev/null +++ b/reader/src/formats/dummy/DummyBookReader.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DUMMYBOOKREADER_H__ +#define __DUMMYBOOKREADER_H__ + +#include "../../bookmodel/BookReader.h" + +class DummyBookReader { + +public: + DummyBookReader(BookModel &model); + ~DummyBookReader(); + bool readBook(shared_ptr<ZLInputStream> stream); + + /* + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + */ + +private: + BookReader myModelReader; +}; + +inline DummyBookReader::~DummyBookReader() {} + +#endif /* __DUMMYBOOKREADER_H__ */ diff --git a/reader/src/formats/dummy/DummyMetaInfoReader.cpp b/reader/src/formats/dummy/DummyMetaInfoReader.cpp new file mode 100644 index 0000000..5dd13c5 --- /dev/null +++ b/reader/src/formats/dummy/DummyMetaInfoReader.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "DummyMetaInfoReader.h" + +DummyMetaInfoReader::DummyMetaInfoReader(Book &book) : myBook(book) { +} + +/* +void DummyMetaInfoReader::characterDataHandler(const char *text, std::size_t len) { +} + +void DummyMetaInfoReader::startElementHandler(int tag, const char **) { +} + +void DummyMetaInfoReader::endElementHandler(int tag) { +} +*/ + +bool DummyMetaInfoReader::readMetaInfo(shared_ptr<ZLInputStream> stream) { + return false; +} diff --git a/reader/src/formats/dummy/DummyMetaInfoReader.h b/reader/src/formats/dummy/DummyMetaInfoReader.h new file mode 100644 index 0000000..818d996 --- /dev/null +++ b/reader/src/formats/dummy/DummyMetaInfoReader.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DUMMYMETAINFOREADER_H__ +#define __DUMMYMETAINFOREADER_H__ + +#include <string> + +class Book; + +class DummyMetaInfoReader { + +public: + DummyMetaInfoReader(Book &book); + ~DummyMetaInfoReader(); + bool readMetaInfo(shared_ptr<ZLInputStream> stream); + + /* + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + */ + +private: + Book &myBook; +}; + +inline DummyMetaInfoReader::~DummyMetaInfoReader() {} + +#endif /* __DUMMYMETAINFOREADER_H__ */ diff --git a/reader/src/formats/dummy/DummyPlugin.cpp b/reader/src/formats/dummy/DummyPlugin.cpp new file mode 100644 index 0000000..bfe0662 --- /dev/null +++ b/reader/src/formats/dummy/DummyPlugin.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "DummyPlugin.h" +#include "DummyMetaInfoReader.h" +#include "DummyBookReader.h" +#include "../../library/Book.h" + +DummyPlugin::DummyPlugin() { +} + +DummyPlugin::~DummyPlugin() { +} + +bool DummyPlugin::providesMetaInfo() const { + return true; +} + +bool DummyPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "dummy"; +} + +bool DummyPlugin::readMetaInfo(Book &book) const { + return DummyMetaInfoReader(book).readMetaInfo(ZLFile(path).inputStream()); +} + +bool DummyPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +bool DummyPlugin::readModel(BookModel &model) const { + return DummyBookReader(model).readBook(ZLFile(book.fileName()).inputStream()); +} + +shared_ptr<const ZLImage> DummyPlugin::coverImage(const ZLFile &file) const { + return DummyCoverReader(file).readCover(); +} diff --git a/reader/src/formats/dummy/DummyPlugin.h b/reader/src/formats/dummy/DummyPlugin.h new file mode 100644 index 0000000..073449c --- /dev/null +++ b/reader/src/formats/dummy/DummyPlugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DUMMYPLUGIN_H__ +#define __DUMMYPLUGIN_H__ + +#include "../FormatPlugin.h" + +class DummyPlugin : public FormatPlugin { + +public: + DummyPlugin(); + ~DummyPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + shared_ptr<const ZLImage> coverImage(const ZLFile &file) const; +}; + +#endif /* __DUMMYPLUGIN_H__ */ diff --git a/reader/src/formats/dummy/createPlugin.sh b/reader/src/formats/dummy/createPlugin.sh new file mode 100755 index 0000000..aacc3d4 --- /dev/null +++ b/reader/src/formats/dummy/createPlugin.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ $# != 3 ]; then + echo "usage: $0 <short_format_name> <camel_cased_format_name> <upper_cased_format_name>"; + exit 0; +fi; + +if mkdir ../$1; then + for file in Dummy*.h Dummy*.cpp; do + sed "s/Dummy/$2/g" $file | sed "s/DUMMY/$3/g" > ../$1/`echo $file | sed "s/Dummy/$2/"`; + done +fi; diff --git a/reader/src/formats/fb2/FB2BookReader.cpp b/reader/src/formats/fb2/FB2BookReader.cpp new file mode 100644 index 0000000..f689343 --- /dev/null +++ b/reader/src/formats/fb2/FB2BookReader.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <cstring> + +#include <ZLInputStream.h> +#include <ZLStringUtil.h> +#include <ZLFileImage.h> + +#include <ZLTextParagraph.h> + +#include "FB2BookReader.h" +#include "../../library/Book.h" +#include "../../bookmodel/BookModel.h" + +FB2BookReader::FB2BookReader(BookModel &model) : myModelReader(model) { + myInsideCoverpage = false; + myParagraphsBeforeBodyNumber = (std::size_t)-1; + myInsidePoem = false; + mySectionDepth = 0; + myBodyCounter = 0; + myReadMainText = false; + myCurrentImageStart = -1; + mySectionStarted = false; + myInsideTitle = false; + myCurrentContentType = ZLMimeType::EMPTY; +} + +void FB2BookReader::characterDataHandler(const char *text, std::size_t len) { + if ((len > 0) && (!myCurrentImageId.empty() || myModelReader.paragraphIsOpen())) { + std::string str(text, len); + if (!myCurrentImageId.empty()) { + if (myCurrentImageStart == -1) { + myCurrentImageStart = getCurrentPosition(); + } + } else { + myModelReader.addData(str); + if (myInsideTitle) { + myModelReader.addContentsData(str); + } + } + } +} + +bool FB2BookReader::processNamespaces() const { + return true; +} + +void FB2BookReader::startElementHandler(int tag, const char **xmlattributes) { + const char *id = attributeValue(xmlattributes, "id"); + if (id != 0 && tag != _BINARY) { + if (!myReadMainText) { + myModelReader.setFootnoteTextModel(id); + } + myModelReader.addHyperlinkLabel(id); + } + switch (tag) { + case _P: + if (mySectionStarted) { + mySectionStarted = false; + } else if (myInsideTitle) { + static const std::string SPACE = " "; + myModelReader.addContentsData(SPACE); + } + myModelReader.beginParagraph(); + break; + case _V: + myModelReader.pushKind(VERSE); + myModelReader.beginParagraph(); + break; + case _SUBTITLE: + myModelReader.pushKind(SUBTITLE); + myModelReader.beginParagraph(); + break; + case _TEXT_AUTHOR: + myModelReader.pushKind(AUTHOR); + myModelReader.beginParagraph(); + break; + case _DATE: + myModelReader.pushKind(DATEKIND); + myModelReader.beginParagraph(); + break; + case _CITE: + myModelReader.pushKind(CITE); + break; + case _SECTION: + if (myReadMainText) { + myModelReader.insertEndOfSectionParagraph(); + ++mySectionDepth; + myModelReader.beginContentsParagraph(); + mySectionStarted = true; + } + break; + case _TITLE: + if (myInsidePoem) { + myModelReader.pushKind(POEM_TITLE); + } else if (mySectionDepth == 0) { + myModelReader.insertEndOfSectionParagraph(); + myModelReader.pushKind(TITLE); + } else { + myModelReader.pushKind(SECTION_TITLE); + myModelReader.enterTitle(); + myInsideTitle = true; + } + break; + case _POEM: + myInsidePoem = true; + break; + case _STANZA: + myModelReader.pushKind(STANZA); + myModelReader.beginParagraph(ZLTextParagraph::BEFORE_SKIP_PARAGRAPH); + myModelReader.endParagraph(); + break; + case _EPIGRAPH: + myModelReader.pushKind(EPIGRAPH); + break; + case _ANNOTATION: + if (myBodyCounter == 0) { + myModelReader.setMainTextModel(); + } + myModelReader.pushKind(ANNOTATION); + break; + case _COVERPAGE: + if (myBodyCounter == 0) { + myInsideCoverpage = true; + myModelReader.setMainTextModel(); + } + break; + case _SUB: + myModelReader.addControl(SUB, true); + break; + case _SUP: + myModelReader.addControl(SUP, true); + break; + case _CODE: + myModelReader.addControl(CODE, true); + break; + case _STRIKETHROUGH: + myModelReader.addControl(STRIKETHROUGH, true); + break; + case _STRONG: + myModelReader.addControl(STRONG, true); + break; + case _EMPHASIS: + myModelReader.addControl(EMPHASIS, true); + break; + case _A: + { + const char *ref = attributeValue(xmlattributes, myHrefPredicate); + if (ref != 0) { + if (ref[0] == '#') { + const char *type = attributeValue(xmlattributes, "type"); + static const std::string NOTE = "note"; + if ((type != 0) && (NOTE == type)) { + myHyperlinkType = FOOTNOTE; + } else { + myHyperlinkType = INTERNAL_HYPERLINK; + } + ++ref; + } else { + myHyperlinkType = EXTERNAL_HYPERLINK; + } + myModelReader.addHyperlinkControl(myHyperlinkType, ref); + } else { + myHyperlinkType = FOOTNOTE; + myModelReader.addControl(myHyperlinkType, true); + } + break; + } + case _IMAGE: + { + const char *ref = attributeValue(xmlattributes, myHrefPredicate); + const char *vOffset = attributeValue(xmlattributes, "voffset"); + char offset = vOffset != 0 ? std::atoi(vOffset) : 0; + if (ref != 0 && *ref == '#') { + ++ref; + const bool isCoverImage = + myParagraphsBeforeBodyNumber == + myModelReader.model().bookTextModel()->paragraphsNumber(); + if (myCoverImageReference != ref || !isCoverImage) { + myModelReader.addImageReference(ref, offset); + } + if (myInsideCoverpage) { + myCoverImageReference = ref; + } + } + break; + } + case _BINARY: + { + const char *contentType = attributeValue(xmlattributes, "content-type"); + if (contentType != 0) { + shared_ptr<ZLMimeType> contentMimeType = ZLMimeType::get(contentType); + if ((!contentMimeType.isNull()) && (id != 0) && (ZLMimeType::TEXT_XML != contentMimeType)) { + myCurrentContentType = contentMimeType; + myCurrentImageId.assign(id); + } + } + break; + } + case _EMPTY_LINE: + myModelReader.beginParagraph(ZLTextParagraph::EMPTY_LINE_PARAGRAPH); + myModelReader.endParagraph(); + break; + case _BODY: + ++myBodyCounter; + myParagraphsBeforeBodyNumber = myModelReader.model().bookTextModel()->paragraphsNumber(); + if ((myBodyCounter == 1) || (attributeValue(xmlattributes, "name") == 0)) { + myModelReader.setMainTextModel(); + myReadMainText = true; + } + myModelReader.pushKind(REGULAR); + break; + default: + break; + } +} + +void FB2BookReader::endElementHandler(int tag) { + switch (tag) { + case _P: + myModelReader.endParagraph(); + break; + case _V: + case _SUBTITLE: + case _TEXT_AUTHOR: + case _DATE: + myModelReader.popKind(); + myModelReader.endParagraph(); + break; + case _CITE: + myModelReader.popKind(); + break; + case _SECTION: + if (myReadMainText) { + myModelReader.endContentsParagraph(); + --mySectionDepth; + mySectionStarted = false; + } else { + myModelReader.unsetTextModel(); + } + break; + case _TITLE: + myModelReader.exitTitle(); + myModelReader.popKind(); + myInsideTitle = false; + break; + case _POEM: + myInsidePoem = false; + break; + case _STANZA: + myModelReader.beginParagraph(ZLTextParagraph::AFTER_SKIP_PARAGRAPH); + myModelReader.endParagraph(); + myModelReader.popKind(); + break; + case _EPIGRAPH: + myModelReader.popKind(); + break; + case _ANNOTATION: + myModelReader.popKind(); + if (myBodyCounter == 0) { + myModelReader.insertEndOfSectionParagraph(); + myModelReader.unsetTextModel(); + } + break; + case _COVERPAGE: + if (myBodyCounter == 0) { + myInsideCoverpage = false; + myModelReader.insertEndOfSectionParagraph(); + myModelReader.unsetTextModel(); + } + break; + case _SUB: + myModelReader.addControl(SUB, false); + break; + case _SUP: + myModelReader.addControl(SUP, false); + break; + case _CODE: + myModelReader.addControl(CODE, false); + break; + case _STRIKETHROUGH: + myModelReader.addControl(STRIKETHROUGH, false); + break; + case _STRONG: + myModelReader.addControl(STRONG, false); + break; + case _EMPHASIS: + myModelReader.addControl(EMPHASIS, false); + break; + case _A: + myModelReader.addControl(myHyperlinkType, false); + break; + case _BINARY: + if (!myCurrentImageId.empty() && myCurrentImageStart != -1) { + myModelReader.addImage(myCurrentImageId, new ZLFileImage( + ZLFile(myModelReader.model().book()->file().path(), myCurrentContentType), + myCurrentImageStart, + getCurrentPosition() - myCurrentImageStart, + ZLFileImage::ENCODING_BASE64 + )); + } + myCurrentImageId.clear(); + myCurrentContentType = ZLMimeType::EMPTY; + myCurrentImageStart = -1; + break; + case _BODY: + myModelReader.popKind(); + myModelReader.unsetTextModel(); + myReadMainText = false; + break; + default: + break; + } +} + +bool FB2BookReader::readBook() { + return readDocument(myModelReader.model().book()->file()); +} diff --git a/reader/src/formats/fb2/FB2BookReader.h b/reader/src/formats/fb2/FB2BookReader.h new file mode 100644 index 0000000..b9d22d1 --- /dev/null +++ b/reader/src/formats/fb2/FB2BookReader.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2BOOKREADER_H__ +#define __FB2BOOKREADER_H__ + +#include <ZLMimeType.h> + +#include "FB2Reader.h" +#include "../../bookmodel/BookReader.h" + +class BookModel; + +class FB2BookReader : public FB2Reader { + +public: + FB2BookReader(BookModel &model); + bool readBook(); + + bool processNamespaces() const; + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + int mySectionDepth; + int myBodyCounter; + bool myReadMainText; + bool myInsideCoverpage; + std::size_t myParagraphsBeforeBodyNumber; + std::string myCoverImageReference; + bool myInsidePoem; + BookReader myModelReader; + + int myCurrentImageStart; + std::string myCurrentImageId; + shared_ptr<ZLMimeType> myCurrentContentType; + + bool mySectionStarted; + bool myInsideTitle; + + FBTextKind myHyperlinkType; +}; + +#endif /* __FB2BOOKREADER_H__ */ diff --git a/reader/src/formats/fb2/FB2CoverReader.cpp b/reader/src/formats/fb2/FB2CoverReader.cpp new file mode 100644 index 0000000..cc84ac2 --- /dev/null +++ b/reader/src/formats/fb2/FB2CoverReader.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFileImage.h> + +#include "FB2CoverReader.h" + +#include "../../library/Book.h" + +FB2CoverReader::FB2CoverReader(const ZLFile &file) : myFile(file) { +} + +shared_ptr<const ZLImage> FB2CoverReader::readCover() { + myReadCoverPage = false; + myLookForImage = false; + myImageId.erase(); + myImageStart = -1; + + readDocument(myFile); + + return myImage; +} + +bool FB2CoverReader::processNamespaces() const { + return true; +} + +void FB2CoverReader::startElementHandler(int tag, const char **attributes) { + switch (tag) { + case _COVERPAGE: + myReadCoverPage = true; + break; + case _IMAGE: + if (myReadCoverPage) { + const char *ref = attributeValue(attributes, myHrefPredicate); + if (ref != 0 && *ref == '#' && *(ref + 1) != '\0') { + myImageId = ref + 1; + } + } + break; + case _BINARY: + { + const char *id = attributeValue(attributes, "id"); + const char *contentType = attributeValue(attributes, "content-type"); + if (id != 0 && contentType != 0 && myImageId == id) { + myLookForImage = true; + } + } + } +} + +void FB2CoverReader::endElementHandler(int tag) { + switch (tag) { + case _COVERPAGE: + myReadCoverPage = false; + break; + case _DESCRIPTION: + if (myImageId.empty()) { + interrupt(); + } + break; + case _BINARY: + if (!myImageId.empty() && myImageStart >= 0) { + myImage = new ZLFileImage(myFile, myImageStart, getCurrentPosition() - myImageStart, ZLFileImage::ENCODING_BASE64); + interrupt(); + } + break; + } +} + +void FB2CoverReader::characterDataHandler(const char *text, std::size_t len) { + if (len > 0 && myLookForImage) { + myImageStart = getCurrentPosition(); + myLookForImage = false; + } +} diff --git a/reader/src/formats/fb2/FB2CoverReader.h b/reader/src/formats/fb2/FB2CoverReader.h new file mode 100644 index 0000000..6807aa9 --- /dev/null +++ b/reader/src/formats/fb2/FB2CoverReader.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2COVERREADER_H__ +#define __FB2COVERREADER_H__ + +#include <ZLFile.h> +#include <ZLImage.h> + +#include "FB2Reader.h" + +class FB2CoverReader : public FB2Reader { + +public: + FB2CoverReader(const ZLFile &file); + shared_ptr<const ZLImage> readCover(); + +private: + bool processNamespaces() const; + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + const ZLFile myFile; + bool myReadCoverPage; + bool myLookForImage; + std::string myImageId; + int myImageStart; + shared_ptr<const ZLImage> myImage; +}; + +#endif /* __FB2COVERREADER_H__ */ diff --git a/reader/src/formats/fb2/FB2MetaInfoReader.cpp b/reader/src/formats/fb2/FB2MetaInfoReader.cpp new file mode 100644 index 0000000..3d596ac --- /dev/null +++ b/reader/src/formats/fb2/FB2MetaInfoReader.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLInputStream.h> +#include <ZLUnicodeUtil.h> + +#include "FB2MetaInfoReader.h" +#include "FB2TagManager.h" + +#include "../../library/Book.h" + +FB2MetaInfoReader::FB2MetaInfoReader(Book &book) : myBook(book) { + myBook.removeAllAuthors(); + myBook.setTitle(std::string()); + myBook.setLanguage(std::string()); + myBook.removeAllTags(); +} + +void FB2MetaInfoReader::characterDataHandler(const char *text, std::size_t len) { + switch (myReadState) { + case READ_TITLE: + myBuffer.append(text, len); + break; + case READ_LANGUAGE: + myBuffer.append(text, len); + break; + case READ_AUTHOR_NAME_0: + myAuthorNames[0].append(text, len); + break; + case READ_AUTHOR_NAME_1: + myAuthorNames[1].append(text, len); + break; + case READ_AUTHOR_NAME_2: + myAuthorNames[2].append(text, len); + break; + case READ_GENRE: + myBuffer.append(text, len); + break; + default: + break; + } +} + +void FB2MetaInfoReader::startElementHandler(int tag, const char **attributes) { + switch (tag) { + case _BODY: + myReturnCode = true; + interrupt(); + break; + case _TITLE_INFO: + myReadState = READ_SOMETHING; + break; + case _BOOK_TITLE: + if (myReadState == READ_SOMETHING) { + myReadState = READ_TITLE; + } + break; + case _GENRE: + if (myReadState == READ_SOMETHING) { + myReadState = READ_GENRE; + } + break; + case _AUTHOR: + if (myReadState == READ_SOMETHING) { + myReadState = READ_AUTHOR; + } + break; + case _LANG: + if (myReadState == READ_SOMETHING) { + myReadState = READ_LANGUAGE; + } + break; + case _FIRST_NAME: + if (myReadState == READ_AUTHOR) { + myReadState = READ_AUTHOR_NAME_0; + } + break; + case _MIDDLE_NAME: + if (myReadState == READ_AUTHOR) { + myReadState = READ_AUTHOR_NAME_1; + } + break; + case _LAST_NAME: + if (myReadState == READ_AUTHOR) { + myReadState = READ_AUTHOR_NAME_2; + } + break; + case _SEQUENCE: + if (myReadState == READ_SOMETHING) { + const char *name = attributeValue(attributes, "name"); + if (name != 0) { + std::string seriesTitle = name; + ZLUnicodeUtil::utf8Trim(seriesTitle); + const char *number = attributeValue(attributes, "number"); + myBook.setSeries(seriesTitle, number != 0 ? std::string(number) : std::string()); + } + } + break; + default: + break; + } +} + +void FB2MetaInfoReader::endElementHandler(int tag) { + switch (tag) { + case _TITLE_INFO: + myReadState = READ_NOTHING; + break; + case _BOOK_TITLE: + if (myReadState == READ_TITLE) { + myBook.setTitle(myBuffer); + myBuffer.erase(); + myReadState = READ_SOMETHING; + } + break; + case _GENRE: + if (myReadState == READ_GENRE) { + ZLUnicodeUtil::utf8Trim(myBuffer); + if (!myBuffer.empty()) { + const std::vector<std::string> &tags = + FB2TagManager::Instance().humanReadableTags(myBuffer); + if (!tags.empty()) { + for (std::vector<std::string>::const_iterator it = tags.begin(); it != tags.end(); ++it) { + myBook.addTag(*it); + } + } else { + myBook.addTag(myBuffer); + } + myBuffer.erase(); + } + myReadState = READ_SOMETHING; + } + break; + case _AUTHOR: + if (myReadState == READ_AUTHOR) { + ZLUnicodeUtil::utf8Trim(myAuthorNames[0]); + ZLUnicodeUtil::utf8Trim(myAuthorNames[1]); + ZLUnicodeUtil::utf8Trim(myAuthorNames[2]); + std::string fullName = myAuthorNames[0]; + if (!fullName.empty() && !myAuthorNames[1].empty()) { + fullName += ' '; + } + fullName += myAuthorNames[1]; + if (!fullName.empty() && !myAuthorNames[2].empty()) { + fullName += ' '; + } + fullName += myAuthorNames[2]; + myBook.addAuthor(fullName, myAuthorNames[2]); + myAuthorNames[0].erase(); + myAuthorNames[1].erase(); + myAuthorNames[2].erase(); + myReadState = READ_SOMETHING; + } + break; + case _LANG: + if (myReadState == READ_LANGUAGE) { + myBook.setLanguage(myBuffer); + myBuffer.erase(); + myReadState = READ_SOMETHING; + } + break; + case _FIRST_NAME: + if (myReadState == READ_AUTHOR_NAME_0) { + myReadState = READ_AUTHOR; + } + break; + case _MIDDLE_NAME: + if (myReadState == READ_AUTHOR_NAME_1) { + myReadState = READ_AUTHOR; + } + break; + case _LAST_NAME: + if (myReadState == READ_AUTHOR_NAME_2) { + myReadState = READ_AUTHOR; + } + break; + default: + break; + } +} + +bool FB2MetaInfoReader::readMetaInfo() { + myReadState = READ_NOTHING; + for (int i = 0; i < 3; ++i) { + myAuthorNames[i].erase(); + } + return readDocument(myBook.file()); +} diff --git a/reader/src/formats/fb2/FB2MetaInfoReader.h b/reader/src/formats/fb2/FB2MetaInfoReader.h new file mode 100644 index 0000000..cc09909 --- /dev/null +++ b/reader/src/formats/fb2/FB2MetaInfoReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2METAINFOREADER_H__ +#define __FB2METAINFOREADER_H__ + +#include <string> + +#include "FB2Reader.h" + +class Book; + +class FB2MetaInfoReader : public FB2Reader { + +public: + FB2MetaInfoReader(Book &book); + bool readMetaInfo(); + + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + Book &myBook; + + bool myReturnCode; + + enum { + READ_NOTHING, + READ_SOMETHING, + READ_TITLE, + READ_AUTHOR, + READ_AUTHOR_NAME_0, + READ_AUTHOR_NAME_1, + READ_AUTHOR_NAME_2, + READ_LANGUAGE, + READ_GENRE + } myReadState; + + std::string myAuthorNames[3]; + std::string myBuffer; +}; + +#endif /* __FB2METAINFOREADER_H__ */ diff --git a/reader/src/formats/fb2/FB2Plugin.cpp b/reader/src/formats/fb2/FB2Plugin.cpp new file mode 100644 index 0000000..f65ddcb --- /dev/null +++ b/reader/src/formats/fb2/FB2Plugin.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLImage.h> + +#include "FB2Plugin.h" +#include "FB2MetaInfoReader.h" +#include "FB2BookReader.h" +#include "FB2CoverReader.h" + +#include "../../database/booksdb/BooksDBUtil.h" + +bool FB2Plugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "fb2"; +} + +bool FB2Plugin::readMetaInfo(Book &book) const { + return FB2MetaInfoReader(book).readMetaInfo(); +} + +bool FB2Plugin::readModel(BookModel &model) const { + return FB2BookReader(model).readBook(); +} + +shared_ptr<const ZLImage> FB2Plugin::coverImage(const ZLFile &file) const { + return FB2CoverReader(file).readCover(); +} +bool FB2Plugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} diff --git a/reader/src/formats/fb2/FB2Plugin.h b/reader/src/formats/fb2/FB2Plugin.h new file mode 100644 index 0000000..d96558d --- /dev/null +++ b/reader/src/formats/fb2/FB2Plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2PLUGIN_H__ +#define __FB2PLUGIN_H__ + +#include "../FormatPlugin.h" + +class FB2Plugin : public FormatPlugin { + +public: + FB2Plugin(); + ~FB2Plugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + shared_ptr<const ZLImage> coverImage(const ZLFile &file) const; +}; + +inline FB2Plugin::FB2Plugin() {} +inline FB2Plugin::~FB2Plugin() {} +inline bool FB2Plugin::providesMetaInfo() const { return true; } + +#endif /* __FB2PLUGIN_H__ */ diff --git a/reader/src/formats/fb2/FB2Reader.cpp b/reader/src/formats/fb2/FB2Reader.cpp new file mode 100644 index 0000000..c8e279c --- /dev/null +++ b/reader/src/formats/fb2/FB2Reader.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLibrary.h> +#include <ZLStringUtil.h> +#include <ZLXMLNamespace.h> + +#include "FB2Reader.h" + +#include "../util/EntityFilesCollector.h" + +FB2Reader::FB2Reader() : myHrefPredicate(ZLXMLNamespace::XLink, "href") { +} + +void FB2Reader::startElementHandler(const char *t, const char **attributes) { + startElementHandler(tag(t), attributes); +} + +void FB2Reader::endElementHandler(const char *t) { + endElementHandler(tag(t)); +} + +static const FB2Reader::Tag TAGS[] = { + {"p", FB2Reader::_P}, + {"subtitle", FB2Reader::_SUBTITLE}, + {"cite", FB2Reader::_CITE}, + {"text-author", FB2Reader::_TEXT_AUTHOR}, + {"date", FB2Reader::_DATE}, + {"section", FB2Reader::_SECTION}, + {"v", FB2Reader::_V}, + {"title", FB2Reader::_TITLE}, + {"poem", FB2Reader::_POEM}, + {"stanza", FB2Reader::_STANZA}, + {"epigraph", FB2Reader::_EPIGRAPH}, + {"annotation", FB2Reader::_ANNOTATION}, + {"sub", FB2Reader::_SUB}, + {"sup", FB2Reader::_SUP}, + {"code", FB2Reader::_CODE}, + {"strikethrough", FB2Reader::_STRIKETHROUGH}, + {"strong", FB2Reader::_STRONG}, + {"emphasis", FB2Reader::_EMPHASIS}, + {"a", FB2Reader::_A}, + {"image", FB2Reader::_IMAGE}, + {"binary", FB2Reader::_BINARY}, + {"description", FB2Reader::_DESCRIPTION}, + {"body", FB2Reader::_BODY}, + {"empty-line", FB2Reader::_EMPTY_LINE}, + {"title-info", FB2Reader::_TITLE_INFO}, + {"book-title", FB2Reader::_BOOK_TITLE}, + {"author", FB2Reader::_AUTHOR}, + {"lang", FB2Reader::_LANG}, + {"first-name", FB2Reader::_FIRST_NAME}, + {"middle-name", FB2Reader::_MIDDLE_NAME}, + {"last-name", FB2Reader::_LAST_NAME}, + {"coverpage", FB2Reader::_COVERPAGE}, + {"sequence", FB2Reader::_SEQUENCE}, + {"genre", FB2Reader::_GENRE}, + {0, FB2Reader::_UNKNOWN} +}; + +int FB2Reader::tag(const char *name) { + for (int i = 0; ; ++i) { + if (TAGS[i].tagName == 0 || std::strcmp(name, TAGS[i].tagName) == 0) { + return TAGS[i].tagCode; + } + } +} + +const std::vector<std::string> &FB2Reader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("fb2"); +} diff --git a/reader/src/formats/fb2/FB2Reader.h b/reader/src/formats/fb2/FB2Reader.h new file mode 100644 index 0000000..8fa8654 --- /dev/null +++ b/reader/src/formats/fb2/FB2Reader.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2READER_H__ +#define __FB2READER_H__ + +#include <ZLXMLReader.h> + +class FB2Reader : public ZLXMLReader { + +public: + struct Tag { + const char *tagName; + int tagCode; + }; + +protected: + virtual int tag(const char *name); + + virtual void startElementHandler(int tag, const char **attributes) = 0; + virtual void endElementHandler(int tag) = 0; + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + + const std::vector<std::string> &externalDTDs() const; + +public: + enum TagCode { + _P, + _SUBTITLE, + _CITE, + _TEXT_AUTHOR, + _DATE, + _SECTION, + _V, + _TITLE, + _POEM, + _STANZA, + _EPIGRAPH, + _ANNOTATION, + _SUB, + _SUP, + _CODE, + _STRIKETHROUGH, + _STRONG, + _EMPHASIS, + _A, + _IMAGE, + _BINARY, + _DESCRIPTION, + _BODY, + _EMPTY_LINE, + _TITLE_INFO, + _BOOK_TITLE, + _AUTHOR, + _LANG, + _FIRST_NAME, + _MIDDLE_NAME, + _LAST_NAME, + _COVERPAGE, + _SEQUENCE, + _GENRE, + _UNKNOWN + }; + +protected: + FB2Reader(); + ~FB2Reader(); + +protected: + const NamespaceAttributeNamePredicate myHrefPredicate; +}; + +inline FB2Reader::~FB2Reader() {} + +#endif /* __FB2READER_H__ */ diff --git a/reader/src/formats/fb2/FB2TagManager.cpp b/reader/src/formats/fb2/FB2TagManager.cpp new file mode 100644 index 0000000..f698ace --- /dev/null +++ b/reader/src/formats/fb2/FB2TagManager.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <vector> + +#include <ZLFile.h> +#include <ZLXMLReader.h> +#include <ZLibrary.h> +#include <ZLUnicodeUtil.h> + +#include "FB2TagManager.h" + +class FB2TagInfoReader : public ZLXMLReader { + +public: + FB2TagInfoReader(std::map<std::string,std::vector<std::string> > &tagMap); + + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + +private: + std::map<std::string,std::vector<std::string> > &myTagMap; + + std::string myCategoryName; + std::string mySubCategoryName; + std::vector<std::string> myGenreIds; + std::string myLanguage; +}; + +FB2TagInfoReader::FB2TagInfoReader(std::map<std::string,std::vector<std::string> > &tagMap) : myTagMap(tagMap) { + myLanguage = ZLibrary::Language(); + if (myLanguage != "ru") { + myLanguage = "en"; + } +} + +static const std::string CATEGORY_NAME_TAG = "root-descr"; +static const std::string SUBCATEGORY_NAME_TAG = "genre-descr"; +static const std::string GENRE_TAG = "genre"; +static const std::string SUBGENRE_TAG = "subgenre"; +static const std::string SUBGENRE_ALT_TAG = "genre-alt"; + +void FB2TagInfoReader::startElementHandler(const char *tag, const char **attributes) { + if ((SUBGENRE_TAG == tag) || (SUBGENRE_ALT_TAG == tag)) { + const char *id = attributeValue(attributes, "value"); + if (id != 0) { + myGenreIds.push_back(id); + } + } else if (CATEGORY_NAME_TAG == tag) { + const char *lang = attributeValue(attributes, "lang"); + if ((lang != 0) && (myLanguage == lang)) { + const char *name = attributeValue(attributes, "genre-title"); + if (name != 0) { + myCategoryName = name; + ZLUnicodeUtil::utf8Trim(myCategoryName); + } + } + } else if (SUBCATEGORY_NAME_TAG == tag) { + const char *lang = attributeValue(attributes, "lang"); + if ((lang != 0) && (myLanguage == lang)) { + const char *name = attributeValue(attributes, "title"); + if (name != 0) { + mySubCategoryName = name; + ZLUnicodeUtil::utf8Trim(mySubCategoryName); + } + } + } +} + +void FB2TagInfoReader::endElementHandler(const char *tag) { + if (GENRE_TAG == tag) { + myCategoryName.erase(); + mySubCategoryName.erase(); + myGenreIds.clear(); + } else if (SUBGENRE_TAG == tag) { + if (!myCategoryName.empty() && !mySubCategoryName.empty()) { + const std::string fullTagName = myCategoryName + '/' + mySubCategoryName; + for (std::vector<std::string>::const_iterator it = myGenreIds.begin(); it != myGenreIds.end(); ++it) { + myTagMap[*it].push_back(fullTagName); + } + } + mySubCategoryName.erase(); + myGenreIds.clear(); + } +} + +FB2TagManager *FB2TagManager::ourInstance = 0; + +const FB2TagManager &FB2TagManager::Instance() { + if (ourInstance == 0) { + ourInstance = new FB2TagManager(); + } + return *ourInstance; +} + +FB2TagManager::FB2TagManager() { + FB2TagInfoReader(myTagMap).readDocument(ZLFile( + ZLibrary::ApplicationDirectory() + ZLibrary::FileNameDelimiter + + "formats" + ZLibrary::FileNameDelimiter + "fb2" + + ZLibrary::FileNameDelimiter + "fb2genres.xml" + )); +} + +const std::vector<std::string> &FB2TagManager::humanReadableTags(const std::string &id) const { + static const std::vector<std::string> EMPTY; + std::map<std::string,std::vector<std::string> >::const_iterator it = myTagMap.find(id); + return (it != myTagMap.end()) ? it->second : EMPTY; +} diff --git a/reader/src/formats/fb2/FB2TagManager.h b/reader/src/formats/fb2/FB2TagManager.h new file mode 100644 index 0000000..cfbf076 --- /dev/null +++ b/reader/src/formats/fb2/FB2TagManager.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2TAGMANAGER_H__ +#define __FB2TAGMANAGER_H__ + +#include <string> +#include <map> +#include <vector> + +class FB2TagManager { + +private: + static FB2TagManager *ourInstance; + +public: + static const FB2TagManager &Instance(); + +private: + FB2TagManager(); + +public: + const std::vector<std::string> &humanReadableTags(const std::string &id) const; + +private: + std::map<std::string,std::vector<std::string> > myTagMap; +}; + +#endif /* __FB2TAGMANAGER_H__ */ diff --git a/reader/src/formats/html/HtmlBookReader.cpp b/reader/src/formats/html/HtmlBookReader.cpp new file mode 100644 index 0000000..321913d --- /dev/null +++ b/reader/src/formats/html/HtmlBookReader.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> + +#include <ZLFile.h> +#include <ZLFileImage.h> +#include <ZLStringUtil.h> + +#include "HtmlBookReader.h" +#include "HtmlTagActions.h" +#include "../txt/PlainTextFormat.h" +#include "../util/MiscUtil.h" +#include "../../bookmodel/BookModel.h" +#include "../css/StyleSheetParser.h" + +HtmlTagAction::HtmlTagAction(HtmlBookReader &reader) : myReader(reader) { +} + +HtmlTagAction::~HtmlTagAction() { +} + +void HtmlTagAction::reset() { +} + +DummyHtmlTagAction::DummyHtmlTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void DummyHtmlTagAction::run(const HtmlReader::HtmlTag&) { +} + +HtmlControlTagAction::HtmlControlTagAction(HtmlBookReader &reader, FBTextKind kind) : HtmlTagAction(reader), myKind(kind) { +} + +void HtmlControlTagAction::run(const HtmlReader::HtmlTag &tag) { + std::vector<FBTextKind> &list = myReader.myKindList; + int index; + for (index = list.size() - 1; index >= 0; --index) { + if (list[index] == myKind) { + break; + } + } + if (tag.Start) { + if (index == -1) { + bookReader().pushKind(myKind); + myReader.myKindList.push_back(myKind); + bookReader().addControl(myKind, true); + } + } else { + if (index >= 0) { + for (int i = list.size() - 1; i >= index; --i) { + bookReader().addControl(list[i], false); + bookReader().popKind(); + } + for (unsigned int j = index + 1; j < list.size(); ++j) { + bookReader().addControl(list[j], true); + bookReader().pushKind(list[j]); + } + list.erase(list.begin() + index); + } + } +} + +HtmlHeaderTagAction::HtmlHeaderTagAction(HtmlBookReader &reader, FBTextKind kind) : HtmlTagAction(reader), myKind(kind) { +} + +void HtmlHeaderTagAction::run(const HtmlReader::HtmlTag &tag) { + myReader.myIsStarted = false; + if (tag.Start) { + if (myReader.myBuildTableOfContent && !myReader.myIgnoreTitles) { + if (!bookReader().contentsParagraphIsOpen()) { + bookReader().insertEndOfSectionParagraph(); + bookReader().enterTitle(); + bookReader().beginContentsParagraph(); + } + } + bookReader().pushKind(myKind); + } else { + bookReader().popKind(); + if (myReader.myBuildTableOfContent && !myReader.myIgnoreTitles) { + bookReader().endContentsParagraph(); + bookReader().exitTitle(); + } + } + bookReader().beginParagraph(); +} + +HtmlIgnoreTagAction::HtmlIgnoreTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlIgnoreTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + if (myTagNames.find(tag.Name) == myTagNames.end()) { + ++myReader.myIgnoreDataCounter; + myTagNames.insert(tag.Name); + } + } else { + if (myTagNames.find(tag.Name) != myTagNames.end()) { + --myReader.myIgnoreDataCounter; + myTagNames.erase(tag.Name); + } + } +} + +HtmlHrefTagAction::HtmlHrefTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlHrefTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "NAME") { + bookReader().addHyperlinkLabel(tag.Attributes[i].Value); + } else if ((hyperlinkType() == REGULAR) && (tag.Attributes[i].Name == "HREF")) { + std::string value = tag.Attributes[i].Value; + if (!myReader.myFileName.empty() && + (value.length() > myReader.myFileName.length()) && + (value.substr(0, myReader.myFileName.length()) == myReader.myFileName)) { + value = value.substr(myReader.myFileName.length()); + } + if (!value.empty()) { + if (value[0] == '#') { + setHyperlinkType(INTERNAL_HYPERLINK); + bookReader().addHyperlinkControl(INTERNAL_HYPERLINK, value.substr(1)); + } else { + FBTextKind hyperlinkType = MiscUtil::referenceType(value); + if (hyperlinkType != INTERNAL_HYPERLINK) { + setHyperlinkType(hyperlinkType); + bookReader().addHyperlinkControl(hyperlinkType, value); + } + } + } + } + } + } else if (hyperlinkType() != REGULAR) { + bookReader().addControl(hyperlinkType(), false); + setHyperlinkType(REGULAR); + } +} + +void HtmlHrefTagAction::reset() { + setHyperlinkType(REGULAR); +} + +FBTextKind HtmlHrefTagAction::hyperlinkType() const { + return myHyperlinkType; +} + +void HtmlHrefTagAction::setHyperlinkType(FBTextKind hyperlinkType) { + myHyperlinkType = hyperlinkType; +} + +HtmlImageTagAction::HtmlImageTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlImageTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + bookReader().endParagraph(); + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "SRC") { + const std::string fileName = MiscUtil::decodeHtmlURL(tag.Attributes[i].Value); + const ZLFile file(myReader.myBaseDirPath + fileName); + if (file.exists()) { + bookReader().addImageReference(fileName); + bookReader().addImage(fileName, new ZLFileImage(file, 0)); + } + break; + } + } + bookReader().beginParagraph(); + } +} + +HtmlBreakTagAction::HtmlBreakTagAction(HtmlBookReader &reader, BreakType breakType) : HtmlTagAction(reader), myBreakType(breakType) { +} + +void HtmlBreakTagAction::run(const HtmlReader::HtmlTag &tag) { + if (myReader.myDontBreakParagraph) { + myReader.myDontBreakParagraph = false; + return; + } + + if ((tag.Start && (myBreakType & BREAK_AT_START)) || + (!tag.Start && (myBreakType & BREAK_AT_END))) { + bookReader().endParagraph(); + if (bookReader().isKindStackEmpty()) { + bookReader().pushKind(REGULAR); + } + bookReader().beginParagraph(); + } +} + +HtmlPreTagAction::HtmlPreTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlPreTagAction::run(const HtmlReader::HtmlTag &tag) { + bookReader().endParagraph(); + myReader.myIsPreformatted = tag.Start; + myReader.mySpaceCounter = -1; + myReader.myBreakCounter = 0; + if (myReader.myFormat.breakType() == PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE) { + if (tag.Start) { + bookReader().pushKind(PREFORMATTED); + } else { + bookReader().popKind(); + } + } + bookReader().beginParagraph(); +} + +HtmlListTagAction::HtmlListTagAction(HtmlBookReader &reader, int startIndex) : HtmlTagAction(reader), myStartIndex(startIndex) { +} + +void HtmlListTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + myReader.myListNumStack.push(myStartIndex); + } else if (!myReader.myListNumStack.empty()) { + myReader.myListNumStack.pop(); + } +} + +HtmlListItemTagAction::HtmlListItemTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlListItemTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + bookReader().endParagraph(); + bookReader().beginParagraph(); + if (!myReader.myListNumStack.empty()) { + bookReader().addFixedHSpace(3 * myReader.myListNumStack.size()); + int &index = myReader.myListNumStack.top(); + if (index == 0) { + myReader.addConvertedDataToBuffer("\342\200\242 ", 4, false); + } else { + std::string number; + ZLStringUtil::appendNumber(number, index++); + number += ". "; + myReader.addConvertedDataToBuffer(number.data(), number.length(), false); + } + myReader.myDontBreakParagraph = true; + } + } else { + myReader.myDontBreakParagraph = false; + } +} + +HtmlTableTagAction::HtmlTableTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlTableTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + myReader.myIgnoreTitles = true; + } else { + myReader.myIgnoreTitles = false; + } +} + +HtmlStyleTagAction::HtmlStyleTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void HtmlStyleTagAction::run(const HtmlReader::HtmlTag &tag) { + myReader.myStyleSheetParser = tag.Start ? new StyleSheetTableParser(myReader.myStyleSheetTable) : 0; + /* + if (!tag.Start) { + myReader.myStyleSheetTable.dump(); + } + */ +} + +shared_ptr<HtmlTagAction> HtmlBookReader::createAction(const std::string &tag) { + if (tag == "EM") { + return new HtmlControlTagAction(*this, EMPHASIS); + } else if (tag == "STRONG") { + return new HtmlControlTagAction(*this, STRONG); + } else if (tag == "B") { + return new HtmlControlTagAction(*this, BOLD); + } else if (tag == "I") { + return new HtmlControlTagAction(*this, ITALIC); + } else if (tag == "TT") { + return new HtmlControlTagAction(*this, CODE); + } else if (tag == "CODE") { + return new HtmlControlTagAction(*this, CODE); + } else if (tag == "CITE") { + return new HtmlControlTagAction(*this, CITE); + } else if (tag == "SUB") { + return new HtmlControlTagAction(*this, SUB); + } else if (tag == "SUP") { + return new HtmlControlTagAction(*this, SUP); + } else if (tag == "H1") { + return new HtmlHeaderTagAction(*this, H1); + } else if (tag == "H2") { + return new HtmlHeaderTagAction(*this, H2); + } else if (tag == "H3") { + return new HtmlHeaderTagAction(*this, H3); + } else if (tag == "H4") { + return new HtmlHeaderTagAction(*this, H4); + } else if (tag == "H5") { + return new HtmlHeaderTagAction(*this, H5); + } else if (tag == "H6") { + return new HtmlHeaderTagAction(*this, H6); + } else if (tag == "HEAD") { + return new HtmlIgnoreTagAction(*this); + } else if (tag == "TITLE") { + return new HtmlIgnoreTagAction(*this); + } else if (tag == "STYLE") { + return new HtmlStyleTagAction(*this); + } else if (tag == "SELECT") { + return new HtmlIgnoreTagAction(*this); + } else if (tag == "SCRIPT") { + return new HtmlIgnoreTagAction(*this); + } else if (tag == "A") { + return new HtmlHrefTagAction(*this); + } else if (tag == "TD") { + //return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_END); + } else if (tag == "TR") { + return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_END); + } else if (tag == "DIV") { + return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_END); + } else if (tag == "DT") { + return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_START); + } else if (tag == "P") { + return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_START_AND_AT_END); + } else if (tag == "BR") { + return new HtmlBreakTagAction(*this, HtmlBreakTagAction::BREAK_AT_START_AND_AT_END); + } else if (tag == "IMG") { + return new HtmlImageTagAction(*this); + } else if (tag == "UL") { + return new HtmlListTagAction(*this, 0); + } else if (tag == "MENU") { + return new HtmlListTagAction(*this, 0); + } else if (tag == "DIR") { + return new HtmlListTagAction(*this, 0); + } else if (tag == "OL") { + return new HtmlListTagAction(*this, 1); + } else if (tag == "LI") { + return new HtmlListItemTagAction(*this); + } else if (tag == "PRE") { + if (myProcessPreTag) { + return new HtmlPreTagAction(*this); + } + } else if (tag == "TABLE") { + return new HtmlTableTagAction(*this); + } + /* + } else if (tag == "DD") { + return 0; + } else if (tag == "DL") { + return 0; + } else if (tag == "DFN") { + return 0; + } else if (tag == "SAMP") { + return 0; + } else if (tag == "KBD") { + return 0; + } else if (tag == "VAR") { + return 0; + } else if (tag == "ABBR") { + return 0; + } else if (tag == "ACRONYM") { + return 0; + } else if (tag == "BLOCKQUOTE") { + return 0; + } else if (tag == "Q") { + return 0; + } else if (tag == "INS") { + return 0; + } else if (tag == "DEL") { + return 0; + } else if (tag == "BODY") { + return 0; + */ + return new DummyHtmlTagAction(*this); +} + +void HtmlBookReader::setBuildTableOfContent(bool build) { + myBuildTableOfContent = build; +} + +void HtmlBookReader::setProcessPreTag(bool process) { + myProcessPreTag = process; +} + +HtmlBookReader::HtmlBookReader(const std::string &baseDirectoryPath, BookModel &model, const PlainTextFormat &format, const std::string &encoding) : HtmlReader(encoding), myBookReader(model), myBaseDirPath(baseDirectoryPath), myFormat(format), myBuildTableOfContent(true), myProcessPreTag(true) { +} + +HtmlBookReader::~HtmlBookReader() { +} + +void HtmlBookReader::addConvertedDataToBuffer(const char *text, std::size_t len, bool convert) { + if (len > 0) { + if (myDontBreakParagraph) { + while (len > 0 && std::isspace(*text)) { + --len; + ++text; + } + if (len == 0) { + return; + } + } + if (convert) { + myConverter->convert(myConverterBuffer, text, text + len); + myBookReader.addData(myConverterBuffer); + myBookReader.addContentsData(myConverterBuffer); + myConverterBuffer.erase(); + } else { + std::string strText(text, len); + myBookReader.addData(strText); + myBookReader.addContentsData(strText); + } + myDontBreakParagraph = false; + } +} + +bool HtmlBookReader::tagHandler(const HtmlTag &tag) { + myConverter->reset(); + + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "ID") { + myBookReader.addHyperlinkLabel(tag.Attributes[i].Value); + break; + } + } + shared_ptr<HtmlTagAction> action = myActionMap[tag.Name]; + if (action.isNull()) { + action = createAction(tag.Name); + myActionMap[tag.Name] = action; + } + action->run(tag); + + return true; +} + +void HtmlBookReader::preformattedCharacterDataHandler(const char *text, std::size_t len, bool convert) { + const char *start = text; + const char *end = text + len; + + int breakType = myFormat.breakType(); + if (breakType & PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE) { + for (const char *ptr = text; ptr != end; ++ptr) { + if (*ptr == '\n') { + mySpaceCounter = 0; + if (start < ptr) { + addConvertedDataToBuffer(start, ptr - start, convert); + } else { + static const std::string SPACE = " "; + myBookReader.addData(SPACE); + } + myBookReader.endParagraph(); + myBookReader.beginParagraph(); + start = ptr + 1; + } else if (mySpaceCounter >= 0) { + if (std::isspace((unsigned char)*ptr)) { + ++mySpaceCounter; + } else { + myBookReader.addFixedHSpace(mySpaceCounter); + mySpaceCounter = -1; + } + } + } + addConvertedDataToBuffer(start, end - start, convert); + } else if (breakType & PlainTextFormat::BREAK_PARAGRAPH_AT_LINE_WITH_INDENT) { + for (const char *ptr = text; ptr != end; ++ptr) { + if (std::isspace((unsigned char)*ptr)) { + if (*ptr == '\n') { + mySpaceCounter = 0; + } else if (mySpaceCounter >= 0) { + ++mySpaceCounter; + } + } else { + if (mySpaceCounter > myFormat.ignoredIndent()) { + if (ptr - start > mySpaceCounter) { + addConvertedDataToBuffer(start, ptr - start - mySpaceCounter, convert); + myBookReader.endParagraph(); + myBookReader.beginParagraph(); + } + start = ptr; + } + mySpaceCounter = -1; + } + } + mySpaceCounter = std::max(mySpaceCounter, 0); + if (end - start > mySpaceCounter) { + addConvertedDataToBuffer(start, end - start - mySpaceCounter, convert); + } + } else if (breakType & PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE) { + for (const char *ptr = start; ptr != end; ++ptr) { + if (std::isspace((unsigned char)*ptr)) { + if (*ptr == '\n') { + ++myBreakCounter; + } + } else { + if (myBreakCounter > 1) { + addConvertedDataToBuffer(start, ptr - start, convert); + myBookReader.endParagraph(); + myBookReader.beginParagraph(); + start = ptr; + } + myBreakCounter = 0; + } + } + addConvertedDataToBuffer(start, end - start, convert); + } +} + +bool HtmlBookReader::characterDataHandler(const char *text, std::size_t len, bool convert) { + if (!myStyleSheetParser.isNull()) { + myStyleSheetParser->parse(text, len); + return true; + } + + if (myIgnoreDataCounter != 0) { + return true; + } + + if (myIsPreformatted) { + preformattedCharacterDataHandler(text, len, convert); + return true; + } + + const char *ptr = text; + const char *end = text + len; + if (!myIsStarted) { + for (; ptr != end; ++ptr) { + if (!std::isspace((unsigned char)*ptr)) { + myIsStarted = true; + break; + } + } + } + if (myIsStarted) { + addConvertedDataToBuffer(ptr, end - ptr, convert); + } + return true; +} + +void HtmlBookReader::startDocumentHandler() { + while (!myListNumStack.empty()) { + myListNumStack.pop(); + } + myConverterBuffer.erase(); + myKindList.clear(); + + myBookReader.reset(); + myBookReader.setMainTextModel(); + myBookReader.pushKind(REGULAR); + myBookReader.beginParagraph(); + myIgnoreDataCounter = 0; + myIsPreformatted = false; + myDontBreakParagraph = false; + for (std::map<std::string,shared_ptr<HtmlTagAction> >::const_iterator it = myActionMap.begin(); it != myActionMap.end(); ++it) { + it->second->reset(); + } + myIsStarted = false; + myIgnoreTitles = false; + + myStyleSheetParser = 0; + + mySpaceCounter = -1; + myBreakCounter = 0; +} + +void HtmlBookReader::endDocumentHandler() { + myBookReader.endParagraph(); +} + +void HtmlBookReader::setFileName(const std::string fileName) { + myFileName = fileName; +} diff --git a/reader/src/formats/html/HtmlBookReader.h b/reader/src/formats/html/HtmlBookReader.h new file mode 100644 index 0000000..c8d4e32 --- /dev/null +++ b/reader/src/formats/html/HtmlBookReader.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLBOOKREADER_H__ +#define __HTMLBOOKREADER_H__ + +#include <stack> + +#include <shared_ptr.h> + +#include "HtmlReader.h" +#include "../../bookmodel/BookReader.h" +#include "../css/StyleSheetTable.h" + +class BookModel; +class PlainTextFormat; +class StyleSheetParser; + +class HtmlTagAction; + +class HtmlBookReader : public HtmlReader { + +public: + HtmlBookReader(const std::string &baseDirectoryPath, BookModel &model, const PlainTextFormat &format, const std::string &encoding); + ~HtmlBookReader(); + void setFileName(const std::string fileName); + +protected: + virtual shared_ptr<HtmlTagAction> createAction(const std::string &tag); + void setBuildTableOfContent(bool build); + void setProcessPreTag(bool process); + +protected: + void startDocumentHandler(); + void endDocumentHandler(); + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + +private: + void preformattedCharacterDataHandler(const char *text, std::size_t len, bool convert); + void addConvertedDataToBuffer(const char *text, std::size_t len, bool convert); + +protected: + BookReader myBookReader; + std::string myBaseDirPath; + +private: + const PlainTextFormat &myFormat; + int myIgnoreDataCounter; + bool myIsPreformatted; + bool myDontBreakParagraph; + + bool myIsStarted; + bool myBuildTableOfContent; + bool myProcessPreTag; + bool myIgnoreTitles; + std::stack<int> myListNumStack; + + StyleSheetTable myStyleSheetTable; + shared_ptr<StyleSheetParser> myStyleSheetParser; + + int mySpaceCounter; + int myBreakCounter; + std::string myConverterBuffer; + + std::map<std::string,shared_ptr<HtmlTagAction> > myActionMap; + std::vector<FBTextKind> myKindList; + + std::string myFileName; + + friend class HtmlTagAction; + friend class HtmlControlTagAction; + friend class HtmlHeaderTagAction; + friend class HtmlIgnoreTagAction; + friend class HtmlHrefTagAction; + friend class HtmlImageTagAction; + friend class HtmlBreakTagAction; + friend class HtmlPreTagAction; + friend class HtmlListTagAction; + friend class HtmlListItemTagAction; + friend class HtmlTableTagAction; + friend class HtmlStyleTagAction; +}; + +#endif /* __HTMLBOOKREADER_H__ */ diff --git a/reader/src/formats/html/HtmlDescriptionReader.cpp b/reader/src/formats/html/HtmlDescriptionReader.cpp new file mode 100644 index 0000000..6ebcb8b --- /dev/null +++ b/reader/src/formats/html/HtmlDescriptionReader.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "HtmlDescriptionReader.h" + +#include "../../library/Book.h" + +HtmlDescriptionReader::HtmlDescriptionReader(Book &book) : HtmlReader(book.encoding()), myBook(book) { + myBook.setTitle(""); +} + +void HtmlDescriptionReader::startDocumentHandler() { + myReadTitle = false; +} + +void HtmlDescriptionReader::endDocumentHandler() { + if (!myBook.title().empty()) { + const char *titleStart = myBook.title().data(); + const char *titleEnd = titleStart + myBook.title().length(); + std::string newTitle; + myConverter->convert(newTitle, titleStart, titleEnd); + myBook.setTitle(newTitle); + } +} + +bool HtmlDescriptionReader::tagHandler(const HtmlTag &tag) { + if (tag.Name == "TITLE") { + if (myReadTitle && !tag.Start) { + myBook.setTitle(myBuffer); + myBuffer.erase(); + } + myReadTitle = tag.Start && myBook.title().empty(); + return true; + } else if (tag.Start && tag.Name == "META") { + std::vector<HtmlAttribute>::const_iterator it = tag.Attributes.begin(); + for (; it != tag.Attributes.end(); ++it) { + if (it->Name == "CONTENT") { + break; + } + } + if (it != tag.Attributes.end()) { + const std::string prefix = "charset="; + std::size_t index = it->Value.find(prefix); + if (index != std::string::npos) { + std::string charset = it->Value.substr(index + prefix.length()); + index = charset.find(';'); + if (index != std::string::npos) { + charset = charset.substr(0, index); + } + index = charset.find(' '); + if (index != std::string::npos) { + charset = charset.substr(0, index); + } + myBook.setEncoding(charset); + } + } + } + return tag.Name != "BODY"; +} + +bool HtmlDescriptionReader::characterDataHandler(const char *text, std::size_t len, bool) { + if (myReadTitle) { + myBuffer.append(text, len); + } + return true; +} diff --git a/reader/src/formats/html/HtmlDescriptionReader.h b/reader/src/formats/html/HtmlDescriptionReader.h new file mode 100644 index 0000000..159d4b0 --- /dev/null +++ b/reader/src/formats/html/HtmlDescriptionReader.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLDESCRIPTIONREADER_H__ +#define __HTMLDESCRIPTIONREADER_H__ + +#include "HtmlReader.h" + +class Book; + +class HtmlDescriptionReader : public HtmlReader { + +public: + HtmlDescriptionReader(Book &book); + ~HtmlDescriptionReader(); + +protected: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + +private: + bool myReadTitle; + std::string myBuffer; + Book &myBook; +}; + +inline HtmlDescriptionReader::~HtmlDescriptionReader() {} + +#endif /* __HTMLDESCRIPTIONREADER_H__ */ diff --git a/reader/src/formats/html/HtmlEntityCollection.cpp b/reader/src/formats/html/HtmlEntityCollection.cpp new file mode 100644 index 0000000..bd1bb4e --- /dev/null +++ b/reader/src/formats/html/HtmlEntityCollection.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <cctype> + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLXMLReader.h> + +#include "HtmlEntityCollection.h" + +class CollectionReader : public ZLXMLReader { + +public: + CollectionReader(std::map<std::string,int> &collection); + void startElementHandler(const char *tag, const char **attributes); + +private: + std::map<std::string,int> &myCollection; +}; + +std::map<std::string,int> HtmlEntityCollection::ourCollection; + +int HtmlEntityCollection::symbolNumber(const std::string &name) { + if (ourCollection.empty()) { + CollectionReader(ourCollection).readDocument(ZLFile( + ZLibrary::ApplicationDirectory() + ZLibrary::FileNameDelimiter + + "formats" + ZLibrary::FileNameDelimiter + + "html" + ZLibrary::FileNameDelimiter + "html.ent" + )); + } + std::map<std::string,int>::const_iterator it = ourCollection.find(name); + return it == ourCollection.end() ? 0 : it->second; +} + +CollectionReader::CollectionReader(std::map<std::string,int> &collection) : myCollection(collection) { +} + +void CollectionReader::startElementHandler(const char *tag, const char **attributes) { + static const std::string ENTITY = "entity"; + + if (ENTITY == tag) { + for (int i = 0; i < 4; ++i) { + if (attributes[i] == 0) { + return; + } + } + static const std::string _name = "name"; + static const std::string _number = "number"; + if (_name == attributes[0] && _number == attributes[2]) { + myCollection[attributes[1]] = std::atoi(attributes[3]); + } + } +} diff --git a/reader/src/formats/html/HtmlEntityCollection.h b/reader/src/formats/html/HtmlEntityCollection.h new file mode 100644 index 0000000..6f70491 --- /dev/null +++ b/reader/src/formats/html/HtmlEntityCollection.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLENTITYCOLLECTION_H__ +#define __HTMLENTITYCOLLECTION_H__ + +#include <string> +#include <map> + +class HtmlEntityCollection { + +public: + static int symbolNumber(const std::string &name); + +private: + static std::map<std::string,int> ourCollection; + +private: + HtmlEntityCollection(); +}; + +#endif /* __HTMLENTITYCOLLECTION_H__ */ diff --git a/reader/src/formats/html/HtmlPlugin.cpp b/reader/src/formats/html/HtmlPlugin.cpp new file mode 100644 index 0000000..279e096 --- /dev/null +++ b/reader/src/formats/html/HtmlPlugin.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "HtmlPlugin.h" +#include "HtmlDescriptionReader.h" +#include "HtmlBookReader.h" +#include "HtmlReaderStream.h" +#include "../txt/PlainTextFormat.h" +#include "../util/MiscUtil.h" +#include "../../library/Book.h" +#include "../../bookmodel/BookModel.h" + +bool HtmlPlugin::acceptsFile(const ZLFile &file) const { + const std::string &extension = file.extension(); + return ZLStringUtil::stringEndsWith(extension, "html") || (extension == "htm"); +} + +bool HtmlPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = book.file().inputStream(); + if (stream.isNull()) { + return false; + } + + shared_ptr<ZLInputStream> htmlStream = new HtmlReaderStream(stream, 50000); + detectEncodingAndLanguage(book, *htmlStream); + if (book.encoding().empty()) { + return false; + } + HtmlDescriptionReader(book).readDocument(*stream); + + return true; +} + +bool HtmlPlugin::readModel(BookModel &model) const { + const Book& book = *model.book(); + const ZLFile &file = book.file(); + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull()) { + return false; + } + + PlainTextFormat format(file); + if (!format.initialized()) { + PlainTextFormatDetector detector; + detector.detect(*stream, format); + } + + std::string directoryPrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + HtmlBookReader reader(directoryPrefix, model, format, book.encoding()); + reader.setFileName(MiscUtil::htmlFileName(file.path())); + reader.readDocument(*stream); + + return true; +} + +FormatInfoPage *HtmlPlugin::createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file) { + return new PlainTextInfoPage(dialog, file, ZLResourceKey("<PRE>"), false); +} + +bool HtmlPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} diff --git a/reader/src/formats/html/HtmlPlugin.h b/reader/src/formats/html/HtmlPlugin.h new file mode 100644 index 0000000..c66a108 --- /dev/null +++ b/reader/src/formats/html/HtmlPlugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLPLUGIN_H__ +#define __HTMLPLUGIN_H__ + +#include "../FormatPlugin.h" + +class HtmlPlugin : public FormatPlugin { + +public: + HtmlPlugin(); + ~HtmlPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); +}; + +inline HtmlPlugin::HtmlPlugin() {} +inline HtmlPlugin::~HtmlPlugin() {} +inline bool HtmlPlugin::providesMetaInfo() const { return false; } + +#endif /* __HTMLPLUGIN_H__ */ diff --git a/reader/src/formats/html/HtmlReader.cpp b/reader/src/formats/html/HtmlReader.cpp new file mode 100644 index 0000000..a5ce7fa --- /dev/null +++ b/reader/src/formats/html/HtmlReader.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> +#include <cctype> + +#include <ZLInputStream.h> +#include <ZLXMLReader.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "HtmlReader.h" +#include "HtmlEntityCollection.h" + +HtmlReader::HtmlReader(const std::string &encoding) : EncodedTextReader(encoding) { +} + +HtmlReader::~HtmlReader() { +} + +void HtmlReader::setTag(HtmlTag &tag, const std::string &name) { + tag.Attributes.clear(); + + if (name.length() == 0) { + tag.Name = name; + return; + } + + tag.Start = name[0] != '/'; + if (tag.Start) { + tag.Name = name; + } else { + tag.Name = name.substr(1); + } + + const std::size_t len = tag.Name.length(); + for (std::size_t i = 0; i < len; ++i) { + tag.Name[i] = std::toupper(tag.Name[i]); + } +} + +enum ParseState { + PS_TEXT, + PS_TAGSTART, + PS_TAGNAME, + PS_WAIT_END_OF_TAG, + PS_ATTRIBUTENAME, + PS_ATTRIBUTEVALUE, + PS_SKIPTAG, + PS_COMMENT, + PS_SPECIAL, + PS_SPECIAL_IN_ATTRIBUTEVALUE, +}; + +enum SpecialType { + ST_UNKNOWN, + ST_NUM, + ST_NAME, + ST_DEC, + ST_HEX +}; + +static bool allowSymbol(SpecialType type, char ch) { + return + (type == ST_NAME && std::isalpha(ch)) || + (type == ST_DEC && std::isdigit(ch)) || + (type == ST_HEX && std::isxdigit(ch)); +} + +static int specialSymbolNumber(SpecialType type, const std::string &txt) { + char *end = 0; + switch (type) { + case ST_NAME: + return HtmlEntityCollection::symbolNumber(txt); + case ST_DEC: + return std::strtol(txt.c_str() + 1, &end, 10); + case ST_HEX: + return std::strtol(txt.c_str() + 2, &end, 16); + default: + return 0; + } +} + +void HtmlReader::appendString(std::string &to, std::string &from) { + if (myConverter.isNull()) { + to += from; + } else { + myConverter->convert(to, from); + myConverter->reset(); + } + from.erase(); +} + +void HtmlReader::readDocument(ZLInputStream &stream) { + if (!stream.open()) { + return; + } + + startDocumentHandler(); + + ParseState state = PS_TEXT; + SpecialType state_special = ST_UNKNOWN; + std::string currentString; + std::string attributeValueString; + std::string specialString; + int quotationCounter = 0; + HtmlTag currentTag; + char endOfComment[2] = "\0"; + + const std::size_t BUFSIZE = 2048; + char *buffer = new char[BUFSIZE]; + std::size_t length; + std::size_t offset = 0; + do { + length = stream.read(buffer, BUFSIZE); + char *start = buffer; + char *endOfBuffer = buffer + length; + for (char *ptr = buffer; ptr < endOfBuffer; ++ptr) { + switch (state) { + case PS_TEXT: + if (*ptr == '<') { + if (!characterDataHandler(start, ptr - start, true)) { + goto endOfProcessing; + } + start = ptr + 1; + state = PS_TAGSTART; + currentTag.Offset = offset + (ptr - buffer); + } + if (*ptr == '&') { + if (!characterDataHandler(start, ptr - start, true)) { + goto endOfProcessing; + } + start = ptr + 1; + state = PS_SPECIAL; + state_special = ST_UNKNOWN; + } + break; + case PS_SPECIAL: + case PS_SPECIAL_IN_ATTRIBUTEVALUE: + if (state_special == ST_UNKNOWN) { + if (*ptr == '#') { + state_special = ST_NUM; + } else if (std::isalpha(*ptr)) { + state_special = ST_NAME; + } else { + start = ptr; + state = (state == PS_SPECIAL) ? PS_TEXT : PS_ATTRIBUTEVALUE; + } + } else if (state_special == ST_NUM) { + if (*ptr == 'x') { + state_special = ST_HEX; + } else if (std::isdigit(*ptr)) { + state_special = ST_DEC; + } else { + start = ptr; + state = (state == PS_SPECIAL) ? PS_TEXT : PS_ATTRIBUTEVALUE; + } + } else { + if (*ptr == ';') { + specialString.append(start, ptr - start); + int number = specialSymbolNumber(state_special, specialString); + if ((128 <= number) && (number <= 159)) { + char ch = number; + if (state == PS_SPECIAL) { + characterDataHandler(&ch, 1, true); + } else { + myConverter->convert(attributeValueString, &ch, &ch + 1); + } + } else if (number != 0) { + char buffer[4]; + int len = ZLUnicodeUtil::ucs4ToUtf8(buffer, number); + if (state == PS_SPECIAL) { + characterDataHandler(buffer, len, false); + } else { + attributeValueString.append(buffer, len); + } + } else { + specialString = "&" + specialString + ";"; + if (state == PS_SPECIAL) { + characterDataHandler(specialString.c_str(), specialString.length(), false); + } else { + attributeValueString += specialString; + } + } + specialString.erase(); + start = ptr + 1; + state = (state == PS_SPECIAL) ? PS_TEXT : PS_ATTRIBUTEVALUE; + } else if (!allowSymbol(state_special, *ptr)) { + start = ptr; + state = (state == PS_SPECIAL) ? PS_TEXT : PS_ATTRIBUTEVALUE; + } + } + break; + case PS_TAGSTART: + state = (*ptr == '!') ? PS_COMMENT : PS_TAGNAME; + break; + case PS_COMMENT: + if ((endOfComment[0] == '\0') && (*ptr != '-')) { + state = PS_TAGNAME; + } else if ((endOfComment[0] == '-') && (endOfComment[1] == '-') && (*ptr == '>')) { + start = ptr + 1; + state = PS_TEXT; + endOfComment[0] = '\0'; + endOfComment[1] = '\0'; + } else { + endOfComment[0] = endOfComment[1]; + endOfComment[1] = *ptr; + } + break; + case PS_WAIT_END_OF_TAG: + if (*ptr == '>') { + start = ptr + 1; + state = PS_TEXT; + } + break; + case PS_TAGNAME: + if (*ptr == '>' || *ptr == '/' || std::isspace((unsigned char)*ptr)) { + currentString.append(start, ptr - start); + start = ptr + 1; + setTag(currentTag, currentString); + currentString.erase(); + if (currentTag.Name == "") { + state = *ptr == '>' ? PS_TEXT : PS_SKIPTAG; + } else { + if (*ptr == '>') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_TEXT; + } else if (*ptr == '/') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + currentTag.Start = false; + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_WAIT_END_OF_TAG; + } else { + state = PS_ATTRIBUTENAME; + } + } + } + break; + case PS_ATTRIBUTENAME: + if (*ptr == '>' || *ptr == '/' || *ptr == '=' || std::isspace((unsigned char)*ptr)) { + if (ptr != start || !currentString.empty()) { + currentString.append(start, ptr - start); + for (unsigned int i = 0; i < currentString.length(); ++i) { + currentString[i] = std::toupper(currentString[i]); + } + currentTag.addAttribute(currentString); + currentString.erase(); + } + start = ptr + 1; + if (*ptr == '>') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_TEXT; + } else if (*ptr == '/') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + currentTag.Start = false; + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_WAIT_END_OF_TAG; + } else { + state = (*ptr == '=') ? PS_ATTRIBUTEVALUE : PS_ATTRIBUTENAME; + } + } + break; + case PS_ATTRIBUTEVALUE: + if (*ptr == '"') { + if (((ptr == start) && currentString.empty()) || (quotationCounter > 0)) { + ++quotationCounter; + } + } else if (*ptr == '&') { + currentString.append(start, ptr - start); + start = ptr + 1; + appendString(attributeValueString, currentString); + state = PS_SPECIAL_IN_ATTRIBUTEVALUE; + state_special = ST_UNKNOWN; + } else if (quotationCounter != 1 && (*ptr == '>' || *ptr == '/' || std::isspace((unsigned char)*ptr))) { + if (ptr != start || !currentString.empty()) { + currentString.append(start, ptr - start); + appendString(attributeValueString, currentString); + if (attributeValueString[0] == '"') { + attributeValueString = attributeValueString.substr(1, attributeValueString.length() - 2); + } + currentTag.setLastAttributeValue(attributeValueString); + attributeValueString.erase(); + quotationCounter = 0; + } + start = ptr + 1; + if (*ptr == '>') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_TEXT; + } else if (*ptr == '/') { + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + currentTag.Start = false; + if (!tagHandler(currentTag)) { + goto endOfProcessing; + } + state = PS_WAIT_END_OF_TAG; + } else { + state = PS_ATTRIBUTENAME; + } + } + break; + case PS_SKIPTAG: + if (*ptr == '>') { + start = ptr + 1; + state = PS_TEXT; + } + break; + } + } + if (start != endOfBuffer) { + switch (state) { + case PS_TEXT: + if (!characterDataHandler(start, endOfBuffer - start, true)) { + goto endOfProcessing; + } + break; + case PS_TAGNAME: + case PS_ATTRIBUTENAME: + case PS_ATTRIBUTEVALUE: + currentString.append(start, endOfBuffer - start); + break; + case PS_SPECIAL: + case PS_SPECIAL_IN_ATTRIBUTEVALUE: + specialString.append(start, endOfBuffer - start); + break; + case PS_TAGSTART: + case PS_SKIPTAG: + case PS_COMMENT: + case PS_WAIT_END_OF_TAG: + break; + } + } + offset += length; + } while (length == BUFSIZE); +endOfProcessing: + delete[] buffer; + + endDocumentHandler(); + + stream.close(); +} diff --git a/reader/src/formats/html/HtmlReader.h b/reader/src/formats/html/HtmlReader.h new file mode 100644 index 0000000..876fad8 --- /dev/null +++ b/reader/src/formats/html/HtmlReader.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLREADER_H__ +#define __HTMLREADER_H__ + +#include <string> +#include <vector> + +#include <ZLEncodingConverter.h> +#include "../EncodedTextReader.h" + +class ZLInputStream; + +class HtmlReader : public EncodedTextReader { + +public: + struct HtmlAttribute { + std::string Name; + std::string Value; + bool HasValue; + + HtmlAttribute(const std::string &name); + ~HtmlAttribute(); + void setValue(const std::string &value); + }; + + struct HtmlTag { + std::string Name; + std::size_t Offset; + bool Start; + std::vector<HtmlAttribute> Attributes; + + HtmlTag(); + ~HtmlTag(); + void addAttribute(const std::string &name); + void setLastAttributeValue(const std::string &value); + + private: + HtmlTag(const HtmlTag&); + const HtmlTag &operator = (const HtmlTag&); + }; + +private: + static void setTag(HtmlTag &tag, const std::string &fullName); + +public: + virtual void readDocument(ZLInputStream &stream); + +protected: + HtmlReader(const std::string &encoding); + virtual ~HtmlReader(); + +protected: + virtual void startDocumentHandler() = 0; + virtual void endDocumentHandler() = 0; + + // returns false iff processing must be stopped + virtual bool tagHandler(const HtmlTag &tag) = 0; + // returns false iff processing must be stopped + virtual bool characterDataHandler(const char *text, std::size_t len, bool convert) = 0; + +private: + void appendString(std::string &to, std::string &from); +}; + +inline HtmlReader::HtmlAttribute::HtmlAttribute(const std::string &name) : Name(name), HasValue(false) {} +inline HtmlReader::HtmlAttribute::~HtmlAttribute() {} +inline void HtmlReader::HtmlAttribute::setValue(const std::string &value) { Value = value; HasValue = true; } + +inline HtmlReader::HtmlTag::HtmlTag() : Start(true) {} +inline HtmlReader::HtmlTag::~HtmlTag() {} +inline void HtmlReader::HtmlTag::addAttribute(const std::string &name) { Attributes.push_back(HtmlAttribute(name)); } +inline void HtmlReader::HtmlTag::setLastAttributeValue(const std::string &value) { if (!Attributes.empty()) Attributes.back().setValue(value); } + +#endif /* __HTMLREADER_H__ */ diff --git a/reader/src/formats/html/HtmlReaderStream.cpp b/reader/src/formats/html/HtmlReaderStream.cpp new file mode 100644 index 0000000..08c43ae --- /dev/null +++ b/reader/src/formats/html/HtmlReaderStream.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <cstring> +#include <algorithm> + +#include "HtmlReaderStream.h" +#include "HtmlReader.h" + +class HtmlTextOnlyReader : public HtmlReader { + +public: + HtmlTextOnlyReader(char *buffer, std::size_t maxSize); + std::size_t size() const; + +private: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + +private: + char *myBuffer; + std::size_t myMaxSize; + std::size_t myFilledSize; + bool myIgnoreText; +}; + +HtmlTextOnlyReader::HtmlTextOnlyReader(char *buffer, std::size_t maxSize) : HtmlReader(std::string()), myBuffer(buffer), myMaxSize(maxSize), myFilledSize(0), myIgnoreText(false) { +} + +std::size_t HtmlTextOnlyReader::size() const { + return myFilledSize; +} + +void HtmlTextOnlyReader::startDocumentHandler() { +} + +void HtmlTextOnlyReader::endDocumentHandler() { +} + +bool HtmlTextOnlyReader::tagHandler(const HtmlTag &tag) { + if (tag.Name == "SCRIPT") { + myIgnoreText = tag.Start; + } + if ((myFilledSize < myMaxSize) && (myFilledSize > 0) && (myBuffer[myFilledSize - 1] != '\n')) { + myBuffer[myFilledSize++] = '\n'; + } + return myFilledSize < myMaxSize; +} + +bool HtmlTextOnlyReader::characterDataHandler(const char *text, std::size_t len, bool) { + if (!myIgnoreText) { + len = std::min((std::size_t)len, myMaxSize - myFilledSize); + std::memcpy(myBuffer + myFilledSize, text, len); + myFilledSize += len; + } + return myFilledSize < myMaxSize; +} + +HtmlReaderStream::HtmlReaderStream(shared_ptr<ZLInputStream> base, std::size_t maxSize) : myBase(base), myBuffer(0), mySize(maxSize) { +} + +HtmlReaderStream::~HtmlReaderStream() { + close(); +} + +bool HtmlReaderStream::open() { + if (myBase.isNull() || !myBase->open()) { + return false; + } + myBuffer = new char[mySize]; + HtmlTextOnlyReader reader(myBuffer, mySize); + reader.readDocument(*myBase); + mySize = reader.size(); + myOffset = 0; + myBase->close(); + return true; +} + +std::size_t HtmlReaderStream::read(char *buffer, std::size_t maxSize) { + maxSize = std::min(maxSize, mySize - myOffset); + if (buffer != 0) { + std::memcpy(buffer, myBuffer, maxSize); + } + myOffset += maxSize; + return maxSize; +} + +void HtmlReaderStream::close() { + if (myBuffer != 0) { + delete[] myBuffer; + myBuffer = 0; + } +} + +void HtmlReaderStream::seek(int offset, bool absoluteOffset) { + if (!absoluteOffset) { + offset += myOffset; + } + myOffset = std::min(mySize, (std::size_t)std::max(0, offset)); +} + +std::size_t HtmlReaderStream::offset() const { + return myOffset; +} + +std::size_t HtmlReaderStream::sizeOfOpened() { + return mySize; +} diff --git a/reader/src/formats/html/HtmlReaderStream.h b/reader/src/formats/html/HtmlReaderStream.h new file mode 100644 index 0000000..c5c15b8 --- /dev/null +++ b/reader/src/formats/html/HtmlReaderStream.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLREADERSTREAM_H__ +#define __HTMLREADERSTREAM_H__ + +#include <shared_ptr.h> +#include <ZLInputStream.h> + +class HtmlReaderStream : public ZLInputStream { + +public: + HtmlReaderStream(shared_ptr<ZLInputStream> base, std::size_t maxSize); + ~HtmlReaderStream(); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + shared_ptr<ZLInputStream> myBase; + char *myBuffer; + std::size_t mySize; + std::size_t myOffset; +}; + +#endif /* __HTMLREADERSTREAM_H__ */ diff --git a/reader/src/formats/html/HtmlTagActions.h b/reader/src/formats/html/HtmlTagActions.h new file mode 100644 index 0000000..7da3f20 --- /dev/null +++ b/reader/src/formats/html/HtmlTagActions.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLTAGACTIONS_H__ +#define __HTMLTAGACTIONS_H__ + +#include <set> + +#include "HtmlBookReader.h" + +class HtmlTagAction { + +protected: + HtmlTagAction(HtmlBookReader &reader); + +public: + virtual ~HtmlTagAction(); + virtual void run(const HtmlReader::HtmlTag &tag) = 0; + virtual void reset(); + +protected: + BookReader &bookReader(); + +protected: + HtmlBookReader &myReader; +}; + +class DummyHtmlTagAction : public HtmlTagAction { + +public: + DummyHtmlTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlControlTagAction : public HtmlTagAction { + +public: + HtmlControlTagAction(HtmlBookReader &reader, FBTextKind kind); + void run(const HtmlReader::HtmlTag &tag); + +private: + FBTextKind myKind; +}; + +class HtmlHeaderTagAction : public HtmlTagAction { + +public: + HtmlHeaderTagAction(HtmlBookReader &reader, FBTextKind kind); + void run(const HtmlReader::HtmlTag &tag); + +private: + FBTextKind myKind; +}; + +class HtmlIgnoreTagAction : public HtmlTagAction { + +public: + HtmlIgnoreTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); + +private: + std::set<std::string> myTagNames; +}; + +class HtmlHrefTagAction : public HtmlTagAction { + +public: + HtmlHrefTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); + void reset(); + +protected: + FBTextKind hyperlinkType() const; + void setHyperlinkType(FBTextKind hyperlinkType); + +private: + FBTextKind myHyperlinkType; +}; + +class HtmlImageTagAction : public HtmlTagAction { + +public: + HtmlImageTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlBreakTagAction : public HtmlTagAction { + +public: + enum BreakType { + BREAK_AT_START = 1, + BREAK_AT_END = 2, + BREAK_AT_START_AND_AT_END = BREAK_AT_START | BREAK_AT_END + }; + HtmlBreakTagAction(HtmlBookReader &reader, BreakType breakType); + void run(const HtmlReader::HtmlTag &tag); + +private: + BreakType myBreakType; +}; + +class HtmlPreTagAction : public HtmlTagAction { + +public: + HtmlPreTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlListTagAction : public HtmlTagAction { + +public: + HtmlListTagAction(HtmlBookReader &reader, int startIndex); + void run(const HtmlReader::HtmlTag &tag); + +private: + int myStartIndex; +}; + +class HtmlListItemTagAction : public HtmlTagAction { + +public: + HtmlListItemTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlTableTagAction : public HtmlTagAction { + +public: + HtmlTableTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class HtmlStyleTagAction : public HtmlTagAction { + +public: + HtmlStyleTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +inline BookReader &HtmlTagAction::bookReader() { return myReader.myBookReader; } + +#endif /* __HTMLTAGACTIONS_H__ */ diff --git a/reader/src/formats/oeb/NCXReader.cpp b/reader/src/formats/oeb/NCXReader.cpp new file mode 100644 index 0000000..e824e16 --- /dev/null +++ b/reader/src/formats/oeb/NCXReader.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include "NCXReader.h" +#include "../util/MiscUtil.h" +#include "../util/EntityFilesCollector.h" + +NCXReader::NCXReader(BookReader &modelReader) : myModelReader(modelReader), myReadState(READ_NONE), myPlayIndex(-65535) { +} + +static const std::string TAG_NAVMAP = "navMap"; +static const std::string TAG_NAVPOINT = "navPoint"; +static const std::string TAG_NAVLABEL = "navLabel"; +static const std::string TAG_CONTENT = "content"; +static const std::string TAG_TEXT = "text"; + +void NCXReader::startElementHandler(const char *fullTag, const char **attributes) { + std::string tag = fullTag; + const std::size_t index = tag.rfind(':'); + if (index != std::string::npos) { + tag = tag.substr(index + 1); + } + switch (myReadState) { + case READ_NONE: + if (TAG_NAVMAP == tag) { + myReadState = READ_MAP; + } + break; + case READ_MAP: + if (TAG_NAVPOINT == tag) { + const char *order = attributeValue(attributes, "playOrder"); + myPointStack.push_back(NavPoint(order != 0 ? std::atoi(order) : myPlayIndex++, myPointStack.size())); + myReadState = READ_POINT; + } + break; + case READ_POINT: + if (TAG_NAVPOINT == tag) { + const char *order = attributeValue(attributes, "playOrder"); + myPointStack.push_back(NavPoint(order != 0 ? std::atoi(order) : myPlayIndex++, myPointStack.size())); + } else if (TAG_NAVLABEL == tag) { + myReadState = READ_LABEL; + } else if (TAG_CONTENT == tag) { + const char *src = attributeValue(attributes, "src"); + if (src != 0) { + myPointStack.back().ContentHRef = MiscUtil::decodeHtmlURL(src); + } + } + break; + case READ_LABEL: + if (TAG_TEXT == tag) { + myReadState = READ_TEXT; + } + break; + case READ_TEXT: + break; + } +} + +void NCXReader::endElementHandler(const char *fullTag) { + std::string tag = fullTag; + const std::size_t index = tag.rfind(':'); + if (index != std::string::npos) { + tag = tag.substr(index + 1); + } + switch (myReadState) { + case READ_NONE: + break; + case READ_MAP: + if (TAG_NAVMAP == tag) { + myReadState = READ_NONE; + } + break; + case READ_POINT: + if (TAG_NAVPOINT == tag) { + if (myPointStack.back().Text.empty()) { + myPointStack.back().Text = "..."; + } + myNavigationMap[myPointStack.back().Order] = myPointStack.back(); + myPointStack.pop_back(); + myReadState = myPointStack.empty() ? READ_MAP : READ_POINT; + } + case READ_LABEL: + if (TAG_NAVLABEL == tag) { + myReadState = READ_POINT; + } + break; + case READ_TEXT: + if (TAG_TEXT == tag) { + myReadState = READ_LABEL; + } + break; + } +} + +void NCXReader::characterDataHandler(const char *text, std::size_t len) { + if (myReadState == READ_TEXT) { + myPointStack.back().Text.append(text, len); + } +} + +const std::vector<std::string> &NCXReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("xhtml"); +} + +const std::map<int,NCXReader::NavPoint> &NCXReader::navigationMap() const { + return myNavigationMap; +} + +NCXReader::NavPoint::NavPoint() { +} + +NCXReader::NavPoint::NavPoint(int order, std::size_t level) : Order(order), Level(level) { +} diff --git a/reader/src/formats/oeb/NCXReader.h b/reader/src/formats/oeb/NCXReader.h new file mode 100644 index 0000000..c10d2ab --- /dev/null +++ b/reader/src/formats/oeb/NCXReader.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NCXREADER_H__ +#define __NCXREADER_H__ + +#include <map> +#include <vector> + +#include <ZLXMLReader.h> + +#include "../../bookmodel/BookReader.h" + +class NCXReader : public ZLXMLReader { + +public: + struct NavPoint { + NavPoint(); + NavPoint(int order, std::size_t level); + + int Order; + std::size_t Level; + std::string Text; + std::string ContentHRef; + }; + +public: + NCXReader(BookReader &modelReader); + const std::map<int,NavPoint> &navigationMap() const; + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + const std::vector<std::string> &externalDTDs() const; + +private: + BookReader &myModelReader; + std::map<int,NavPoint> myNavigationMap; + std::vector<NavPoint> myPointStack; + + enum { + READ_NONE, + READ_MAP, + READ_POINT, + READ_LABEL, + READ_TEXT + } myReadState; + + int myPlayIndex; +}; + +#endif /* __NCXREADER_H__ */ diff --git a/reader/src/formats/oeb/OEBBookReader.cpp b/reader/src/formats/oeb/OEBBookReader.cpp new file mode 100644 index 0000000..c4234a7 --- /dev/null +++ b/reader/src/formats/oeb/OEBBookReader.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLFile.h> +#include <ZLFileImage.h> +#include <ZLXMLNamespace.h> + +#include "OEBBookReader.h" +#include "XHTMLImageFinder.h" +#include "NCXReader.h" +#include "../xhtml/XHTMLReader.h" +#include "../util/MiscUtil.h" +#include "../util/EntityFilesCollector.h" +#include "../../bookmodel/BookModel.h" + +OEBBookReader::OEBBookReader(BookModel &model) : myModelReader(model) { +} + +static const std::string MANIFEST = "manifest"; +static const std::string SPINE = "spine"; +static const std::string GUIDE = "guide"; +static const std::string TOUR = "tour"; +static const std::string SITE = "site"; + +static const std::string ITEM = "item"; +static const std::string ITEMREF = "itemref"; +static const std::string REFERENCE = "reference"; + +static const std::string COVER = "cover"; +static const std::string COVER_IMAGE = "other.ms-coverimage-standard"; + +bool OEBBookReader::isOPFTag(const std::string &expected, const std::string &tag) const { + return expected == tag || testTag(ZLXMLNamespace::OpenPackagingFormat, expected, tag); +} + +void OEBBookReader::startElementHandler(const char *tag, const char **xmlattributes) { + std::string tagString = ZLUnicodeUtil::toLower(tag); + + switch (myState) { + case READ_NONE: + if (isOPFTag(MANIFEST, tagString)) { + myState = READ_MANIFEST; + } else if (isOPFTag(SPINE, tagString)) { + const char *toc = attributeValue(xmlattributes, "toc"); + if (toc != 0) { + myNCXTOCFileName = myIdToHref[toc]; + } + myState = READ_SPINE; + } else if (isOPFTag(GUIDE, tagString)) { + myState = READ_GUIDE; + } else if (isOPFTag(TOUR, tagString)) { + myState = READ_TOUR; + } + break; + case READ_MANIFEST: + if (isOPFTag(ITEM, tagString)) { + const char *href = attributeValue(xmlattributes, "href"); + if (href != 0) { + const std::string sHref = MiscUtil::decodeHtmlURL(href); + const char *id = attributeValue(xmlattributes, "id"); + const char *mediaType = attributeValue(xmlattributes, "media-type"); + if (id != 0) { + myIdToHref[id] = sHref; + } + if (mediaType != 0) { + myHrefToMediatype[sHref] = mediaType; + } + } + } + break; + case READ_SPINE: + if (isOPFTag(ITEMREF, tagString)) { + const char *id = attributeValue(xmlattributes, "idref"); + if (id != 0) { + const std::string &fileName = myIdToHref[id]; + if (!fileName.empty()) { + myHtmlFileNames.push_back(fileName); + } + } + } + break; + case READ_GUIDE: + if (isOPFTag(REFERENCE, tagString)) { + const char *type = attributeValue(xmlattributes, "type"); + const char *title = attributeValue(xmlattributes, "title"); + const char *href = attributeValue(xmlattributes, "href"); + if (href != 0) { + const std::string reference = MiscUtil::decodeHtmlURL(href); + if (title != 0) { + myGuideTOC.push_back(std::make_pair(std::string(title), reference)); + } + if (type != 0) { + if (COVER == type) { + ZLFile imageFile(myFilePrefix + reference); + myCoverFileName = imageFile.path(); + const std::map<std::string,std::string>::const_iterator it = + myHrefToMediatype.find(reference); + const std::string mimeType = + it != myHrefToMediatype.end() ? it->second : std::string(); + shared_ptr<const ZLImage> image; + if (ZLStringUtil::stringStartsWith(mimeType, "image/")) { + image = new ZLFileImage(imageFile, 0); + } else { + image = XHTMLImageFinder().readImage(imageFile); + } + if (!image.isNull()) { + const std::string imageName = imageFile.name(false); + myModelReader.setMainTextModel(); + myModelReader.addImageReference(imageName, 0); + myModelReader.addImage(imageName, image); + myModelReader.insertEndOfSectionParagraph(); + } else { + myCoverFileName.erase(); + } + } else if (COVER_IMAGE == type) { + ZLFile imageFile(myFilePrefix + reference); + myCoverFileName = imageFile.path(); + const std::string imageName = imageFile.name(false); + myModelReader.setMainTextModel(); + myModelReader.addImageReference(imageName, 0); + myModelReader.addImage(imageName, new ZLFileImage(imageFile, 0)); + myModelReader.insertEndOfSectionParagraph(); + } + } + } + } + break; + case READ_TOUR: + if (isOPFTag(SITE, tagString)) { + const char *title = attributeValue(xmlattributes, "title"); + const char *href = attributeValue(xmlattributes, "href"); + if ((title != 0) && (href != 0)) { + myTourTOC.push_back(std::make_pair(title, MiscUtil::decodeHtmlURL(href))); + } + } + break; + } +} + +void OEBBookReader::endElementHandler(const char *tag) { + std::string tagString = ZLUnicodeUtil::toLower(tag); + + switch (myState) { + case READ_MANIFEST: + if (isOPFTag(MANIFEST, tagString)) { + myState = READ_NONE; + } + break; + case READ_SPINE: + if (isOPFTag(SPINE, tagString)) { + myState = READ_NONE; + } + break; + case READ_GUIDE: + if (isOPFTag(GUIDE, tagString)) { + myState = READ_NONE; + } + break; + case READ_TOUR: + if (isOPFTag(TOUR, tagString)) { + myState = READ_NONE; + } + break; + case READ_NONE: + break; + } +} + +bool OEBBookReader::readBook(const ZLFile &file) { + myFilePrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + + myIdToHref.clear(); + myHtmlFileNames.clear(); + myNCXTOCFileName.erase(); + myCoverFileName.erase(); + myTourTOC.clear(); + myGuideTOC.clear(); + myState = READ_NONE; + + if (!readDocument(file)) { + return false; + } + + myModelReader.setMainTextModel(); + myModelReader.pushKind(REGULAR); + + XHTMLReader xhtmlReader(myModelReader); + bool firstFile = true; + for (std::vector<std::string>::const_iterator it = myHtmlFileNames.begin(); it != myHtmlFileNames.end(); ++it) { + const ZLFile xhtmlFile(myFilePrefix + *it); + if (firstFile && myCoverFileName == xhtmlFile.path()) { + continue; + } + if (!firstFile) { + myModelReader.insertEndOfSectionParagraph(); + } + xhtmlReader.readFile(xhtmlFile, *it); + firstFile = false; + } + + generateTOC(xhtmlReader); + + return true; +} + +void OEBBookReader::generateTOC(const XHTMLReader &xhtmlReader) { + if (!myNCXTOCFileName.empty()) { + NCXReader ncxReader(myModelReader); + if (ncxReader.readDocument(ZLFile(myFilePrefix + myNCXTOCFileName))) { + const std::map<int,NCXReader::NavPoint> navigationMap = ncxReader.navigationMap(); + if (!navigationMap.empty()) { + std::size_t level = 0; + for (std::map<int,NCXReader::NavPoint>::const_iterator it = navigationMap.begin(); it != navigationMap.end(); ++it) { + const NCXReader::NavPoint &point = it->second; + int index = myModelReader.model().label(xhtmlReader.normalizedReference(point.ContentHRef)).ParagraphNumber; + while (level > point.Level) { + myModelReader.endContentsParagraph(); + --level; + } + while (++level <= point.Level) { + myModelReader.beginContentsParagraph(-2); + myModelReader.addContentsData("..."); + } + myModelReader.beginContentsParagraph(index); + myModelReader.addContentsData(point.Text); + } + while (level > 0) { + myModelReader.endContentsParagraph(); + --level; + } + return; + } + } + } + + std::vector<std::pair<std::string,std::string> > &toc = myTourTOC.empty() ? myGuideTOC : myTourTOC; + for (std::vector<std::pair<std::string,std::string> >::const_iterator it = toc.begin(); it != toc.end(); ++it) { + int index = myModelReader.model().label(it->second).ParagraphNumber; + if (index != -1) { + myModelReader.beginContentsParagraph(index); + myModelReader.addContentsData(it->first); + myModelReader.endContentsParagraph(); + } + } +} + +bool OEBBookReader::processNamespaces() const { + return true; +} + +const std::vector<std::string> &OEBBookReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("xhtml"); +} diff --git a/reader/src/formats/oeb/OEBBookReader.h b/reader/src/formats/oeb/OEBBookReader.h new file mode 100644 index 0000000..092f269 --- /dev/null +++ b/reader/src/formats/oeb/OEBBookReader.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBBOOKREADER_H__ +#define __OEBBOOKREADER_H__ + +#include <map> +#include <vector> +#include <string> + +#include <ZLXMLReader.h> + +#include "../../bookmodel/BookReader.h" + +class XHTMLReader; + +class OEBBookReader : public ZLXMLReader { + +public: + OEBBookReader(BookModel &model); + bool readBook(const ZLFile &file); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + bool processNamespaces() const; + bool isOPFTag(const std::string &expected, const std::string &tag) const; + const std::vector<std::string> &externalDTDs() const; + + void generateTOC(const XHTMLReader &xhtmlReader); + +private: + enum ReaderState { + READ_NONE, + READ_MANIFEST, + READ_SPINE, + READ_GUIDE, + READ_TOUR + }; + + BookReader myModelReader; + ReaderState myState; + + std::string myFilePrefix; + std::map<std::string,std::string> myIdToHref; + std::map<std::string,std::string> myHrefToMediatype; + std::vector<std::string> myHtmlFileNames; + std::string myNCXTOCFileName; + std::string myCoverFileName; + std::vector<std::pair<std::string,std::string> > myTourTOC; + std::vector<std::pair<std::string,std::string> > myGuideTOC; +}; + +#endif /* __OEBBOOKREADER_H__ */ diff --git a/reader/src/formats/oeb/OEBCoverReader.cpp b/reader/src/formats/oeb/OEBCoverReader.cpp new file mode 100644 index 0000000..842de30 --- /dev/null +++ b/reader/src/formats/oeb/OEBCoverReader.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLFileImage.h> +#include <ZLXMLNamespace.h> + +#include "OEBCoverReader.h" +#include "XHTMLImageFinder.h" + +#include "../util/MiscUtil.h" + +OEBCoverReader::OEBCoverReader() { +} + +shared_ptr<const ZLImage> OEBCoverReader::readCover(const ZLFile &file) { + myPathPrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + myReadState = READ_NOTHING; + myImage.reset(); + myCoverXHTML.erase(); + readDocument(file); + if (myImage.isNull() && !myCoverXHTML.empty()) { + const ZLFile coverFile(myCoverXHTML); + const std::string ext = coverFile.extension(); + if (ext == "gif" || ext == "jpeg" || ext == "jpg") { + myImage = new ZLFileImage(coverFile, 0); + } else { + myImage = XHTMLImageFinder().readImage(coverFile); + } + } + return myImage; +} + +static const std::string METADATA = "metadata"; +static const std::string META = "meta"; +static const std::string MANIFEST = "manifest"; +static const std::string ITEM = "item"; +static const std::string GUIDE = "guide"; +static const std::string REFERENCE = "reference"; +static const std::string COVER = "cover"; +static const std::string COVER_IMAGE = "other.ms-coverimage-standard"; + +bool OEBCoverReader::processNamespaces() const { + return true; +} + +void OEBCoverReader::startElementHandler(const char *tag, const char **attributes) { + switch (myReadState) { + case READ_NOTHING: + if (GUIDE == tag) { + myReadState = READ_GUIDE; + } else if (MANIFEST == tag && !myCoverId.empty()) { + myReadState = READ_MANIFEST; + } else if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tag)) { + myReadState = READ_METADATA; + } + break; + case READ_GUIDE: + if (REFERENCE == tag) { + const char *type = attributeValue(attributes, "type"); + if (type != 0) { + if (COVER == type) { + const char *href = attributeValue(attributes, "href"); + if (href != 0) { + myCoverXHTML = myPathPrefix + MiscUtil::decodeHtmlURL(href); + interrupt(); + } + } else if (COVER_IMAGE == type) { + createImage(attributeValue(attributes, "href")); + } + } + } + break; + case READ_METADATA: + if (testTag(ZLXMLNamespace::OpenPackagingFormat, META, tag)) { + const char *name = attributeValue(attributes, "name"); + if (name != 0 && COVER == name) { + myCoverId = attributeValue(attributes, "content"); + } + } + break; + case READ_MANIFEST: + if (ITEM == tag) { + const char *id = attributeValue(attributes, "id"); + if (id != 0 && myCoverId == id) { + createImage(attributeValue(attributes, "href")); + } + } + break; + } +} + +void OEBCoverReader::createImage(const char *href) { + if (href != 0) { + myImage = new ZLFileImage(ZLFile(myPathPrefix + MiscUtil::decodeHtmlURL(href)), 0); + interrupt(); + } +} + +void OEBCoverReader::endElementHandler(const char *tag) { + switch (myReadState) { + case READ_NOTHING: + break; + case READ_GUIDE: + if (GUIDE == tag) { + myReadState = READ_NOTHING; + } + break; + case READ_METADATA: + if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tag)) { + myReadState = READ_NOTHING; + } + break; + case READ_MANIFEST: + if (MANIFEST == tag) { + myReadState = READ_NOTHING; + } + break; + } +} diff --git a/reader/src/formats/oeb/OEBCoverReader.h b/reader/src/formats/oeb/OEBCoverReader.h new file mode 100644 index 0000000..e1f96b5 --- /dev/null +++ b/reader/src/formats/oeb/OEBCoverReader.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBCOVERREADER_H__ +#define __OEBCOVERREADER_H__ + +#include <vector> + +#include <shared_ptr.h> +#include <ZLXMLReader.h> + +class ZLImage; + +class OEBCoverReader : public ZLXMLReader { + +public: + OEBCoverReader(); + shared_ptr<const ZLImage> readCover(const ZLFile &file); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + bool processNamespaces() const; + + void createImage(const char *href); + +private: + shared_ptr<const ZLImage> myImage; + std::string myPathPrefix; + std::string myCoverXHTML; + std::string myCoverId; + enum { + READ_NOTHING, + READ_METADATA, + READ_MANIFEST, + READ_GUIDE + } myReadState; +}; + +#endif /* __OEBCOVERREADER_H__ */ diff --git a/reader/src/formats/oeb/OEBMetaInfoReader.cpp b/reader/src/formats/oeb/OEBMetaInfoReader.cpp new file mode 100644 index 0000000..f9eb82d --- /dev/null +++ b/reader/src/formats/oeb/OEBMetaInfoReader.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLLogger.h> +#include <ZLXMLNamespace.h> + +#include "OEBMetaInfoReader.h" +#include "../util/EntityFilesCollector.h" + +#include "../../library/Book.h" + +OEBMetaInfoReader::OEBMetaInfoReader(Book &book) : myBook(book) { + myBook.removeAllAuthors(); + myBook.setTitle(""); + myBook.removeAllTags(); +} + +static const std::string METADATA = "metadata"; +static const std::string DC_METADATA = "dc-metadata"; +static const std::string META = "meta"; +static const std::string AUTHOR_ROLE = "aut"; + +void OEBMetaInfoReader::characterDataHandler(const char *text, std::size_t len) { + switch (myReadState) { + case READ_NONE: + case READ_METADATA: + break; + case READ_AUTHOR: + case READ_AUTHOR2: + case READ_SUBJECT: + case READ_LANGUAGE: + case READ_TITLE: + myBuffer.append(text, len); + break; + } +} + +bool OEBMetaInfoReader::testDCTag(const std::string &name, const std::string &tag) const { + return + testTag(ZLXMLNamespace::DublinCore, name, tag) || + testTag(ZLXMLNamespace::DublinCoreLegacy, name, tag); +} + +bool OEBMetaInfoReader::isNSName(const std::string &fullName, const std::string &shortName, const std::string &fullNSId) const { + const int prefixLength = fullName.length() - shortName.length() - 1; + if (prefixLength <= 0 || + fullName[prefixLength] != ':' || + !ZLStringUtil::stringEndsWith(fullName, shortName)) { + return false; + } + const std::map<std::string,std::string> &namespaceMap = namespaces(); + std::map<std::string,std::string>::const_iterator iter = + namespaceMap.find(fullName.substr(0, prefixLength)); + return iter != namespaceMap.end() && iter->second == fullNSId; +} + +void OEBMetaInfoReader::startElementHandler(const char *tag, const char **attributes) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + switch (myReadState) { + default: + break; + case READ_NONE: + if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tagString) || + DC_METADATA == tagString) { + myReadState = READ_METADATA; + } + break; + case READ_METADATA: + if (testDCTag("title", tagString)) { + myReadState = READ_TITLE; + } else if (testDCTag("creator", tagString)) { + const char *role = attributeValue(attributes, "role"); + if (role == 0) { + myReadState = READ_AUTHOR2; + } else if (AUTHOR_ROLE == role) { + myReadState = READ_AUTHOR; + } + } else if (testDCTag("subject", tagString)) { + myReadState = READ_SUBJECT; + } else if (testDCTag("language", tagString)) { + myReadState = READ_LANGUAGE; + } else if (testTag(ZLXMLNamespace::OpenPackagingFormat, META, tagString)) { + const char *name = attributeValue(attributes, "name"); + const char *content = attributeValue(attributes, "content"); + if (name != 0 && content != 0) { + std::string sName = name; + if (sName == "calibre:series" || isNSName(sName, "series", ZLXMLNamespace::CalibreMetadata)) { + myBook.setSeries(content, myBook.indexInSeries()); + } else if (sName == "calibre:series_index" || isNSName(sName, "series_index", ZLXMLNamespace::CalibreMetadata)) { + myBook.setSeries(myBook.seriesTitle(), std::string(content)); + } + } + } + break; + } +} + +void OEBMetaInfoReader::endElementHandler(const char *tag) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + ZLUnicodeUtil::utf8Trim(myBuffer); + switch (myReadState) { + case READ_NONE: + break; + case READ_METADATA: + if (testTag(ZLXMLNamespace::OpenPackagingFormat, METADATA, tagString) || DC_METADATA == tagString) { + interrupt(); + myReadState = READ_NONE; + return; + } + break; + case READ_AUTHOR: + if (!myBuffer.empty()) { + myAuthorList.push_back(myBuffer); + } + break; + case READ_AUTHOR2: + if (!myBuffer.empty()) { + myAuthorList2.push_back(myBuffer); + } + break; + case READ_SUBJECT: + if (!myBuffer.empty()) { + myBook.addTag(myBuffer); + } + break; + case READ_TITLE: + if (!myBuffer.empty()) { + myBook.setTitle(myBuffer); + } + break; + case READ_LANGUAGE: + if (!myBuffer.empty()) { + int index = myBuffer.find('-'); + if (index >= 0) { + myBuffer = myBuffer.substr(0, index); + } + index = myBuffer.find('_'); + if (index >= 0) { + myBuffer = myBuffer.substr(0, index); + } + myBook.setLanguage(myBuffer); + } + break; + } + myBuffer.erase(); + myReadState = READ_METADATA; +} + +bool OEBMetaInfoReader::processNamespaces() const { + return true; +} + +bool OEBMetaInfoReader::readMetaInfo(const ZLFile &file) { + myReadState = READ_NONE; + if (!readDocument(file)) { + ZLLogger::Instance().println("epub", "Failure while reading info from " + file.path()); + return false; + } + + if (!myAuthorList.empty()) { + for (std::vector<std::string>::const_iterator it = myAuthorList.begin(); it != myAuthorList.end(); ++it) { + myBook.addAuthor(*it); + } + } else { + for (std::vector<std::string>::const_iterator it = myAuthorList2.begin(); it != myAuthorList2.end(); ++it) { + myBook.addAuthor(*it); + } + } + return true; +} + +const std::vector<std::string> &OEBMetaInfoReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("xhtml"); +} diff --git a/reader/src/formats/oeb/OEBMetaInfoReader.h b/reader/src/formats/oeb/OEBMetaInfoReader.h new file mode 100644 index 0000000..2337c50 --- /dev/null +++ b/reader/src/formats/oeb/OEBMetaInfoReader.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBMETAINFOREADER_H__ +#define __OEBMETAINFOREADER_H__ + +#include <vector> + +#include <ZLXMLReader.h> + +class Book; + +class OEBMetaInfoReader : public ZLXMLReader { + +public: + OEBMetaInfoReader(Book &book); + bool readMetaInfo(const ZLFile &file); + + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + bool processNamespaces() const; + const std::vector<std::string> &externalDTDs() const; + +private: + bool testDCTag(const std::string &name, const std::string &tag) const; + bool isNSName(const std::string &fullName, const std::string &shortName, const std::string &fullNSId) const; + +private: + Book &myBook; + + enum { + READ_NONE, + READ_METADATA, + READ_AUTHOR, + READ_AUTHOR2, + READ_TITLE, + READ_SUBJECT, + READ_LANGUAGE, + } myReadState; + + std::string myBuffer; + std::vector<std::string> myAuthorList; + std::vector<std::string> myAuthorList2; +}; + +#endif /* __OEBMETAINFOREADER_H__ */ diff --git a/reader/src/formats/oeb/OEBPlugin.cpp b/reader/src/formats/oeb/OEBPlugin.cpp new file mode 100644 index 0000000..96970c1 --- /dev/null +++ b/reader/src/formats/oeb/OEBPlugin.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLImage.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLDir.h> +#include <ZLInputStream.h> +#include <ZLLogger.h> +#include <ZLMimeType.h> + +#include "OEBPlugin.h" +#include "OEBMetaInfoReader.h" +#include "OEBBookReader.h" +#include "OEBCoverReader.h" +#include "OEBTextStream.h" +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +static const std::string OPF = "opf"; +static const std::string OEBZIP = "oebzip"; +static const std::string EPUB = "epub"; + +class ContainerFileReader : public ZLXMLReader { + +public: + const std::string &rootPath() const; + +private: + void startElementHandler(const char *tag, const char **attributes); + +private: + std::string myRootPath; +}; + +const std::string &ContainerFileReader::rootPath() const { + return myRootPath; +} + +void ContainerFileReader::startElementHandler(const char *tag, const char **attributes) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (tagString == "rootfile") { + const char *path = attributeValue(attributes, "full-path"); + if (path != 0) { + myRootPath = path; + interrupt(); + } + } +} + +OEBPlugin::~OEBPlugin() { +} + +bool OEBPlugin::providesMetaInfo() const { + return true; +} + +bool OEBPlugin::acceptsFile(const ZLFile &file) const { + shared_ptr<ZLMimeType> mimeType = file.mimeType(); + const std::string &extension = file.extension(); + if (!mimeType.isNull() && mimeType != ZLMimeType::EMPTY) { + return + mimeType == ZLMimeType::APPLICATION_EPUB_ZIP || + (mimeType == ZLMimeType::APPLICATION_XML && extension == OPF) || + (mimeType == ZLMimeType::APPLICATION_ZIP && extension == OEBZIP); + } + return extension == OPF || extension == OEBZIP || extension == EPUB; +} + +ZLFile OEBPlugin::opfFile(const ZLFile &oebFile) { + //ZLLogger::Instance().registerClass("epub"); + + if (oebFile.extension() == OPF) { + return oebFile; + } + + ZLLogger::Instance().println("epub", "Looking for opf file in " + oebFile.path()); + + shared_ptr<ZLDir> oebDir = oebFile.directory(); + if (!oebDir.isNull()) { + const ZLFile containerInfoFile(oebDir->itemPath("META-INF/container.xml")); + if (containerInfoFile.exists()) { + ZLLogger::Instance().println("epub", "Found container file " + containerInfoFile.path()); + ContainerFileReader reader; + reader.readDocument(containerInfoFile); + const std::string &opfPath = reader.rootPath(); + ZLLogger::Instance().println("epub", "opf path = " + opfPath); + if (!opfPath.empty()) { + return ZLFile(oebDir->itemPath(opfPath)); + } + } + } + + oebFile.forceArchiveType(ZLFile::ZIP); + shared_ptr<ZLDir> zipDir = oebFile.directory(false); + if (zipDir.isNull()) { + ZLLogger::Instance().println("epub", "Couldn't open zip archive"); + return ZLFile::NO_FILE; + } + std::vector<std::string> fileNames; + zipDir->collectFiles(fileNames, false); + for (std::vector<std::string>::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) { + ZLLogger::Instance().println("epub", "Item: " + *it); + if (ZLStringUtil::stringEndsWith(*it, ".opf")) { + return ZLFile(zipDir->itemPath(*it)); + } + } + ZLLogger::Instance().println("epub", "Opf file not found"); + return ZLFile::NO_FILE; +} + +bool OEBPlugin::readMetaInfo(Book &book) const { + const ZLFile &file = book.file(); + return OEBMetaInfoReader(book).readMetaInfo(opfFile(file)); +} + +bool OEBPlugin::readModel(BookModel &model) const { + const ZLFile &file = model.book()->file(); + return OEBBookReader(model).readBook(opfFile(file)); +} + +shared_ptr<const ZLImage> OEBPlugin::coverImage(const ZLFile &file) const { + return OEBCoverReader().readCover(opfFile(file)); +} + +bool OEBPlugin::readLanguageAndEncoding(Book &book) const { + if (book.language().empty()) { + shared_ptr<ZLInputStream> oebStream = new OEBTextStream(opfFile(book.file())); + detectLanguage(book, *oebStream, book.encoding()); + } + return true; +} diff --git a/reader/src/formats/oeb/OEBPlugin.h b/reader/src/formats/oeb/OEBPlugin.h new file mode 100644 index 0000000..a515208 --- /dev/null +++ b/reader/src/formats/oeb/OEBPlugin.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBPLUGIN_H__ +#define __OEBPLUGIN_H__ + +#include "../FormatPlugin.h" + +class OEBPlugin : public FormatPlugin { + +public: + static ZLFile opfFile(const ZLFile &oebFile); + +public: + ~OEBPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + shared_ptr<const ZLImage> coverImage(const ZLFile &file) const; +}; + +#endif /* __OEBPLUGIN_H__ */ diff --git a/reader/src/formats/oeb/OEBTextStream.cpp b/reader/src/formats/oeb/OEBTextStream.cpp new file mode 100644 index 0000000..4dbfa47 --- /dev/null +++ b/reader/src/formats/oeb/OEBTextStream.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <map> + +#include <ZLFile.h> +#include <ZLXMLReader.h> +#include <ZLUnicodeUtil.h> + +#include "OEBTextStream.h" +#include "../util/MiscUtil.h" +#include "../util/XMLTextStream.h" + +class XHTMLFilesCollector : public ZLXMLReader { + +public: + XHTMLFilesCollector(std::vector<std::string> &xhtmlFileNames); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + +private: + std::vector<std::string> &myXHTMLFileNames; + std::map<std::string,std::string> myIdToHref; + enum { + READ_NONE, + READ_MANIFEST, + READ_SPINE + } myState; +}; + +XHTMLFilesCollector::XHTMLFilesCollector(std::vector<std::string> &xhtmlFileNames) : myXHTMLFileNames(xhtmlFileNames), myState(READ_NONE) { +} + +static const std::string MANIFEST = "manifest"; +static const std::string SPINE = "spine"; +static const std::string ITEM = "item"; +static const std::string ITEMREF = "itemref"; + +void XHTMLFilesCollector::startElementHandler(const char *tag, const char **xmlattributes) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (MANIFEST == tagString) { + myState = READ_MANIFEST; + } else if (SPINE == tagString) { + myState = READ_SPINE; + } else if ((myState == READ_MANIFEST) && (ITEM == tagString)) { + const char *id = attributeValue(xmlattributes, "id"); + const char *href = attributeValue(xmlattributes, "href"); + if ((id != 0) && (href != 0)) { + myIdToHref[id] = href; + } + } else if ((myState == READ_SPINE) && (ITEMREF == tagString)) { + const char *id = attributeValue(xmlattributes, "idref"); + if (id != 0) { + const std::string &fileName = myIdToHref[id]; + if (!fileName.empty()) { + myXHTMLFileNames.push_back(fileName); + } + } + } +} + +void XHTMLFilesCollector::endElementHandler(const char *tag) { + if (SPINE == ZLUnicodeUtil::toLower(tag)) { + interrupt(); + } +} + +OEBTextStream::OEBTextStream(const ZLFile &opfFile) { + myFilePrefix = MiscUtil::htmlDirectoryPrefix(opfFile.path()); + XHTMLFilesCollector(myXHTMLFileNames).readDocument(opfFile); +} + +void OEBTextStream::resetToStart() { + myIndex = 0; +} + +shared_ptr<ZLInputStream> OEBTextStream::nextStream() { + if (myIndex >= myXHTMLFileNames.size()) { + return 0; + } + ZLFile xhtmlFile(myFilePrefix + myXHTMLFileNames[myIndex++]); + return new XMLTextStream(xhtmlFile.inputStream(), "body"); +} diff --git a/reader/src/formats/oeb/OEBTextStream.h b/reader/src/formats/oeb/OEBTextStream.h new file mode 100644 index 0000000..6ddd2c9 --- /dev/null +++ b/reader/src/formats/oeb/OEBTextStream.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBTEXTSTREAM_H__ +#define __OEBTEXTSTREAM_H__ + +#include <vector> +#include <string> + +#include "../util/MergedStream.h" + +class OEBTextStream : public MergedStream { + +public: + OEBTextStream(const ZLFile &opfFile); + +private: + void resetToStart(); + shared_ptr<ZLInputStream> nextStream(); + +private: + std::string myFilePrefix; + std::vector<std::string> myXHTMLFileNames; + std::size_t myIndex; +}; + +#endif /* __OEBTEXTSTREAM_H__ */ diff --git a/reader/src/formats/oeb/XHTMLImageFinder.cpp b/reader/src/formats/oeb/XHTMLImageFinder.cpp new file mode 100644 index 0000000..6a449c9 --- /dev/null +++ b/reader/src/formats/oeb/XHTMLImageFinder.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLFileImage.h> +#include <ZLXMLNamespace.h> + +#include "XHTMLImageFinder.h" +#include "../util/MiscUtil.h" + +static const std::string TAG_IMG = "img"; +static const std::string TAG_IMAGE = "image"; + +shared_ptr<const ZLImage> XHTMLImageFinder::readImage(const ZLFile &file) { + myImage.reset(); + myPathPrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + readDocument(file); + return myImage; +} + +bool XHTMLImageFinder::processNamespaces() const { + return true; +} + +void XHTMLImageFinder::startElementHandler(const char *tag, const char **attributes) { + const char *reference = 0; + if (TAG_IMG == tag) { + reference = attributeValue(attributes, "src"); + } else if (TAG_IMAGE == tag) { + reference = attributeValue( + attributes, NamespaceAttributeNamePredicate(ZLXMLNamespace::XLink, "href") + ); + } + if (reference != 0) { + myImage = new ZLFileImage(ZLFile(myPathPrefix + reference), 0); + interrupt(); + } +} diff --git a/reader/src/formats/oeb/XHTMLImageFinder.h b/reader/src/formats/oeb/XHTMLImageFinder.h new file mode 100644 index 0000000..28e53f2 --- /dev/null +++ b/reader/src/formats/oeb/XHTMLImageFinder.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __XHTMLIMAGEFINDER_H__ +#define __XHTMLIMAGEFINDER_H__ + +#include <shared_ptr.h> +#include <ZLXMLReader.h> + +class ZLFile; +class ZLImage; + +class XHTMLImageFinder : public ZLXMLReader { + +public: + shared_ptr<const ZLImage> readImage(const ZLFile &file); + +private: + bool processNamespaces() const; + void startElementHandler(const char *tag, const char **attributes); + +private: + std::string myPathPrefix; + shared_ptr<const ZLImage> myImage; +}; + +#endif /* __XHTMLIMAGEFINDER_H__ */ diff --git a/reader/src/formats/openreader/ORBookReader.cpp b/reader/src/formats/openreader/ORBookReader.cpp new file mode 100644 index 0000000..d494b7f --- /dev/null +++ b/reader/src/formats/openreader/ORBookReader.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cstdlib> +#include <algorithm> + +#include <ZLUnicodeUtil.h> +#include <ZLFileImage.h> + +#include "ORBookReader.h" +#include "../xhtml/XHTMLReader.h" +#include "../util/MiscUtil.h" +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +ORBookReader::ORBookReader(BookModel &model) : myModelReader(model) { +} + +void ORBookReader::characterDataHandler(const char *data, std::size_t len) { + if (myState == READ_TOCTITLE) { + myTOCTitle.append(data, len); + } +} + +static const std::string TAG_RESOURCES = "resources"; +static const std::string TAG_USERSET = "userset"; +static const std::string TAG_NAVIGATION = "primarynav"; + +static const std::string TAG_SPINE = "spine"; +static const std::string TAG_COVER = "cover"; + +static const std::string TAG_ITEM = "item"; +static const std::string TAG_ITEMREF = "itemref"; +static const std::string TAG_POINTER = "pointer"; +static const std::string TAG_TITLE = "title"; + +static const std::string xhtmlMediaType = "application/x-orp-bcd1+xml"; + +void ORBookReader::startElementHandler(const char *tag, const char **xmlattributes) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (TAG_RESOURCES == tagString) { + myState = READ_RESOURCES; + } else if (TAG_USERSET == tagString) { + myState = READ_USERSET; + } else if ((myState == READ_RESOURCES) && (TAG_ITEM == tagString)) { + const char *resid = attributeValue(xmlattributes, "resid"); + const char *resource = attributeValue(xmlattributes, "resource"); + shared_ptr<ZLMimeType> mediaType = ZLMimeType::get(attributeValue(xmlattributes, "media-type")); + if ((resid != 0) && (resource != 0)) { + myResources[resid] = resource; + if (!mediaType.isNull() && mediaType != ZLMimeType::EMPTY) { + if (ZLMimeType::APPLICATION_OR_XML == mediaType) { + myHtmlFileIDs.insert(resid); + } else if (ZLMimeType::isImage(mediaType)) { + myImageIDs[resid] = mediaType; + } + } + } + } else if (myState == READ_USERSET) { + if (TAG_NAVIGATION == tagString) { + myState = READ_NAVIGATION; + } else if (TAG_SPINE == tagString) { + const char *residrefs = attributeValue(xmlattributes, "residrefs"); + if (residrefs != 0) { + while (1) { + const char *nextSpace = std::strchr(residrefs, ' '); + if (nextSpace == 0) { + if (*residrefs != '\0') { + myHtmlFilesOrder.push_back(residrefs); + } + break; + } + if (nextSpace != residrefs) { + myHtmlFilesOrder.push_back(std::string(residrefs, nextSpace - residrefs)); + } + residrefs = nextSpace + 1; + } + } + } else if (TAG_COVER == tagString) { + const char *residrefs = attributeValue(xmlattributes, "residrefs"); + if (residrefs != 0) { + myCoverReference = residrefs; + } + } + } else if (myState == READ_NAVIGATION && TAG_POINTER == tagString) { + const char *ref = attributeValue(xmlattributes, "elemrefs"); + const char *level = attributeValue(xmlattributes, "level"); + if (ref != 0 && level != 0) { + myTOCReference = ref; + myTOCLevel = std::atoi(level); + myState = READ_POINTER; + } + } else if (myState == READ_POINTER && TAG_TITLE == tagString) { + myState = READ_TOCTITLE; + } +} + +void ORBookReader::endElementHandler(const char *tag) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (TAG_RESOURCES == tagString || TAG_USERSET == tagString) { + myState = READ_NONE; + } else if (myState == READ_NAVIGATION && TAG_NAVIGATION == tagString) { + myState = READ_USERSET; + } else if (myState == READ_POINTER && TAG_POINTER == tagString) { + myState = READ_NAVIGATION; + } else if (myState == READ_TOCTITLE && TAG_TITLE == tagString) { + myTOC.push_back(TOCItem(myTOCReference, myTOCTitle, myTOCLevel)); + myTOCTitle.erase(); + myState = READ_POINTER; + } +} + +bool ORBookReader::readBook() { + const ZLFile &file = myModelReader.model().book()->file(); + myFilePrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + + myResources.clear(); + myCoverReference.erase(); + myHtmlFileIDs.clear(); + myImageIDs.clear(); + myHtmlFilesOrder.clear(); + myTOC.clear(); + myState = READ_NONE; + + if (!readDocument(file)) { + return false; + } + + myModelReader.setMainTextModel(); + myModelReader.pushKind(REGULAR); + + if (!myCoverReference.empty()) { + myModelReader.addImageReference(myCoverReference); + } + + for (std::vector<std::string>::const_iterator it = myHtmlFilesOrder.begin(); it != myHtmlFilesOrder.end(); ++it) { + myHtmlFileIDs.erase(*it); + XHTMLReader(myModelReader).readFile(ZLFile(myFilePrefix + myResources[*it]), *it); + } + + int level = 1; + for (std::vector<TOCItem>::const_iterator it = myTOC.begin(); it != myTOC.end(); ++it) { + int index = myModelReader.model().label(it->Reference).ParagraphNumber; + if (index != -1) { + for (; level > it->Level; --level) { + myModelReader.endContentsParagraph(); + } + ++level; + myModelReader.beginContentsParagraph(index); + myModelReader.addContentsData(it->Text); + } + } + for (; level > 1; --level) { + myModelReader.endContentsParagraph(); + } + + for (std::set<std::string>::const_iterator it = myHtmlFileIDs.begin(); it != myHtmlFileIDs.end(); ++it) { + myModelReader.setFootnoteTextModel(*it); + myModelReader.pushKind(REGULAR); + XHTMLReader(myModelReader).readFile(ZLFile(myFilePrefix + myResources[*it]), *it); + } + + for (std::map<std::string,shared_ptr<ZLMimeType> >::const_iterator it = myImageIDs.begin(); it != myImageIDs.end(); ++it) { + myModelReader.addImage(it->first, new ZLFileImage(ZLFile(myFilePrefix + myResources[it->first], it->second), 0)); + } + + return true; +} diff --git a/reader/src/formats/openreader/ORBookReader.h b/reader/src/formats/openreader/ORBookReader.h new file mode 100644 index 0000000..160c9f1 --- /dev/null +++ b/reader/src/formats/openreader/ORBookReader.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ORBOOKREADER_H__ +#define __ORBOOKREADER_H__ + +#include <map> +#include <set> +#include <vector> +#include <string> + +#include <ZLXMLReader.h> + +#include "../../bookmodel/BookReader.h" + +class ORBookReader : public ZLXMLReader { + +public: + ORBookReader(BookModel &model); + bool readBook(); + + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + enum ReaderState { + READ_NONE, + READ_RESOURCES, + READ_USERSET, + READ_NAVIGATION, + READ_POINTER, + READ_TOCTITLE + }; + + BookReader myModelReader; + ReaderState myState; + + std::string myFilePrefix; + std::map<std::string,std::string> myResources; + std::string myCoverReference; + std::set<std::string> myHtmlFileIDs; + std::map<std::string,shared_ptr<ZLMimeType> > myImageIDs; + std::vector<std::string> myHtmlFilesOrder; + + struct TOCItem { + TOCItem(const std::string &reference, const std::string &text, int level) : Reference(reference), Text(text), Level(level) { + } + + std::string Reference; + std::string Text; + int Level; + }; + std::vector<TOCItem> myTOC; + + std::string myTOCReference; + int myTOCLevel; + std::string myTOCTitle; +}; + +#endif /* __ORBOOKREADER_H__ */ diff --git a/reader/src/formats/openreader/ORDescriptionReader.cpp b/reader/src/formats/openreader/ORDescriptionReader.cpp new file mode 100644 index 0000000..8c80dfa --- /dev/null +++ b/reader/src/formats/openreader/ORDescriptionReader.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "ORDescriptionReader.h" + +#include "../util/EntityFilesCollector.h" +#include "../../library/Book.h" + +ORDescriptionReader::ORDescriptionReader(Book &book) : myBook(book) { + myBook.removeAllAuthors(); + myBook.setTitle(""); +} + +// TODO: replace "dc" by real DC scheme name +static const std::string METADATA = "metadata"; +static const std::string TITLE = "dc:title"; +static const std::string AUTHOR_TAG = "dc:creator"; +static const std::string AUTHOR_ROLE = "aut"; + +void ORDescriptionReader::characterDataHandler(const char *text, std::size_t len) { + switch (myReadState) { + case READ_NONE: + break; + case READ_AUTHOR: + myCurrentAuthor.append(text, len); + break; + case READ_TITLE: + myBook.setTitle(myBook.title() + std::string(text, len)); + break; + } +} + +void ORDescriptionReader::startElementHandler(const char *tag, const char **attributes) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (METADATA == tagString) { + myReadMetaData = true; + } else if (myReadMetaData) { + if (TITLE == tagString) { + myReadState = READ_TITLE; + } else if (AUTHOR_TAG == tagString) { + const char *role = attributeValue(attributes, "role"); + if ((role != 0) && (AUTHOR_ROLE == role)) { + myReadState = READ_AUTHOR; + } + } + } +} + +void ORDescriptionReader::endElementHandler(const char *tag) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (METADATA == tagString) { + interrupt(); + } else { + if (!myCurrentAuthor.empty()) { + myBook.addAuthor(myCurrentAuthor); + myCurrentAuthor.erase(); + } + myReadState = READ_NONE; + } +} + +bool ORDescriptionReader::readMetaInfo() { + myReadMetaData = false; + myReadState = READ_NONE; + return readDocument(myBook.file()); +} + +const std::vector<std::string> &ORDescriptionReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("xhtml"); +} diff --git a/reader/src/formats/openreader/ORDescriptionReader.h b/reader/src/formats/openreader/ORDescriptionReader.h new file mode 100644 index 0000000..a4f6b2a --- /dev/null +++ b/reader/src/formats/openreader/ORDescriptionReader.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ORDESCRIPTIONREADER_H__ +#define __ORDESCRIPTIONREADER_H__ + +#include <ZLXMLReader.h> + +class Book; + +class ORDescriptionReader : public ZLXMLReader { + +public: + ORDescriptionReader(Book &book); + bool readMetaInfo(); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + + const std::vector<std::string> &externalDTDs() const; + +private: + Book &myBook; + + bool myReadMetaData; + enum { + READ_NONE, + READ_AUTHOR, + READ_TITLE + } myReadState; + + std::string myCurrentAuthor; +}; + +#endif /* __ORDESCRIPTIONREADER_H__ */ diff --git a/reader/src/formats/openreader/OpenReaderPlugin.cpp b/reader/src/formats/openreader/OpenReaderPlugin.cpp new file mode 100644 index 0000000..545f83b --- /dev/null +++ b/reader/src/formats/openreader/OpenReaderPlugin.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLDir.h> + +#include "OpenReaderPlugin.h" +#include "ORDescriptionReader.h" +#include "ORBookReader.h" + +#include "../../library/Book.h" + +OpenReaderPlugin::~OpenReaderPlugin() { +} + +bool OpenReaderPlugin::providesMetaInfo() const { + return true; +} + +bool OpenReaderPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "orb"; +} + +bool OpenReaderPlugin::readMetaInfo(Book &book) const { + return ORDescriptionReader(book).readMetaInfo(); +} + +bool OpenReaderPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +bool OpenReaderPlugin::readModel(BookModel &model) const { + return ORBookReader(model).readBook(); +} diff --git a/reader/src/formats/openreader/OpenReaderPlugin.h b/reader/src/formats/openreader/OpenReaderPlugin.h new file mode 100644 index 0000000..fcfaa11 --- /dev/null +++ b/reader/src/formats/openreader/OpenReaderPlugin.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPENREADERPLUGIN_H__ +#define __OPENREADERPLUGIN_H__ + +#include "../FormatPlugin.h" + +class OpenReaderPlugin : public FormatPlugin { + +public: + ~OpenReaderPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +#endif /* __OPENREADERPLUGIN_H__ */ diff --git a/reader/src/formats/pdb/BitReader.cpp b/reader/src/formats/pdb/BitReader.cpp new file mode 100644 index 0000000..551aaf3 --- /dev/null +++ b/reader/src/formats/pdb/BitReader.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <string> + +#include "BitReader.h" + +BitReader::BitReader(const unsigned char* data, std::size_t size) : myOffset(0), myLength(size * 8) { + myData = new unsigned char[size + 4]; + std::memcpy(myData, data, size); + std::memset(myData + size, 0x00, 4); +} + +BitReader::~BitReader() { + delete[] myData; +} + +unsigned long long BitReader::peek(std::size_t n) { + if (n > 32) { + return 0; + } + unsigned long long r = 0; + std::size_t g = 0; + while (g < n) { + r = (r << 8) | myData[(myOffset + g) >> 3]; + g = g + 8 - ((myOffset+g) & 7); + } + unsigned long long mask = 1; + mask = (mask << n) - 1; + return (r >> (g - n)) & mask; +} + +bool BitReader::eat(std::size_t n) { + myOffset += n; + return myOffset <= myLength; +} + +std::size_t BitReader::left() const { + return myLength - myOffset; +} diff --git a/reader/src/formats/pdb/BitReader.h b/reader/src/formats/pdb/BitReader.h new file mode 100644 index 0000000..a8a3d2d --- /dev/null +++ b/reader/src/formats/pdb/BitReader.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BITREADER_H__ +#define __BITREADER_H__ + +class BitReader { + +public: + BitReader(const unsigned char* data, std::size_t size); + ~BitReader(); + + unsigned long long peek(std::size_t n); + bool eat(std::size_t n); + std::size_t left() const; + +private: + unsigned char* myData; + std::size_t myOffset; + std::size_t myLength; +}; + +#endif //__BITREADER_H__ diff --git a/reader/src/formats/pdb/DocDecompressor.cpp b/reader/src/formats/pdb/DocDecompressor.cpp new file mode 100644 index 0000000..9175bc9 --- /dev/null +++ b/reader/src/formats/pdb/DocDecompressor.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLInputStream.h> + +#include "DocDecompressor.h" + +static unsigned char TOKEN_CODE[256] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; + +std::size_t DocDecompressor::decompress(ZLInputStream &stream, char *targetBuffer, std::size_t compressedSize, std::size_t maxUncompressedSize) { + const unsigned char *sourceBuffer = new unsigned char[compressedSize]; + const unsigned char *sourceBufferEnd = sourceBuffer + compressedSize; + const unsigned char *sourcePtr = sourceBuffer; + + unsigned char *targetBufferEnd = (unsigned char*)targetBuffer + maxUncompressedSize; + unsigned char *targetPtr = (unsigned char*)targetBuffer; + + if (stream.read((char*)sourceBuffer, compressedSize) == compressedSize) { + unsigned char token; + unsigned short copyLength, N, shift; + unsigned char *shifted; + + while ((sourcePtr < sourceBufferEnd) && (targetPtr < targetBufferEnd)) { + token = *(sourcePtr++); + switch (TOKEN_CODE[token]) { + case 0: + *(targetPtr++) = token; + break; + case 1: + if ((sourcePtr + token > sourceBufferEnd) || (targetPtr + token > targetBufferEnd)) { + goto endOfLoop; + } + std::memcpy(targetPtr, sourcePtr, token); + sourcePtr += token; + targetPtr += token; + break; + case 2: + if (targetPtr + 2 > targetBufferEnd) { + goto endOfLoop; + } + *(targetPtr++) = ' '; + *(targetPtr++) = token ^ 0x80; + break; + case 3: + if (sourcePtr + 1 > sourceBufferEnd) { + goto endOfLoop; + } + N = 256 * token + *(sourcePtr++); + copyLength = (N & 7) + 3; + if (targetPtr + copyLength > targetBufferEnd) { + goto endOfLoop; + } + shift = (N & 0x3fff) / 8; + shifted = targetPtr - shift; + if ((char*)shifted >= targetBuffer) { + for (short i = 0; i < copyLength; i++) { + *(targetPtr++) = *(shifted++); + } + } + break; + } + } + } +endOfLoop: + + delete[] sourceBuffer; + return targetPtr - (unsigned char*)targetBuffer; +} diff --git a/reader/src/formats/pdb/DocDecompressor.h b/reader/src/formats/pdb/DocDecompressor.h new file mode 100644 index 0000000..820bb0a --- /dev/null +++ b/reader/src/formats/pdb/DocDecompressor.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __DOCDECOMPRESSOR_H__ +#define __DOCDECOMPRESSOR_H__ + +#include <string> + +class ZLInputStream; + +class DocDecompressor { + +public: + DocDecompressor() {} + ~DocDecompressor() {} + + std::size_t decompress(ZLInputStream &stream, char *buffer, std::size_t compressedSize, std::size_t maxUncompressedSize); +}; + +#endif /* __DOCDECOMPRESSOR_H__ */ diff --git a/reader/src/formats/pdb/EReaderPlugin.cpp b/reader/src/formats/pdb/EReaderPlugin.cpp new file mode 100644 index 0000000..8420c7f --- /dev/null +++ b/reader/src/formats/pdb/EReaderPlugin.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> +#include <ZLEncodingConverter.h> +#include <ZLStringUtil.h> +#include <ZLLanguageUtil.h> +#include <ZLFileImage.h> + +#include "PdbPlugin.h" +#include "EReaderStream.h" +#include "PmlBookReader.h" + +#include "../../library/Book.h" + +bool EReaderPlugin::providesMetaInfo() const { + return true; +} + +bool EReaderPlugin::acceptsFile(const ZLFile &file) const { + return PdbPlugin::fileType(file) == "PNRdPPrs"; +} + +void EReaderPlugin::readDocumentInternal(const ZLFile &file, BookModel &model, const PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const { + if (!stream.open()) { + //TODO maybe anything else opens stream + return; + } + BookReader bookReader(model); + PmlBookReader pmlBookReader(bookReader, format, encoding); + bookReader.setMainTextModel(); + pmlBookReader.readDocument(stream); + EReaderStream &estream = (EReaderStream&)stream; + const std::map<std::string, EReaderStream::ImageInfo>& imageIds = estream.images(); + for(std::map<std::string, EReaderStream::ImageInfo>::const_iterator it = imageIds.begin(); it != imageIds.end(); ++it) { + const std::string id = it->first; + bookReader.addImage(id, new ZLFileImage(ZLFile(file.path(), it->second.Type), it->second.Offset, it->second.Size)); + } + const std::map<std::string, unsigned short>& footnoteIds = estream.footnotes(); + for(std::map<std::string, unsigned short>::const_iterator it = footnoteIds.begin(); it != footnoteIds.end(); ++it) { + const std::string id = it->first; + if (estream.switchStreamDestination(EReaderStream::FOOTNOTE, id)) { + bookReader.setFootnoteTextModel(id); + bookReader.addHyperlinkLabel(id); + pmlBookReader.readDocument(estream); + } + } + stream.close(); +} + +shared_ptr<ZLInputStream> EReaderPlugin::createStream(const ZLFile &file) const { + return new EReaderStream(file); +} + +const std::string &EReaderPlugin::tryOpen(const ZLFile &file) const { + EReaderStream stream(file); + stream.open(); + return stream.error(); +} + +bool EReaderPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = book.file().inputStream(); + if (stream.isNull() || ! stream->open()) { + return false; + } + PdbHeader header; + if (!header.read(stream)) { + return false; + } + stream->seek(header.Offsets[0] + 46, true); + unsigned short metaInfoOffset; + PdbUtil::readUnsignedShort(*stream, metaInfoOffset); + if (metaInfoOffset == 0 || metaInfoOffset >= header.Offsets.size()) { + return false; + } + std::size_t currentOffset = header.Offsets[metaInfoOffset]; + std::size_t nextOffset = + (metaInfoOffset + 1 < (unsigned short)header.Offsets.size()) ? + header.Offsets[metaInfoOffset + 1] : stream->sizeOfOpened(); + if (nextOffset <= currentOffset) { + return false; + } + std::size_t length = nextOffset - currentOffset; + + char* metaInfoBuffer = new char[length]; + stream->seek(currentOffset, true); + stream->read(metaInfoBuffer, length); + std::string metaInfoStr(metaInfoBuffer, length); + delete[] metaInfoBuffer; + + std::string metaInfoData[5]; // Title; Author; Rights; Publisher; isbn; + for (std::size_t i = 0; i < 5; ++i) { + const std::size_t index = metaInfoStr.find('\0'); + metaInfoData[i] = metaInfoStr.substr(0,index); + metaInfoStr = metaInfoStr.substr(index + 1); + } + + if (!metaInfoData[0].empty()) { + book.setTitle(metaInfoData[0]); + } + + if (!metaInfoData[1].empty()) { + book.addAuthor(metaInfoData[1]); + } + + stream->close(); + return SimplePdbPlugin::readMetaInfo(book); +} diff --git a/reader/src/formats/pdb/EReaderStream.cpp b/reader/src/formats/pdb/EReaderStream.cpp new file mode 100644 index 0000000..9775773 --- /dev/null +++ b/reader/src/formats/pdb/EReaderStream.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> +#include <cctype> + +#include <ZLFile.h> +#include <ZLResource.h> +#include <ZLZDecompressor.h> + +#include "EReaderStream.h" +#include "DocDecompressor.h" + + +EReaderStream::EReaderStream(const ZLFile &file) : PalmDocLikeStream(file) { + myDestination = TEXT; +} + +EReaderStream::~EReaderStream() { + close(); +} + +bool EReaderStream::switchStreamDestination(StreamDestination destination, const std::string& id) { + bool result = true; + switch(destination) { + case TEXT: + myDestination = TEXT; + myRecordIndex = 1; + break; + case FOOTNOTE: + std::map<std::string, unsigned short>::const_iterator footnoteIt = myFootnotes.find(id); + if (footnoteIt != myFootnotes.end()) { + myDestination = FOOTNOTE; + myRecordIndex = footnoteIt->second; + } else { + result = false; + } + break; + } + return result; +} + +bool EReaderStream::fillBuffer() { + if (myDestination == TEXT) { + return PalmDocLikeStream::fillBuffer(); + } else { + while (myBufferOffset == myBufferLength) { + if (!processRecord()) { + return false; + } + } + return true; + } +} + +bool EReaderStream::processRecord() { + const std::size_t currentOffset = recordOffset(myRecordIndex); + if (currentOffset < myBase->offset()) { + return false; + } + myBase->seek(currentOffset, true); + const std::size_t nextOffset = recordOffset(myRecordIndex + 1); + if (nextOffset < currentOffset) { + return false; + } + + unsigned short myCompressedSize = nextOffset - currentOffset; + + switch (myCompressionVersion) { + case 10: // Inflate compression + myBase->seek(2, false); + myBufferLength = ZLZDecompressor(myCompressedSize - 2).decompress(*myBase, myBuffer, myMaxRecordSize); + break; + case 2: // PalmDoc compression + myBufferLength = DocDecompressor().decompress(*myBase, myBuffer, myCompressedSize, myMaxRecordSize); + break; + } + clearBuffer('\0'); + myBufferOffset = 0; + return true; +} + +bool EReaderStream::processZeroRecord() { + // Use it with offset presetting to zero record offset value + PdbUtil::readUnsignedShort(*myBase, myCompressionVersion); // myBase offset: ^ + 2 + if (myCompressionVersion > 255) { + myErrorCode = ERROR_ENCRYPTION; + return false; + } else { + switch (myCompressionVersion) { + case 2: + case 10: + break; + default: + myErrorCode = ERROR_COMPRESSION; + return false; + } + } + myBase->seek(10, false); // myBase offset: ^ + 12 + PdbUtil::readUnsignedShort(*myBase, myNonTextOffset); // myBase offset: ^ + 14 + PdbUtil::readUnsignedShort(*myBase, myNonTextOffsetReserved); // myBase offset: ^ + 16 + myBase->seek(12, false); // myBase offset: ^ + 28 + PdbUtil::readUnsignedShort(*myBase, myFootnoteRecords); // myBase offset: ^ + 30 + PdbUtil::readUnsignedShort(*myBase, mySidebarRecords); // myBase offset: ^ + 32 + PdbUtil::readUnsignedShort(*myBase, myBookmarksOffset); // myBase offset: ^ + 34 + myBase->seek(2, false); // myBase offset: ^ + 36 + PdbUtil::readUnsignedShort(*myBase, myNonTextOffsetExtraReserved); // myBase offset: ^ + 38 + myBase->seek(2, false); // myBase offset: ^ + 40 + PdbUtil::readUnsignedShort(*myBase, myImagedataOffset); // myBase offset: ^ + 42 + PdbUtil::readUnsignedShort(*myBase, myImagedataOffsetReserved); // myBase offset: ^ + 44 + PdbUtil::readUnsignedShort(*myBase, myMetadataOffset); // myBase offset: ^ + 46 + PdbUtil::readUnsignedShort(*myBase, myMetadataOffsetReserved); // myBase offset: ^ + 48 + PdbUtil::readUnsignedShort(*myBase, myFootnoteOffset); // myBase offset: ^ + 50 + PdbUtil::readUnsignedShort(*myBase, mySidebarOffset); // myBase offset: ^ + 52 + PdbUtil::readUnsignedShort(*myBase, myLastdataOffset); // myBase offset: ^ + 54 + + unsigned short endSectionIndex = header().Offsets.size(); + myMaxRecordIndex = std::min((unsigned short) (myNonTextOffset - 1), (unsigned short) (endSectionIndex - 1)); + + myMaxRecordSize = 65535; // Maximum size of addressable space in PalmOS + // not more than 8192 bytes happens in the tested examples + + if (myFootnoteRecords) { + bool isSuccess = processFootnoteIdsRecord(); + if (!isSuccess) { + //TODO take in account returned bool value + //false if wrong footnotes amount anounced in zero record + //or corrupted or wrong footnote ids record + } + } + + if (myImagedataOffset != myMetadataOffset) { + bool isSuccess = processImageHeaders(); + if (!isSuccess) { + //TODO take in account returned bool value + //false if one of image record is corrupted + } + } + + myBase->seek(header().Offsets[1], true); + + /* + std::cerr << "EReaderStream::processZeroRecord():\n"; + std::cerr << "PDB header indentificator : " << header().Id << "\n"; + std::cerr << "PDB file system: sizeof opened : " << myBaseSize << "\n"; + std::cerr << "PDB header/record[0] max index : " << myMaxRecordIndex << "\n"; + std::cerr << "PDB record[0][0..2] compression : " << myCompressionVersion << "\n"; + std::cerr << "EReader record[0] myNonTextOffset : " << myNonTextOffset << std::endl; + std::cerr << "EReader record[0] myNonTextOffset2 : " << myNonTextOffsetReserved << std::endl; + std::cerr << "EReader record[0] myFootnoteRecords : " << myFootnoteRecords << std::endl; + std::cerr << "EReader record[0] mySidebarRecords : " << mySidebarRecords << std::endl; + std::cerr << "EReader record[0] myBookmarksOffset : " << myBookmarksOffset << std::endl; + std::cerr << "EReader record[0] myNonTextOffset3 : " << myNonTextOffsetExtraReserved << std::endl; + std::cerr << "EReader record[0] myImagedataOffset : " << myImagedataOffset << std::endl; + std::cerr << "EReader record[0] myImagedataOffset2 : " << myImagedataOffsetReserved << std::endl; + std::cerr << "EReader record[0] myMetadataOffset : " << myMetadataOffset << std::endl; + std::cerr << "EReader record[0] myMetadataOffset2 : " << myMetadataOffsetReserved << std::endl; + std::cerr << "EReader record[0] myFootnoteOffset : " << myFootnoteOffset << std::endl; + std::cerr << "EReader record[0] mySidebarOffset : " << mySidebarOffset << std::endl; + std::cerr << "EReader record[0] myLastdataOffset : " << myLastdataOffset << std::endl; + std::cerr << "PDB header lastSectionIndex : " << endSectionIndex - 1 << "\n"; + */ + return true; +} + +void EReaderStream::clearBuffer(unsigned char symbol) { + myBufferLength = std::remove(myBuffer, myBuffer + myBufferLength, symbol) - myBuffer; +} + +bool EReaderStream::processFootnoteIdsRecord() { + char* footnoteIdBuffer = new char[myMaxRecordSize]; + myBase->seek(header().Offsets[myFootnoteOffset], true); + const std::size_t currentOffset = recordOffset(myFootnoteOffset); + const std::size_t nextOffset = recordOffset(myFootnoteOffset + 1); + const std::size_t length = nextOffset - currentOffset; + myBase->read(footnoteIdBuffer, length); + std::string footnoteIdStr(footnoteIdBuffer, length); + unsigned short footnoteIndex = myFootnoteOffset + 1; + while (!footnoteIdStr.empty() && (footnoteIndex < myLastdataOffset)) { + std::string id = findFootnoteId(footnoteIdStr); + if (!id.empty()) { + myFootnotes[id] = footnoteIndex; + ++footnoteIndex; + } + } + delete[] footnoteIdBuffer; + return (myFootnoteRecords - 1 == (unsigned short)myFootnotes.size()); +} + +std::string EReaderStream::findFootnoteId(std::string &footnoteIdStr) const { + std::string resultStr; + if (!footnoteIdStr.empty()) { + std::size_t counter = 0; + for (; counter < footnoteIdStr.length(); ++counter) { + if (std::isalnum(footnoteIdStr[counter])) { + break; + } + } + const std::size_t startIdIndex = counter; + for (; counter < footnoteIdStr.length(); ++counter) { + if (footnoteIdStr[counter] == '\0') { + break; + } + } + const std::size_t endIdIndex = counter; + resultStr = footnoteIdStr.substr(startIdIndex, endIdIndex - startIdIndex); + footnoteIdStr = footnoteIdStr.substr(endIdIndex); + } + return resultStr; +} + +const std::map<std::string, unsigned short>& EReaderStream::footnotes() const { + return myFootnotes; +} + +bool EReaderStream::processImageHeaders() { + unsigned short recordIndex = myImagedataOffset; + bool result = true; + myBase->seek(header().Offsets[recordIndex], true); + while (recordIndex < myMetadataOffset && recordIndex < myLastdataOffset) { + result = result && addImageInfo(recordIndex); + ++recordIndex; + } + return result; +} + +bool EReaderStream::addImageInfo(const unsigned short recordIndex) { + const std::size_t bufferLength = 128; + char *buffer = new char[bufferLength]; //TODO may be it's needed here more bytes + ImageInfo image; + const std::size_t currentOffset = recordOffset(recordIndex); + const std::size_t nextOffset = recordOffset(recordIndex + 1); + + myBase->read(buffer, bufferLength); + std::string header(buffer, bufferLength); + delete[] buffer; + + image.Offset = currentOffset + header.find("\x89PNG"); //TODO treat situation when there isn't PNG in first 128 bytes + image.Size = nextOffset - image.Offset; + const int endType = header.find(' '); + image.Type = ZLMimeType::get(header.substr(0, endType)); + header = header.substr(endType + 1); + const int endId = header.find('\0'); + const std::string id = header.substr(0, endId); + myBase->seek(nextOffset - currentOffset - bufferLength, false); + if (id.empty()) { + return false; + } + myImages[id] = image; + return true; +} + + +/*bool EReaderStream::hasExtraSections() const { + return false; + //return myMaxRecordIndex < header().Offsets.size() - 1; +}*/ + +EReaderStream::ImageInfo EReaderStream::imageLocation(const std::string& id) { + if (myImagedataOffset != myMetadataOffset && myImages.empty()) { + processImageHeaders(); + } + const std::map<std::string, ImageInfo>::const_iterator it = myImages.find(id); + if (it != myImages.end()) { + return it->second; + } else { + return ImageInfo(); + } +} + +const std::map<std::string, EReaderStream::ImageInfo>& EReaderStream::images() const { + return myImages; +} diff --git a/reader/src/formats/pdb/EReaderStream.h b/reader/src/formats/pdb/EReaderStream.h new file mode 100644 index 0000000..990c6ba --- /dev/null +++ b/reader/src/formats/pdb/EReaderStream.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __EREADERSTREAM_H__ +#define __EREADERSTREAM_H__ + +#include <map> + +#include "PalmDocLikeStream.h" +#include <ZLMimeType.h> + +class ZLFile; + +class EReaderStream : public PalmDocLikeStream { + +public: + EReaderStream(const ZLFile &file); + ~EReaderStream(); + + enum StreamDestination { + TEXT, + FOOTNOTE, + }; + + struct ImageInfo { + unsigned long Offset; + unsigned short Size; + shared_ptr<ZLMimeType> Type; + }; + + ImageInfo imageLocation(const std::string& id); + //bool hasExtraSections() const; + bool switchStreamDestination(StreamDestination destination, const std::string &footnoteId); + const std::map<std::string, unsigned short>& footnotes() const; + const std::map<std::string, ImageInfo>& images() const; + +private: + bool processRecord(); + bool processZeroRecord(); + bool processFootnoteIdsRecord(); + bool processImageHeaders(); + + void clearBuffer(unsigned char symbol); + std::string findFootnoteId(std::string &footnoteIdStr) const; + bool addImageInfo(const unsigned short recordIndex); + + bool fillBuffer(); + +private: + unsigned short myCompressionVersion; + unsigned short myNonTextOffset; + unsigned short myNonTextOffsetReserved; //TODO: Warning: isn't used + unsigned short myFootnoteRecords; + unsigned short mySidebarRecords; + unsigned short myBookmarksOffset; + unsigned short myNonTextOffsetExtraReserved; //TODO: Warning: isn't used + unsigned short myImagedataOffset; + unsigned short myImagedataOffsetReserved; //TODO: Warning: isn't used + unsigned short myMetadataOffset; + unsigned short myMetadataOffsetReserved; //TODO: Warning: isn't used + unsigned short myFootnoteOffset; + unsigned short mySidebarOffset; + unsigned short myLastdataOffset; + + + StreamDestination myDestination; + std::map<std::string, unsigned short> myFootnotes; + std::map<std::string, ImageInfo> myImages; + +}; + +#endif /* __EREADERSTREAM_H__ */ diff --git a/reader/src/formats/pdb/HtmlMetainfoReader.cpp b/reader/src/formats/pdb/HtmlMetainfoReader.cpp new file mode 100644 index 0000000..8829591 --- /dev/null +++ b/reader/src/formats/pdb/HtmlMetainfoReader.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "HtmlMetainfoReader.h" + +#include "../../library/Book.h" + +HtmlMetainfoReader::HtmlMetainfoReader(Book &book, ReadType readType) : + HtmlReader(book.encoding()), myBook(book), myReadType(readType) { +} + +bool HtmlMetainfoReader::tagHandler(const HtmlReader::HtmlTag &tag) { + if (tag.Name == "BODY") { + return false; + } else if (((myReadType & TAGS) == TAGS) && (tag.Name == "DC:SUBJECT")) { + myReadTags = tag.Start; + if (!tag.Start && !myBuffer.empty()) { + myBook.addTag(myBuffer); + myBuffer.erase(); + } + } else if (((myReadType & TITLE) == TITLE) && (tag.Name == "DC:TITLE")) { + myReadTitle = tag.Start; + if (!tag.Start && !myBuffer.empty()) { + myBook.setTitle(myBuffer); + myBuffer.erase(); + } + } else if (((myReadType & AUTHOR) == AUTHOR) && (tag.Name == "DC:CREATOR")) { + if (tag.Start) { + bool flag = false; + for (std::size_t i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "ROLE") { + flag = ZLUnicodeUtil::toUpper(tag.Attributes[i].Value) == "AUT"; + break; + } + } + if (flag) { + if (!myBuffer.empty()) { + myBuffer += ", "; + } + myReadAuthor = true; + } + } else { + myReadAuthor = false; + if (!myBuffer.empty()) { + myBook.addAuthor(myBuffer); + } + myBuffer.erase(); + } + } + return true; +} + +void HtmlMetainfoReader::startDocumentHandler() { + myReadAuthor = false; + myReadTitle = false; + myReadTags = false; +} + +void HtmlMetainfoReader::endDocumentHandler() { +} + +bool HtmlMetainfoReader::characterDataHandler(const char *text, std::size_t len, bool convert) { + if (myReadTitle || myReadAuthor || myReadTags) { + if (convert) { + myConverter->convert(myBuffer, text, text + len); + } else { + myBuffer.append(text, len); + } + } + return true; +} diff --git a/reader/src/formats/pdb/HtmlMetainfoReader.h b/reader/src/formats/pdb/HtmlMetainfoReader.h new file mode 100644 index 0000000..119c72e --- /dev/null +++ b/reader/src/formats/pdb/HtmlMetainfoReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLMETAINFOREADER_H__ +#define __HTMLMETAINFOREADER_H__ + +#include "../html/HtmlReader.h" + +class Book; + +class HtmlMetainfoReader : public HtmlReader { + +public: + enum ReadType { + NONE = 0, + TITLE = 1, + AUTHOR = 2, + TITLE_AND_AUTHOR = TITLE | AUTHOR, + TAGS = 4, + ALL = TITLE | AUTHOR | TAGS + }; + +public: + HtmlMetainfoReader(Book &book, ReadType readType); + +private: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + +private: + Book &myBook; + const ReadType myReadType; + + bool myReadTitle; + bool myReadAuthor; + bool myReadTags; + + std::string myBuffer; +}; + +#endif /* __HTMLMETAINFOREADER_H__ */ diff --git a/reader/src/formats/pdb/HuffDecompressor.cpp b/reader/src/formats/pdb/HuffDecompressor.cpp new file mode 100644 index 0000000..9b6f285 --- /dev/null +++ b/reader/src/formats/pdb/HuffDecompressor.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLInputStream.h> + +#include "PdbReader.h" +#include "BitReader.h" +#include "HuffDecompressor.h" + +HuffDecompressor::HuffDecompressor(ZLInputStream& stream, + const std::vector<unsigned long>::const_iterator beginIt, + const std::vector<unsigned long>::const_iterator endIt, + const unsigned long endHuffDataOffset, const unsigned long extraFlags) : myExtraFlags(extraFlags), myErrorCode(ERROR_NONE) { + + + const unsigned long huffHeaderOffset = *beginIt; + const unsigned long huffRecordsNumber = endIt - beginIt; + const unsigned long huffDataOffset = *(beginIt + 1); + + stream.seek(huffHeaderOffset, true); + stream.seek(16, false); + unsigned long cacheTableOffset, baseTableOffset; + PdbUtil::readUnsignedLongBE(stream, cacheTableOffset); + PdbUtil::readUnsignedLongBE(stream, baseTableOffset); + + + myCacheTable = new unsigned long[256]; + stream.seek(huffHeaderOffset + cacheTableOffset, true); + for (std::size_t i = 0; i < 256; ++i) { + PdbUtil::readUnsignedLongLE(stream, myCacheTable[i]); //LE + } + + myBaseTable = new unsigned long[64]; + stream.seek(huffHeaderOffset + baseTableOffset, true); + for (std::size_t i = 0; i < 64; ++i) { + PdbUtil::readUnsignedLongLE(stream, myBaseTable[i]); //LE + } + + stream.seek(huffDataOffset + 12, true); + PdbUtil::readUnsignedLongBE(stream, myEntryBits); + + std::size_t huffDataSize = endHuffDataOffset - huffDataOffset; + myData = new unsigned char[huffDataSize]; + stream.seek(huffDataOffset, true); + if (huffDataSize == stream.read((char*)myData, huffDataSize)) { + myDicts = new unsigned char* [huffRecordsNumber - 1]; + for(std::size_t i = 0; i < huffRecordsNumber - 1; ++i) { + std::size_t shift = *(beginIt + i + 1) - huffDataOffset; + myDicts[i] = myData + shift; + } + } else { + myErrorCode = ERROR_CORRUPTED_FILE; + } + + myTargetBuffer = 0; + myTargetBufferEnd = 0; + myTargetBufferPtr = 0; +} + +HuffDecompressor::~HuffDecompressor() { + delete[] myCacheTable; + delete[] myBaseTable; + delete[] myData; + delete[] myDicts; +} + +bool HuffDecompressor::error() const { + return myErrorCode == ERROR_CORRUPTED_FILE; +} + +std::size_t HuffDecompressor::decompress(ZLInputStream &stream, char *targetBuffer, std::size_t compressedSize, std::size_t maxUncompressedSize) { + if ((compressedSize == 0) || (myErrorCode == ERROR_CORRUPTED_FILE)) { + return 0; + } + if (targetBuffer != 0) { + unsigned char *sourceBuffer = new unsigned char[compressedSize]; + myTargetBuffer = targetBuffer; + myTargetBufferEnd = targetBuffer + maxUncompressedSize; + myTargetBufferPtr = targetBuffer; + if (stream.read((char*)sourceBuffer, compressedSize) == compressedSize) { + std::size_t trailSize = sizeOfTrailingEntries(sourceBuffer, compressedSize); + if (trailSize < compressedSize) { + bitsDecompress(BitReader(sourceBuffer, compressedSize - trailSize)); + } else { + myErrorCode = ERROR_CORRUPTED_FILE; + } + } + delete[] sourceBuffer; + } else { + myTargetBuffer = 0; + myTargetBufferEnd = 0; + myTargetBufferPtr = 0; + } + + return myTargetBufferPtr - myTargetBuffer; +} + +void HuffDecompressor::bitsDecompress(BitReader bits, std::size_t depth) { + if (depth > 32) { + myErrorCode = ERROR_CORRUPTED_FILE; + return; + } + + while (bits.left()) { + const unsigned long dw = (unsigned long)bits.peek(32); + const unsigned long v = myCacheTable[dw >> 24]; + unsigned long codelen = v & 0x1F; + //if ((codelen == 0) || (codelen > 32)) { + // return false; + //} + unsigned long code = dw >> (32 - codelen); + unsigned long r = (v >> 8); + if (!(v & 0x80)) { + while (code < myBaseTable[(codelen - 1) * 2]) { + codelen += 1; + code = dw >> (32 - codelen); + } + r = myBaseTable[(codelen - 1) * 2 + 1]; + } + r -= code; + //if (codelen == 0) { + // return false; + //} + if (!bits.eat(codelen)) { + return; + } + const unsigned long dicno = r >> myEntryBits; + const unsigned long off1 = 16 + (r - (dicno << myEntryBits)) * 2; + const unsigned char* dict = myDicts[dicno]; //TODO need index check + const unsigned long off2 = 16 + dict[off1] * 256 + dict[off1 + 1]; //TODO need index check + const unsigned long blen = dict[off2] * 256 + dict[off2 + 1]; //TODO need index check + const unsigned char* slice = dict + off2 + 2; + const unsigned long sliceSize = blen & 0x7fff; + if (blen & 0x8000) { + if (myTargetBufferPtr + sliceSize < myTargetBufferEnd) { + std::memcpy(myTargetBufferPtr, slice, sliceSize); + myTargetBufferPtr += sliceSize; + } else { + return; + } + } else { + bitsDecompress(BitReader(slice, sliceSize), depth + 1); + } + } +} + +std::size_t HuffDecompressor::sizeOfTrailingEntries(unsigned char* data, std::size_t size) const { + std::size_t num = 0; + std::size_t flags = myExtraFlags >> 1; + while (flags) { + if (flags & 1) { + if (num < size) { + num += readVariableWidthIntegerBE(data, size - num); + } + } + flags >>= 1; + } + return num; +} + + +std::size_t HuffDecompressor::readVariableWidthIntegerBE(unsigned char* ptr, std::size_t psize) const { + unsigned char bitsSaved = 0; + std::size_t result = 0; + while (true) { + const unsigned char oneByte = ptr[psize - 1]; + result |= (oneByte & 0x7F) << bitsSaved; + bitsSaved += 7; + psize -= 1; + if (((oneByte & 0x80) != 0) || (bitsSaved >= 28) || (psize == 0)) { + return result; + } + } +} diff --git a/reader/src/formats/pdb/HuffDecompressor.h b/reader/src/formats/pdb/HuffDecompressor.h new file mode 100644 index 0000000..76539e9 --- /dev/null +++ b/reader/src/formats/pdb/HuffDecompressor.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HUFFDECOMPRESSOR_H__ +#define __HUFFDECOMPRESSOR_H__ + +#include <string> + +class ZLInputStream; +class BitReader; + +class HuffDecompressor { + +public: + HuffDecompressor(ZLInputStream& stream, + const std::vector<unsigned long>::const_iterator beginHuffRecordOffsetIt, + const std::vector<unsigned long>::const_iterator endHuffRecordOffsetIt, + const unsigned long endHuffDataOffset, const unsigned long extraFlags); + ~HuffDecompressor(); + + std::size_t decompress(ZLInputStream &stream, char *buffer, std::size_t compressedSize, std::size_t maxUncompressedSize); + bool error() const; +private: + std::size_t sizeOfTrailingEntries(unsigned char* data, std::size_t size) const; + std::size_t readVariableWidthIntegerBE(unsigned char* ptr, std::size_t psize) const; + void bitsDecompress(BitReader bits, std::size_t depth = 0); + +private: + unsigned long myEntryBits; + unsigned long myExtraFlags; + + unsigned long* myCacheTable; + unsigned long* myBaseTable; + unsigned char* myData; + unsigned char** myDicts; + + char* myTargetBuffer; + char* myTargetBufferEnd; + char* myTargetBufferPtr; + + enum { + ERROR_NONE, + ERROR_CORRUPTED_FILE + } myErrorCode; +}; + +#endif /* __HUFFDECOMPRESSOR_H__ */ diff --git a/reader/src/formats/pdb/MobipocketHtmlBookReader.cpp b/reader/src/formats/pdb/MobipocketHtmlBookReader.cpp new file mode 100644 index 0000000..cecbfbc --- /dev/null +++ b/reader/src/formats/pdb/MobipocketHtmlBookReader.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLFileImage.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "MobipocketHtmlBookReader.h" +#include "PalmDocStream.h" +#include "../html/HtmlTagActions.h" +#include "../../bookmodel/BookModel.h" + +class MobipocketHtmlImageTagAction : public HtmlTagAction { + +public: + MobipocketHtmlImageTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class MobipocketHtmlHrTagAction : public HtmlTagAction { + +public: + MobipocketHtmlHrTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class MobipocketHtmlHrefTagAction : public HtmlHrefTagAction { + +public: + MobipocketHtmlHrefTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class MobipocketHtmlGuideTagAction : public HtmlTagAction { + +public: + MobipocketHtmlGuideTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class MobipocketHtmlReferenceTagAction : public HtmlTagAction { + +public: + MobipocketHtmlReferenceTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +class MobipocketHtmlPagebreakTagAction : public HtmlTagAction { + +public: + MobipocketHtmlPagebreakTagAction(HtmlBookReader &reader); + void run(const HtmlReader::HtmlTag &tag); +}; + +MobipocketHtmlImageTagAction::MobipocketHtmlImageTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void MobipocketHtmlImageTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "RECINDEX") { + int index = std::atoi(tag.Attributes[i].Value.c_str()); + if (index > 0) { + int &imageCounter = ((MobipocketHtmlBookReader&)myReader).myImageCounter; + imageCounter = std::max(imageCounter, index); + bool stopParagraph = bookReader().paragraphIsOpen(); + if (stopParagraph) { + bookReader().endParagraph(); + } + std::string id; + ZLStringUtil::appendNumber(id, index); + bookReader().addImageReference(id); + if (stopParagraph) { + bookReader().beginParagraph(); + } + } + break; + } + } + } +} + +MobipocketHtmlHrTagAction::MobipocketHtmlHrTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void MobipocketHtmlHrTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + if (bookReader().contentsParagraphIsOpen()) { + bookReader().endContentsParagraph(); + bookReader().exitTitle(); + } + bookReader().insertEndOfSectionParagraph(); + } +} + +MobipocketHtmlHrefTagAction::MobipocketHtmlHrefTagAction(HtmlBookReader &reader) : HtmlHrefTagAction(reader) { +} + +MobipocketHtmlPagebreakTagAction::MobipocketHtmlPagebreakTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void MobipocketHtmlPagebreakTagAction::run(const HtmlReader::HtmlTag &tag) { + if (tag.Start) { + if (bookReader().contentsParagraphIsOpen()) { + bookReader().endContentsParagraph(); + bookReader().exitTitle(); + } + bookReader().insertEndOfSectionParagraph(); + } +} + +MobipocketHtmlBookReader::TOCReader::TOCReader(MobipocketHtmlBookReader &reader) : myReader(reader) { + reset(); +} + +void MobipocketHtmlBookReader::TOCReader::reset() { + myEntries.clear(); + + myIsActive = false; + myStartOffset = (std::size_t)-1; + myEndOffset = (std::size_t)-1; + myCurrentEntryText.erase(); +} + +bool MobipocketHtmlBookReader::TOCReader::rangeContainsPosition(std::size_t position) { + return (myStartOffset <= position) && (myEndOffset > position); +} + +void MobipocketHtmlBookReader::TOCReader::startReadEntry(std::size_t position) { + myCurrentReference = position; + myIsActive = true; +} + +void MobipocketHtmlBookReader::TOCReader::endReadEntry() { + if (myIsActive && !myCurrentEntryText.empty()) { + std::string converted; + myReader.myConverter->convert(converted, myCurrentEntryText); + myReader.myConverter->reset(); + myEntries[myCurrentReference] = converted; + myCurrentEntryText.erase(); + } + myIsActive = false; +} + +void MobipocketHtmlBookReader::TOCReader::appendText(const char *text, std::size_t len) { + if (myIsActive) { + myCurrentEntryText.append(text, len); + } +} + +void MobipocketHtmlBookReader::TOCReader::addReference(std::size_t position, const std::string &text) { + myEntries[position] = text; + if (rangeContainsPosition(position)) { + setEndOffset(position); + } +} + +void MobipocketHtmlBookReader::TOCReader::setStartOffset(std::size_t position) { + myStartOffset = position; + std::map<std::size_t,std::string>::const_iterator it = myEntries.lower_bound(position); + if (it != myEntries.end()) { + ++it; + if (it != myEntries.end()) { + myEndOffset = it->first; + } + } +} + +void MobipocketHtmlBookReader::TOCReader::setEndOffset(std::size_t position) { + myEndOffset = position; +} + +const std::map<std::size_t,std::string> &MobipocketHtmlBookReader::TOCReader::entries() const { + return myEntries; +} + +void MobipocketHtmlHrefTagAction::run(const HtmlReader::HtmlTag &tag) { + MobipocketHtmlBookReader &reader = (MobipocketHtmlBookReader&)myReader; + if (tag.Start) { + for (unsigned int i = 0; i < tag.Attributes.size(); ++i) { + if (tag.Attributes[i].Name == "FILEPOS") { + const std::string &value = tag.Attributes[i].Value; + if (!value.empty()) { + std::string label = "&"; + int intValue = std::atoi(value.c_str()); + if (intValue > 0) { + if (reader.myTocReader.rangeContainsPosition(tag.Offset)) { + reader.myTocReader.startReadEntry(intValue); + if (reader.myTocReader.rangeContainsPosition(intValue)) { + reader.myTocReader.setEndOffset(intValue); + } + } + reader.myFileposReferences.insert(intValue); + ZLStringUtil::appendNumber(label, intValue); + setHyperlinkType(INTERNAL_HYPERLINK); + bookReader().addHyperlinkControl(INTERNAL_HYPERLINK, label); + return; + } + } + } + } + } else { + reader.myTocReader.endReadEntry(); + } + HtmlHrefTagAction::run(tag); +} + +MobipocketHtmlGuideTagAction::MobipocketHtmlGuideTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void MobipocketHtmlGuideTagAction::run(const HtmlReader::HtmlTag &tag) { + MobipocketHtmlBookReader &reader = (MobipocketHtmlBookReader&)myReader; + reader.myInsideGuide = tag.Start; +} + +MobipocketHtmlReferenceTagAction::MobipocketHtmlReferenceTagAction(HtmlBookReader &reader) : HtmlTagAction(reader) { +} + +void MobipocketHtmlReferenceTagAction::run(const HtmlReader::HtmlTag &tag) { + MobipocketHtmlBookReader &reader = (MobipocketHtmlBookReader&)myReader; + if (reader.myInsideGuide) { + std::string title; + std::string filepos; + bool isTocReference = false; + for (std::size_t i = 0; i < tag.Attributes.size(); ++i) { + const std::string &name = tag.Attributes[i].Name; + const std::string &value = tag.Attributes[i].Value; + if (name == "TITLE") { + title = value; + } else if (name == "FILEPOS") { + filepos = value; + } else if ((name == "TYPE") && (ZLUnicodeUtil::toUpper(value) == "TOC")) { + isTocReference = true; + } + } + if (!title.empty() && !filepos.empty()) { + int position = std::atoi(filepos.c_str()); + if (position > 0) { + reader.myTocReader.addReference(position, title); + if (isTocReference) { + reader.myTocReader.setStartOffset(position); + } + } + } + } +} + +shared_ptr<HtmlTagAction> MobipocketHtmlBookReader::createAction(const std::string &tag) { + if (tag == "IMG") { + return new MobipocketHtmlImageTagAction(*this); + } else if (tag == "HR") { + return new MobipocketHtmlHrTagAction(*this); + } else if (tag == "A") { + return new MobipocketHtmlHrefTagAction(*this); + } else if (tag == "GUIDE") { + return new MobipocketHtmlGuideTagAction(*this); + } else if (tag == "REFERENCE") { + return new MobipocketHtmlReferenceTagAction(*this); + } else if (tag == "MBP:PAGEBREAK") { + return new MobipocketHtmlPagebreakTagAction(*this); + } + return HtmlBookReader::createAction(tag); +} + +void MobipocketHtmlBookReader::startDocumentHandler() { + HtmlBookReader::startDocumentHandler(); + myImageCounter = 0; + myInsideGuide = false; + myFileposReferences.clear(); + myPositionToParagraphMap.clear(); + myTocReader.reset(); +} + +bool MobipocketHtmlBookReader::tagHandler(const HtmlTag &tag) { + std::size_t paragraphNumber = myBookReader.model().bookTextModel()->paragraphsNumber(); + if (myBookReader.paragraphIsOpen()) { + --paragraphNumber; + } + myPositionToParagraphMap.push_back(std::make_pair(tag.Offset, paragraphNumber)); + return HtmlBookReader::tagHandler(tag); +} + +MobipocketHtmlBookReader::MobipocketHtmlBookReader(const ZLFile &file, BookModel &model, const PlainTextFormat &format, const std::string &encoding) : HtmlBookReader("", model, format, encoding), myFileName(file.path()), myTocReader(*this) { + setBuildTableOfContent(false); + setProcessPreTag(false); +} + +bool MobipocketHtmlBookReader::characterDataHandler(const char *text, std::size_t len, bool convert) { + myTocReader.appendText(text, len); + return HtmlBookReader::characterDataHandler(text, len, convert); +} + +void MobipocketHtmlBookReader::readDocument(ZLInputStream &stream) { + HtmlBookReader::readDocument(stream); + + PalmDocStream &pdStream = (PalmDocStream&)stream; + int index = pdStream.firstImageLocationIndex(myFileName); + + if (index >= 0) { + for (int i = 0; i < myImageCounter; i++) { + std::pair<int,int> imageLocation = pdStream.imageLocation(pdStream.header(), i + index); + if ((imageLocation.first > 0) && (imageLocation.second > 0)) { + std::string id; + ZLStringUtil::appendNumber(id, i + 1); + myBookReader.addImage(id, new ZLFileImage(ZLFile(myFileName), imageLocation.first, imageLocation.second)); + } + } + } + + std::vector<std::pair<std::size_t,std::size_t> >::const_iterator jt = myPositionToParagraphMap.begin(); + for (std::set<std::size_t>::const_iterator it = myFileposReferences.begin(); it != myFileposReferences.end(); ++it) { + while (jt != myPositionToParagraphMap.end() && jt->first < *it) { + ++jt; + } + if (jt == myPositionToParagraphMap.end()) { + break; + } + std::string label = "&"; + ZLStringUtil::appendNumber(label, *it); + myBookReader.addHyperlinkLabel(label, jt->second); + } + + jt = myPositionToParagraphMap.begin(); + const std::map<std::size_t,std::string> &entries = myTocReader.entries(); + for (std::map<std::size_t,std::string>::const_iterator it = entries.begin(); it != entries.end(); ++it) { + while (jt != myPositionToParagraphMap.end() && jt->first < it->first) { + ++jt; + } + if (jt == myPositionToParagraphMap.end()) { + break; + } + myBookReader.beginContentsParagraph(jt->second); + myBookReader.addContentsData(it->second); + myBookReader.endContentsParagraph(); + } +} diff --git a/reader/src/formats/pdb/MobipocketHtmlBookReader.h b/reader/src/formats/pdb/MobipocketHtmlBookReader.h new file mode 100644 index 0000000..7a35523 --- /dev/null +++ b/reader/src/formats/pdb/MobipocketHtmlBookReader.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __MOBIPOCKETHTMLBOOKREADER_H__ +#define __MOBIPOCKETHTMLBOOKREADER_H__ + +#include <set> + +#include "../html/HtmlBookReader.h" + +class MobipocketHtmlBookReader : public HtmlBookReader { + +public: + MobipocketHtmlBookReader(const ZLFile &file, BookModel &model, const PlainTextFormat &format, const std::string &encoding); + void readDocument(ZLInputStream &stream); + +private: + void startDocumentHandler(); + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + shared_ptr<HtmlTagAction> createAction(const std::string &tag); + +public: + class TOCReader { + + public: + TOCReader(MobipocketHtmlBookReader &reader); + void reset(); + + void addReference(std::size_t position, const std::string &text); + + void setStartOffset(std::size_t position); + void setEndOffset(std::size_t position); + + bool rangeContainsPosition(std::size_t position); + + void startReadEntry(std::size_t position); + void endReadEntry(); + void appendText(const char *text, std::size_t len); + + const std::map<std::size_t,std::string> &entries() const; + + private: + MobipocketHtmlBookReader &myReader; + + std::map<std::size_t,std::string> myEntries; + + bool myIsActive; + std::size_t myStartOffset; + std::size_t myEndOffset; + + std::size_t myCurrentReference; + std::string myCurrentEntryText; + }; + +private: + int myImageCounter; + const std::string myFileName; + + std::vector<std::pair<std::size_t,std::size_t> > myPositionToParagraphMap; + std::set<std::size_t> myFileposReferences; + bool myInsideGuide; + TOCReader myTocReader; + +friend class MobipocketHtmlImageTagAction; +friend class MobipocketHtmlHrefTagAction; +friend class MobipocketHtmlGuideTagAction; +friend class MobipocketHtmlReferenceTagAction; +friend class MobipocketHtmlPagebreakTagAction; +friend class TOCReader; +}; + +#endif /* __MOBIPOCKETHTMLBOOKREADER_H__ */ diff --git a/reader/src/formats/pdb/MobipocketPlugin.cpp b/reader/src/formats/pdb/MobipocketPlugin.cpp new file mode 100644 index 0000000..4832b43 --- /dev/null +++ b/reader/src/formats/pdb/MobipocketPlugin.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> +#include <ZLEncodingConverter.h> +#include <ZLUnicodeUtil.h> +#include <ZLLanguageUtil.h> +#include <ZLImage.h> +#include <ZLFileImage.h> + +#include "PdbPlugin.h" +#include "PalmDocStream.h" +#include "MobipocketHtmlBookReader.h" + +#include "../../library/Book.h" + +bool MobipocketPlugin::acceptsFile(const ZLFile &file) const { + return PdbPlugin::fileType(file) == "BOOKMOBI"; +} + +void MobipocketPlugin::readDocumentInternal(const ZLFile &file, BookModel &model, const PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const { + MobipocketHtmlBookReader(file, model, format, encoding).readDocument(stream); +} + +bool MobipocketPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = book.file().inputStream(); + if (stream.isNull() || ! stream->open()) { + return false; + } + PdbHeader header; + if (!header.read(stream)) { + return false; + } + stream->seek(header.Offsets[0] + 16, true); + char test[5]; + test[4] = '\0'; + stream->read(test, 4); + static const std::string MOBI = "MOBI"; + if (MOBI != test) { + return PalmDocLikePlugin::readMetaInfo(book); + } + + unsigned long length; + PdbUtil::readUnsignedLongBE(*stream, length); + + stream->seek(4, false); + + unsigned long encodingCode; + PdbUtil::readUnsignedLongBE(*stream, encodingCode); + if (book.encoding().empty()) { + ZLEncodingConverterInfoPtr info = ZLEncodingCollection::Instance().info(encodingCode); + if (!info.isNull()) { + book.setEncoding(info->name()); + } + } + + stream->seek(52, false); + + unsigned long fullNameOffset; + PdbUtil::readUnsignedLongBE(*stream, fullNameOffset); + unsigned long fullNameLength; + PdbUtil::readUnsignedLongBE(*stream, fullNameLength); + + unsigned long languageCode; + PdbUtil::readUnsignedLongBE(*stream, languageCode); + book.setLanguage(ZLLanguageUtil::languageByCode(languageCode & 0xFF, (languageCode >> 8) & 0xFF)); + + stream->seek(32, false); + + unsigned long exthFlags; + PdbUtil::readUnsignedLongBE(*stream, exthFlags); + if (exthFlags & 0x40) { + stream->seek(header.Offsets[0] + 16 + length, true); + + stream->read(test, 4); + static const std::string EXTH = "EXTH"; + if (EXTH == test) { + stream->seek(4, false); + unsigned long recordsNum; + PdbUtil::readUnsignedLongBE(*stream, recordsNum); + for (unsigned long i = 0; i < recordsNum; ++i) { + unsigned long type; + PdbUtil::readUnsignedLongBE(*stream, type); + unsigned long size; + PdbUtil::readUnsignedLongBE(*stream, size); + if (size > 8) { + std::string value(size - 8, '\0'); + stream->read((char*)value.data(), size - 8); + switch (type) { + case 100: // author + { + int index = value.find(','); + if (index != -1) { + std::string part0 = value.substr(0, index); + std::string part1 = value.substr(index + 1); + ZLUnicodeUtil::utf8Trim(part0); + ZLUnicodeUtil::utf8Trim(part1); + value = part1 + ' ' + part0; + } else { + ZLUnicodeUtil::utf8Trim(value); + } + book.addAuthor(value); + break; + } + case 105: // subject + book.addTag(value); + break; + } + } + } + } + } + + stream->seek(header.Offsets[0] + fullNameOffset, true); + std::string title(fullNameLength, '\0'); + stream->read((char*)title.data(), fullNameLength); + book.setTitle(title); + + stream->close(); + return PalmDocLikePlugin::readMetaInfo(book); +} + +shared_ptr<const ZLImage> MobipocketPlugin::coverImage(const ZLFile &file) const { + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull() || ! stream->open()) { + return 0; + } + PdbHeader header; + if (!header.read(stream)) { + return 0; + } + stream->seek(header.Offsets[0] + 16, true); + char test[5]; + test[4] = '\0'; + stream->read(test, 4); + static const std::string MOBI = "MOBI"; + if (MOBI != test) { + return 0; + } + + unsigned long length; + PdbUtil::readUnsignedLongBE(*stream, length); + + stream->seek(104, false); + + unsigned long exthFlags; + unsigned long coverIndex = (unsigned long)-1; + unsigned long thumbIndex = (unsigned long)-1; + PdbUtil::readUnsignedLongBE(*stream, exthFlags); + if (exthFlags & 0x40) { + stream->seek(header.Offsets[0] + 16 + length, true); + + stream->read(test, 4); + static const std::string EXTH = "EXTH"; + if (EXTH != test) { + return 0; + } + stream->seek(4, false); + unsigned long recordsNum; + PdbUtil::readUnsignedLongBE(*stream, recordsNum); + for (unsigned long i = 0; i < recordsNum; ++i) { + unsigned long type; + PdbUtil::readUnsignedLongBE(*stream, type); + unsigned long size; + PdbUtil::readUnsignedLongBE(*stream, size); + switch (type) { + case 201: // coveroffset + if (size == 12) { + PdbUtil::readUnsignedLongBE(*stream, coverIndex); + } else { + stream->seek(size - 8, false); + } + break; + case 202: // thumboffset + if (size == 12) { + PdbUtil::readUnsignedLongBE(*stream, thumbIndex); + } else { + stream->seek(size - 8, false); + } + break; + default: + stream->seek(size - 8, false); + break; + } + } + } + stream->close(); + + if (coverIndex == (unsigned long)-1) { + if (thumbIndex == (unsigned long)-1) { + return 0; + } + coverIndex = thumbIndex; + } + + PalmDocStream pbStream(file); + if (!pbStream.open()) { + return 0; + } + int index = pbStream.firstImageLocationIndex(file.path()); + if (index >= 0) { + std::pair<int,int> imageLocation = pbStream.imageLocation(pbStream.header(), index + coverIndex); + if ((imageLocation.first > 0) && (imageLocation.second > 0)) { + return new ZLFileImage( + file, + imageLocation.first, + imageLocation.second + ); + } + } + return 0; +} diff --git a/reader/src/formats/pdb/PalmDocLikePlugin.cpp b/reader/src/formats/pdb/PalmDocLikePlugin.cpp new file mode 100644 index 0000000..27c03a1 --- /dev/null +++ b/reader/src/formats/pdb/PalmDocLikePlugin.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> + +#include "PdbPlugin.h" +#include "PalmDocStream.h" +#include "PalmDocLikeStream.h" + +#include "../../library/Book.h" + +bool PalmDocLikePlugin::providesMetaInfo() const { + return true; +} + +shared_ptr<ZLInputStream> PalmDocLikePlugin::createStream(const ZLFile &file) const { + return new PalmDocStream(file); +} + +const std::string &PalmDocLikePlugin::tryOpen(const ZLFile &file) const { + PalmDocStream stream(file); + stream.open(); + return stream.error(); +} diff --git a/reader/src/formats/pdb/PalmDocLikeStream.cpp b/reader/src/formats/pdb/PalmDocLikeStream.cpp new file mode 100644 index 0000000..8b99d4d --- /dev/null +++ b/reader/src/formats/pdb/PalmDocLikeStream.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLResource.h> + +#include "PalmDocLikeStream.h" + + +PalmDocLikeStream::PalmDocLikeStream(const ZLFile &file) : PdbStream(file) { +} + +PalmDocLikeStream::~PalmDocLikeStream() { + close(); +} + +bool PalmDocLikeStream::open() { + myErrorCode = ERROR_NONE; + if (!PdbStream::open()) { + myErrorCode = ERROR_UNKNOWN; + return false; + } + + if (!processZeroRecord()) { + return false; + } + + myBuffer = new char[myMaxRecordSize]; + myRecordIndex = 0; + return true; +} + +bool PalmDocLikeStream::fillBuffer() { + while (myBufferOffset == myBufferLength) { + if (myRecordIndex + 1 > myMaxRecordIndex) { + return false; + } + ++myRecordIndex; + if (!processRecord()) { + return false; + } + } + //myBufferOffset = 0; + return true; +} + +const std::string &PalmDocLikeStream::error() const { + static const ZLResource &resource = ZLResource::resource("mobipocketPlugin"); + switch (myErrorCode) { + default: + { + static const std::string EMPTY; + return EMPTY; + } + case ERROR_UNKNOWN: + return resource["unknown"].value(); + case ERROR_COMPRESSION: + return resource["unsupportedCompressionMethod"].value(); + case ERROR_ENCRYPTION: + return resource["encryptedFile"].value(); + } +} diff --git a/reader/src/formats/pdb/PalmDocLikeStream.h b/reader/src/formats/pdb/PalmDocLikeStream.h new file mode 100644 index 0000000..623a493 --- /dev/null +++ b/reader/src/formats/pdb/PalmDocLikeStream.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PALMDOCLIKESTREAM_H__ +#define __PALMDOCLIKESTREAM_H__ + +#include "PdbStream.h" + +class ZLFile; + +class PalmDocLikeStream : public PdbStream { + +public: + PalmDocLikeStream(const ZLFile &file); + ~PalmDocLikeStream(); + bool open(); + + const std::string &error() const; + //std::pair<int,int> imageLocation(int index); + //bool hasExtraSections() const; + +protected: + bool fillBuffer(); + +private: + virtual bool processRecord() = 0; + virtual bool processZeroRecord() = 0; + +protected: + unsigned short myMaxRecordSize; + std::size_t myRecordIndex; + std::size_t myMaxRecordIndex; + + enum { + ERROR_NONE, + ERROR_UNKNOWN, + ERROR_COMPRESSION, + ERROR_ENCRYPTION, + } myErrorCode; +}; + +#endif /* __PALMDOCLIKESTREAM_H__ */ diff --git a/reader/src/formats/pdb/PalmDocPlugin.cpp b/reader/src/formats/pdb/PalmDocPlugin.cpp new file mode 100644 index 0000000..c23f11c --- /dev/null +++ b/reader/src/formats/pdb/PalmDocPlugin.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "PdbPlugin.h" +#include "PalmDocStream.h" +#include "MobipocketHtmlBookReader.h" +#include "../txt/PlainTextFormat.h" +#include "../util/TextFormatDetector.h" + +bool PalmDocPlugin::acceptsFile(const ZLFile &file) const { + return PdbPlugin::fileType(file) == "TEXtREAd"; +} + +void PalmDocPlugin::readDocumentInternal(const ZLFile &file, BookModel &model, const PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const { + stream.open(); + bool readAsPalmDoc = ((PalmDocStream&)stream).hasExtraSections(); + stream.close(); + if (readAsPalmDoc) { + MobipocketHtmlBookReader(file, model, format, encoding).readDocument(stream); + } else { + SimplePdbPlugin::readDocumentInternal(file, model, format, encoding, stream); + } +} + +FormatInfoPage *PalmDocPlugin::createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file) { + shared_ptr<ZLInputStream> stream = createStream(file); + stream->open(); + bool readAsPalmDoc = ((PalmDocStream&)*stream).hasExtraSections(); + stream->close(); + if (!readAsPalmDoc) { + return new PlainTextInfoPage(dialog, file, ZLResourceKey("Text"), !TextFormatDetector().isHtml(*stream)); + } else { + return 0; + } +} diff --git a/reader/src/formats/pdb/PalmDocStream.cpp b/reader/src/formats/pdb/PalmDocStream.cpp new file mode 100644 index 0000000..e699d47 --- /dev/null +++ b/reader/src/formats/pdb/PalmDocStream.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLResource.h> +#include <ZLZDecompressor.h> + +#include "PalmDocStream.h" +#include "DocDecompressor.h" +#include "HuffDecompressor.h" + +PalmDocStream::PalmDocStream(const ZLFile &file) : PalmDocLikeStream(file) { +} + +PalmDocStream::~PalmDocStream() { + close(); +} + +bool PalmDocStream::processRecord() { + const std::size_t currentOffset = recordOffset(myRecordIndex); + if (currentOffset < myBase->offset()) { + return false; + } + myBase->seek(currentOffset, true); + const std::size_t nextOffset = recordOffset(myRecordIndex + 1); + if (nextOffset < currentOffset) { + return false; + } + const unsigned short recordSize = nextOffset - currentOffset; + switch(myCompressionVersion) { + case 17480://'DH' // HuffCDic compression + myBufferLength = myHuffDecompressorPtr->decompress(*myBase, myBuffer, recordSize, myMaxRecordSize); + //if (myHuffDecompressorPtr->error()) { + // myErrorCode = ERROR_UNKNOWN; + //} + break; + case 2: // PalmDoc compression + myBufferLength = DocDecompressor().decompress(*myBase, myBuffer, recordSize, myMaxRecordSize); + break; + case 1: // No compression + myBufferLength = myBase->read(myBuffer, std::min(recordSize, myMaxRecordSize)); + break; + } + myBufferOffset = 0; + return true; +} + +bool PalmDocStream::processZeroRecord() { + // Uses with offset presetting to zero record offset value + PdbUtil::readUnsignedShort(*myBase, myCompressionVersion); // myBase offset: ^ + 2 + switch (myCompressionVersion) { + case 1: + case 2: + case 17480: + break; + default: + myErrorCode = ERROR_COMPRESSION; + return false; + } + myBase->seek(2, false); // myBase offset: ^ + 4 + PdbUtil::readUnsignedLongBE(*myBase, myTextLength); // myBase offset: ^ + 8 + PdbUtil::readUnsignedShort(*myBase, myTextRecordNumber); // myBase offset: ^ + 10 + + unsigned short endSectionIndex = header().Offsets.size(); + myMaxRecordIndex = std::min(myTextRecordNumber, (unsigned short)(endSectionIndex - 1)); + //TODO Insert in this point error message about uncompatible records and numRecords from Header + + PdbUtil::readUnsignedShort(*myBase, myMaxRecordSize); // myBase offset: ^ + 12 + if (myMaxRecordSize == 0) { + myErrorCode = ERROR_UNKNOWN; + return false; + } + + /* + std::cerr << "PalmDocStream::processRecord0():\n"; + std::cerr << "PDB header indentificator : " << header().Id << "\n"; + std::cerr << "PDB file system: sizeof opened : " << myBaseSize << "\n"; + std::cerr << "PDB header/record[0] max index : " << myMaxRecordIndex << "\n"; + std::cerr << "PDB record[0][0..2] compression : " << myCompressionVersion << "\n"; + std::cerr << "PDB record[0][2..4] spare : " << mySpare << "\n"; + std::cerr << "PDB record[0][4..8] text length : " << myTextLength << "\n"; + std::cerr << "PDB record[0][8..10] text records : " << myTextRecords << "\n"; + std::cerr << "PDB record[0][10..12] max record size: " << myMaxRecordSize << "\n"; + */ + + if (header().Id == "BOOKMOBI") { + unsigned short encrypted = 0; + PdbUtil::readUnsignedShort(*myBase, encrypted); // myBase offset: ^ + 14 + if (encrypted) { //Always = 2, if encrypted + myErrorCode = ERROR_ENCRYPTION; + return false; + } + } else { + myBase->seek(2, false); + } + + + if (myCompressionVersion == 17480) { + unsigned long mobiHeaderLength; + unsigned long huffSectionIndex; + unsigned long huffSectionNumber; + unsigned short extraFlags; + unsigned long initialOffset = header().Offsets[0]; // myBase offset: ^ + + myBase->seek(6, false); // myBase offset: ^ + 20 + PdbUtil::readUnsignedLongBE(*myBase, mobiHeaderLength); // myBase offset: ^ + 24 + + myBase->seek(0x70 - 24, false); // myBase offset: ^ + 102 (0x70) + PdbUtil::readUnsignedLongBE(*myBase, huffSectionIndex); // myBase offset: ^ + 106 (0x74) + PdbUtil::readUnsignedLongBE(*myBase, huffSectionNumber); // myBase offset: ^ + 110 (0x78) + + if (mobiHeaderLength >= 244) { + myBase->seek(0xF2 - 0x78, false); // myBase offset: ^ + 242 (0xF2) + PdbUtil::readUnsignedShort(*myBase, extraFlags); // myBase offset: ^ + 244 (0xF4) + } else { + extraFlags = 0; + } + /* + std::cerr << "mobi header length: " << mobiHeaderLength << "\n"; + std::cerr << "Huff's start record : " << huffSectionIndex << " from " << endSectionIndex - 1 << "\n"; + std::cerr << "Huff's records number: " << huffSectionNumber << "\n"; + std::cerr << "Huff's extraFlags : " << extraFlags << "\n"; + */ + const unsigned long endHuffSectionIndex = huffSectionIndex + huffSectionNumber; + if (endHuffSectionIndex > endSectionIndex || huffSectionNumber <= 1) { + myErrorCode = ERROR_COMPRESSION; + return false; + } + const unsigned long endHuffDataOffset = recordOffset(endHuffSectionIndex); + std::vector<unsigned long>::const_iterator beginHuffSectionOffsetIt = header().Offsets.begin() + huffSectionIndex; + // point to first Huff section + std::vector<unsigned long>::const_iterator endHuffSectionOffsetIt = header().Offsets.begin() + endHuffSectionIndex; + // point behind last Huff section + + + myHuffDecompressorPtr = new HuffDecompressor(*myBase, beginHuffSectionOffsetIt, endHuffSectionOffsetIt, endHuffDataOffset, extraFlags); + myBase->seek(initialOffset, true); // myBase offset: ^ + 14 + } + return true; +} + +bool PalmDocStream::hasExtraSections() const { + return myMaxRecordIndex < header().Offsets.size() - 1; +} + +std::pair<int,int> PalmDocStream::imageLocation(const PdbHeader &header, int index) const { + index += myMaxRecordIndex + 1; + int recordNumber = header.Offsets.size(); + if (index > recordNumber - 1) { + return std::make_pair(-1, -1); + } else { + int start = header.Offsets[index]; + int end = (index < recordNumber - 1) ? + header.Offsets[index + 1] : myBase->offset(); + return std::make_pair(start, end - start); + } +} + +int PalmDocStream::firstImageLocationIndex(const std::string &fileName) { + shared_ptr<ZLInputStream> fileStream = ZLFile(fileName).inputStream(); + if (fileStream.isNull() || !fileStream->open()) { + return -1; + } + + bool found = false; + int index = 0; + char bu[5] = { 0 }; + std::pair<int,int> firstImageLocation = imageLocation(header(), 0); + fileStream->seek(firstImageLocation.first, false); + while ((firstImageLocation.first > 0) && (firstImageLocation.second > 0)) { + if (firstImageLocation.second > 4) { + fileStream->read(bu, 4); + static const char jpegStart[2] = { (char)0xFF, (char)0xd8 }; + if (std::strncmp(bu, "BM", 2) == 0 || + std::strncmp(bu, "GIF8", 4) == 0 || + std::strncmp(bu, jpegStart, 2) == 0) { + found = true; + break; + } + fileStream->seek(firstImageLocation.second - 4, false); + } else { + fileStream->seek(firstImageLocation.second, false); + } + index++; + firstImageLocation = imageLocation(header(), index); + } + + fileStream->close(); + return found ? index : -1; +} diff --git a/reader/src/formats/pdb/PalmDocStream.h b/reader/src/formats/pdb/PalmDocStream.h new file mode 100644 index 0000000..4782a7b --- /dev/null +++ b/reader/src/formats/pdb/PalmDocStream.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PALMDOCSTREAM_H__ +#define __PALMDOCSTREAM_H__ + +#include "PalmDocLikeStream.h" + +class ZLFile; +class HuffDecompressor; + +class PalmDocStream : public PalmDocLikeStream { + +public: + PalmDocStream(const ZLFile &file); + ~PalmDocStream(); + + std::pair<int,int> imageLocation(const PdbHeader &header, int index) const; + bool hasExtraSections() const; + int firstImageLocationIndex(const std::string &fileName); + +private: + bool processRecord(); + bool processZeroRecord(); + +private: + unsigned short myCompressionVersion; + unsigned long myTextLength; //TODO: Warning: isn't used + unsigned short myTextRecordNumber; + + shared_ptr<HuffDecompressor> myHuffDecompressorPtr; +}; + +#endif /* __PALMDOCSTREAM_H__ */ diff --git a/reader/src/formats/pdb/PdbPlugin.cpp b/reader/src/formats/pdb/PdbPlugin.cpp new file mode 100644 index 0000000..69ef233 --- /dev/null +++ b/reader/src/formats/pdb/PdbPlugin.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> +#include <ZLOptions.h> + +#include "PdbPlugin.h" +#include "../../options/FBCategoryKey.h" + +#include "../../database/booksdb/BooksDBUtil.h" +#include "../../database/booksdb/BooksDB.h" + +PdbPlugin::~PdbPlugin() { +} + +std::string PdbPlugin::fileType(const ZLFile &file) { + const std::string &extension = file.extension(); + if ((extension != "prc") && (extension != "pdb") && (extension != "mobi")) { + return ""; + } + + const std::string &fileName = file.path(); + //int index = fileName.find(':'); + //ZLFile baseFile = (index == -1) ? file : ZLFile(fileName.substr(0, index)); + ZLFile baseFile(file.physicalFilePath()); + bool upToDate = BooksDBUtil::checkInfo(baseFile); + + //ZLStringOption palmTypeOption(FBCategoryKey::BOOKS, file.path(), "PalmType", ""); + std::string palmType = BooksDB::Instance().getPalmType(fileName); + if ((palmType.length() != 8) || !upToDate) { + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull() || !stream->open()) { + return ""; + } + stream->seek(60, false); + char id[8]; + stream->read(id, 8); + stream->close(); + palmType = std::string(id, 8); + if (!upToDate) { + BooksDBUtil::saveInfo(baseFile); + } + //palmTypeOption.setValue(palmType); + BooksDB::Instance().setPalmType(fileName, palmType); + } + return palmType; +} + +bool PdbPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} diff --git a/reader/src/formats/pdb/PdbPlugin.h b/reader/src/formats/pdb/PdbPlugin.h new file mode 100644 index 0000000..9f8600b --- /dev/null +++ b/reader/src/formats/pdb/PdbPlugin.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PDBPLUGIN_H__ +#define __PDBPLUGIN_H__ + +#include <shared_ptr.h> + +#include "../FormatPlugin.h" + +class PdbPlugin : public FormatPlugin { + +public: + static std::string fileType(const ZLFile &file); + bool readLanguageAndEncoding(Book &book) const; + +protected: + PdbPlugin(); + +public: + virtual ~PdbPlugin(); +}; + +class PluckerPlugin : public PdbPlugin { + +public: + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readModel(BookModel &model) const; +}; + +class SimplePdbPlugin : public PdbPlugin { + +public: + bool readMetaInfo(Book &book) const; + bool readModel(BookModel &model) const; + +protected: + virtual shared_ptr<ZLInputStream> createStream(const ZLFile &file) const = 0; + virtual void readDocumentInternal(const ZLFile &file, BookModel &model, const class PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const; +}; + +class PalmDocLikePlugin : public SimplePdbPlugin { + +public: + bool providesMetaInfo() const; + const std::string &tryOpen(const ZLFile &file) const; + +protected: + shared_ptr<ZLInputStream> createStream(const ZLFile &file) const; +}; + +class PalmDocPlugin : public PalmDocLikePlugin { + +public: + bool acceptsFile(const ZLFile &file) const; + + void readDocumentInternal(const ZLFile &file, BookModel &model, const class PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const; + +private: + FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); +}; + +class MobipocketPlugin : public PalmDocLikePlugin { + +private: + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + + void readDocumentInternal(const ZLFile &file, BookModel &model, const class PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const; + shared_ptr<const ZLImage> coverImage(const ZLFile &file) const; +}; + +class EReaderPlugin : public SimplePdbPlugin { + +public: + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + const std::string &tryOpen(const ZLFile &file) const; + + void readDocumentInternal(const ZLFile &file, BookModel &model, const class PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const; +protected: + shared_ptr<ZLInputStream> createStream(const ZLFile &file) const; +}; + +class ZTXTPlugin : public SimplePdbPlugin { + +public: + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + +protected: + shared_ptr<ZLInputStream> createStream(const ZLFile &file) const; + +private: + FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); +}; + +inline PdbPlugin::PdbPlugin() {} + +#endif /* __PDBPLUGIN_H__ */ diff --git a/reader/src/formats/pdb/PdbReader.cpp b/reader/src/formats/pdb/PdbReader.cpp new file mode 100644 index 0000000..54dc654 --- /dev/null +++ b/reader/src/formats/pdb/PdbReader.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> + +#include "PdbReader.h" + +void PdbUtil::readUnsignedShort(ZLInputStream &stream, unsigned short &N) { + unsigned char data[2]; + stream.read((char*)data, 2); + N = (((unsigned short)data[0]) << 8) + data[1]; +} + +void PdbUtil::readUnsignedLongBE(ZLInputStream &stream, unsigned long &N) { + unsigned char data[4]; + stream.read((char*)data, 4); + N = (((unsigned long)data[0]) << 24) + + (((unsigned long)data[1]) << 16) + + (((unsigned long)data[2]) << 8) + + (unsigned long)data[3]; +} + +void PdbUtil::readUnsignedLongLE(ZLInputStream &stream, unsigned long &N) { + unsigned char data[4]; + stream.read((char*)data, 4); + N = (((unsigned long)data[3]) << 24) + + (((unsigned long)data[2]) << 16) + + (((unsigned long)data[1]) << 8) + + (unsigned long)data[0]; +} + +bool PdbHeader::read(shared_ptr<ZLInputStream> stream) { + const std::size_t startOffset = stream->offset(); + DocName.erase(); + DocName.append(32, '\0'); + stream->read((char*)DocName.data(), 32); // stream offset: +32 + + PdbUtil::readUnsignedShort(*stream, Flags); // stream offset: +34 + + stream->seek(26, false); // stream offset: +60 + + Id.erase(); + Id.append(8, '\0'); + stream->read((char*)Id.data(), 8); // stream offset: +68 + + stream->seek(8, false); // stream offset: +76 + Offsets.clear(); + unsigned short numRecords; + PdbUtil::readUnsignedShort(*stream, numRecords); // stream offset: +78 + Offsets.reserve(numRecords); + + for (int i = 0; i < numRecords; ++i) { // stream offset: +78 + 8 * records number + unsigned long recordOffset; + PdbUtil::readUnsignedLongBE(*stream, recordOffset); + Offsets.push_back(recordOffset); + stream->seek(4, false); + } + return stream->offset() == startOffset + 78 + 8 * numRecords; +} + +/*bool PdbRecord0::read(shared_ptr<ZLInputStream> stream) { + std::size_t startOffset = stream->offset(); + + PdbUtil::readUnsignedShort(*stream, CompressionType); + PdbUtil::readUnsignedShort(*stream, Spare); + PdbUtil::readUnsignedLongBE(*stream, TextLength); + PdbUtil::readUnsignedShort(*stream, TextRecords); + PdbUtil::readUnsignedShort(*stream, MaxRecordSize); + PdbUtil::readUnsignedShort(*stream, NontextOffset); + PdbUtil::readUnsignedShort(*stream, NontextOffset2); + + PdbUtil::readUnsignedLongBE(*stream, MobipocketID); + PdbUtil::readUnsignedLongBE(*stream, MobipocketHeaderSize); + PdbUtil::readUnsignedLongBE(*stream, Unknown24); + PdbUtil::readUnsignedShort(*stream, FootnoteRecs); + PdbUtil::readUnsignedShort(*stream, SidebarRecs); + + PdbUtil::readUnsignedShort(*stream, BookmarkOffset); + PdbUtil::readUnsignedShort(*stream, Unknown34); + PdbUtil::readUnsignedShort(*stream, NontextOffset3); + PdbUtil::readUnsignedShort(*stream, Unknown38); + PdbUtil::readUnsignedShort(*stream, ImagedataOffset); + PdbUtil::readUnsignedShort(*stream, ImagedataOffset2); + PdbUtil::readUnsignedShort(*stream, MetadataOffset); + PdbUtil::readUnsignedShort(*stream, MetadataOffset2); + PdbUtil::readUnsignedShort(*stream, FootnoteOffset); + PdbUtil::readUnsignedShort(*stream, SidebarOffset); + PdbUtil::readUnsignedShort(*stream, LastDataOffset); + PdbUtil::readUnsignedShort(*stream, Unknown54); + + return stream->offset() == startOffset + 56; +}*/ diff --git a/reader/src/formats/pdb/PdbReader.h b/reader/src/formats/pdb/PdbReader.h new file mode 100644 index 0000000..f32ebf5 --- /dev/null +++ b/reader/src/formats/pdb/PdbReader.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PDBREADER_H__ +#define __PDBREADER_H__ + +#include <vector> + +#include <shared_ptr.h> +#include <ZLInputStream.h> + +//class BookModel; + +class PdbUtil { + +public: + static void readUnsignedShort(ZLInputStream &stream, unsigned short &N); + static void readUnsignedLongBE(ZLInputStream &stream, unsigned long &N); + static void readUnsignedLongLE(ZLInputStream &stream, unsigned long &N); +}; + +struct PdbHeader { + std::string DocName; + unsigned short Flags; + std::string Id; + std::vector<unsigned long> Offsets; + + bool read(shared_ptr<ZLInputStream> stream); +}; + +struct PdbRecord0 { + unsigned short CompressionType; //[0..2] PalmDoc, Mobipocket, Ereader:version + unsigned short Spare; //[2..4] PalmDoc, Mobipocket + unsigned long TextLength; //[4..8] PalmDoc, Mobipocket + unsigned short TextRecords; //[8..10] PalmDoc, Mobipocket + unsigned short MaxRecordSize; //[10..12] PalmDoc, Mobipocket + unsigned short NontextOffset; //[12..14] Ereader + unsigned short NontextOffset2; //[14..16] Ereader //PalmDoc, Mobipocket: encrypted - there is conflict !!!! + + unsigned long MobipocketID; //[16..20] Mobipocket + unsigned long MobipocketHeaderSize;//[20..24] Mobipocket + unsigned long Unknown24; //[24..28] + unsigned short FootnoteRecs; //[28..30] Ereader + unsigned short SidebarRecs; //[30..32] Ereader + +// Following fields are specific for EReader pdb document specification + + unsigned short BookmarkOffset; //[32..34] + unsigned short Unknown34; //[34..36] + unsigned short NontextOffset3; //[36..38] + unsigned short Unknown38; //[38..40] + unsigned short ImagedataOffset; //[40..42] + unsigned short ImagedataOffset2; //[42..44] + unsigned short MetadataOffset; //[44..46] + unsigned short MetadataOffset2; //[46..48] + unsigned short FootnoteOffset; //[48..50] + unsigned short SidebarOffset; //[50..52] + unsigned short LastDataOffset; //[52..54] + unsigned short Unknown54; //[54..56] + + bool read(shared_ptr<ZLInputStream> stream); +//private: +// static bool readNumberBE(unsigned char* buffer, std::size_t offset, std::size_t size); +}; + +#endif /* __PDBREADER_H__ */ diff --git a/reader/src/formats/pdb/PdbStream.cpp b/reader/src/formats/pdb/PdbStream.cpp new file mode 100644 index 0000000..219a0de --- /dev/null +++ b/reader/src/formats/pdb/PdbStream.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLFile.h> + +#include "PdbStream.h" + +PdbStream::PdbStream(const ZLFile &file) : myBase(file.inputStream()) { + myBuffer = 0; +} + +PdbStream::~PdbStream() { +} + +bool PdbStream::open() { + close(); + if (myBase.isNull() || !myBase->open() || !myHeader.read(myBase)) { + return false; + } + // myBase offset: startOffset + 78 + 8 * records number ( myHeader.Offsets.size() ) + + myBase->seek(myHeader.Offsets[0], true); + // myBase offset: Offset[0] - zero record + + myBufferLength = 0; + myBufferOffset = 0; + + myOffset = 0; + + return true; +} + +std::size_t PdbStream::read(char *buffer, std::size_t maxSize) { + std::size_t realSize = 0; + while (realSize < maxSize) { + if (!fillBuffer()) { + break; + } + std::size_t size = std::min((std::size_t)(maxSize - realSize), (std::size_t)(myBufferLength - myBufferOffset)); + + if (size > 0) { + if (buffer != 0) { + std::memcpy(buffer + realSize, myBuffer + myBufferOffset, size); + } + realSize += size; + myBufferOffset += size; + } + } + + myOffset += realSize; + return realSize; +} + +void PdbStream::close() { + if (!myBase.isNull()) { + myBase->close(); + } + if (myBuffer != 0) { + delete[] myBuffer; + myBuffer = 0; + } +} + +void PdbStream::seek(int offset, bool absoluteOffset) { + if (absoluteOffset) { + offset -= this->offset(); + } + if (offset > 0) { + read(0, offset); + } else if (offset < 0) { + offset += this->offset(); + open(); + if (offset >= 0) { + read(0, offset); + } + } +} + +std::size_t PdbStream::offset() const { + return myOffset; +} + +std::size_t PdbStream::sizeOfOpened() { + // TODO: implement + return 0; +} + +std::size_t PdbStream::recordOffset(std::size_t index) const { + return index < myHeader.Offsets.size() ? + myHeader.Offsets[index] : myBase->sizeOfOpened(); +} diff --git a/reader/src/formats/pdb/PdbStream.h b/reader/src/formats/pdb/PdbStream.h new file mode 100644 index 0000000..f2c58f1 --- /dev/null +++ b/reader/src/formats/pdb/PdbStream.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PDBSTREAM_H__ +#define __PDBSTREAM_H__ + +#include <ZLInputStream.h> + +#include "PdbReader.h" + +class ZLFile; + +class PdbStream : public ZLInputStream { + +public: + PdbStream(const ZLFile &file); + virtual ~PdbStream(); + +protected: + virtual bool open(); + virtual void close(); + +private: + std::size_t read(char *buffer, std::size_t maxSize); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +protected: + virtual bool fillBuffer() = 0; + +protected: + std::size_t recordOffset(std::size_t index) const; + +public: + const PdbHeader &header() const; + +protected: + shared_ptr<ZLInputStream> myBase; + std::size_t myOffset; + +private: + PdbHeader myHeader; + +protected: + char *myBuffer; + unsigned short myBufferLength; + unsigned short myBufferOffset; +}; + +inline const PdbHeader &PdbStream::header() const { + return myHeader; +} + +#endif /* __PDBSTREAM_H__ */ diff --git a/reader/src/formats/pdb/PluckerBookReader.cpp b/reader/src/formats/pdb/PluckerBookReader.cpp new file mode 100644 index 0000000..61bc311 --- /dev/null +++ b/reader/src/formats/pdb/PluckerBookReader.cpp @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> +#include <vector> +#include <cctype> + +#include <ZLZDecompressor.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLImage.h> +#include <ZLFileImage.h> +#include <ZLFile.h> +#include <ZLTextStyleEntry.h> + +#include "PdbReader.h" +#include "PluckerBookReader.h" +#include "DocDecompressor.h" +#include "PluckerImages.h" +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +PluckerBookReader::PluckerBookReader(BookModel &model) : BookReader(model), EncodedTextReader(model.book()->encoding()), myFile(model.book()->file()), myFont(FT_REGULAR) { + myCharBuffer = new char[65535]; + myForcedEntry = 0; +} + +PluckerBookReader::~PluckerBookReader() { + delete[] myCharBuffer; +} + +void PluckerBookReader::safeAddControl(FBTextKind kind, bool start) { + if (myParagraphStarted) { + addControl(kind, start); + } else { + myDelayedControls.push_back(std::make_pair(kind, start)); + } +} + +void PluckerBookReader::safeAddHyperlinkControl(const std::string &id) { + if (myParagraphStarted) { + addHyperlinkControl(INTERNAL_HYPERLINK, id); + } else { + myDelayedHyperlinks.push_back(id); + } +} + +void PluckerBookReader::safeBeginParagraph() { + if (!myParagraphStarted) { + myParagraphStarted = true; + myBufferIsEmpty = true; + beginParagraph(); + if (!myParagraphStored) { + myParagraphVector->push_back(model().bookTextModel()->paragraphsNumber() - 1); + myParagraphStored = true; + } + for (std::vector<std::pair<FBTextKind,bool> >::const_iterator it = myDelayedControls.begin(); it != myDelayedControls.end(); ++it) { + addControl(it->first, it->second); + } + if (myForcedEntry != 0) { + addStyleEntry(*myForcedEntry); + } else { + addControl(REGULAR, true); + } + for (std::vector<std::string>::const_iterator it = myDelayedHyperlinks.begin(); it != myDelayedHyperlinks.end(); ++it) { + addHyperlinkControl(INTERNAL_HYPERLINK, *it); + } + myDelayedHyperlinks.clear(); + } +} + + +void PluckerBookReader::safeEndParagraph() { + if (myParagraphStarted) { + if (myBufferIsEmpty) { + static const std::string SPACE = " "; + addData(SPACE); + } + endParagraph(); + myParagraphStarted = false; + } +} + +void PluckerBookReader::processHeader(FontType font, bool start) { + if (start) { + enterTitle(); + FBTextKind kind; + switch (font) { + case FT_H1: + kind = H1; + break; + case FT_H2: + kind = H2; + break; + case FT_H3: + kind = H3; + break; + case FT_H4: + kind = H4; + break; + case FT_H5: + kind = H5; + break; + case FT_H6: + default: + kind = H6; + break; + } + pushKind(kind); + } else { + popKind(); + exitTitle(); + } +}; + +void PluckerBookReader::setFont(FontType font, bool start) { + switch (font) { + case FT_REGULAR: + break; + case FT_H1: + case FT_H2: + case FT_H3: + case FT_H4: + case FT_H5: + case FT_H6: + processHeader(font, start); + break; + case FT_BOLD: + safeAddControl(BOLD, start); + break; + case FT_TT: + safeAddControl(CODE, start); + break; + case FT_SMALL: + break; + case FT_SUB: + safeAddControl(SUB, start); + break; + case FT_SUP: + safeAddControl(SUP, start); + break; + } +} + +void PluckerBookReader::changeFont(FontType font) { + if (myFont == font) { + return; + } + setFont(myFont, false); + myFont = font; + setFont(myFont, true); +} + +/* +static void listParameters(char *ptr) { + int argc = ((unsigned char)*ptr) % 8; + std::cerr << (int)(unsigned char)*ptr << "("; + for (int i = 0; i < argc - 1; ++i) { + ++ptr; + std::cerr << (int)*ptr << ", "; + } + if (argc > 0) { + ++ptr; + std::cerr << (int)*ptr; + } + std::cerr << ")\n"; +} +*/ + +static unsigned int twoBytes(char *ptr) { + return 256 * (unsigned char)*ptr + (unsigned char)*(ptr + 1); +} + +static unsigned int fourBytes(char *ptr) { + return 65536 * twoBytes(ptr) + twoBytes(ptr + 2); +} + +static std::string fromNumber(unsigned int num) { + std::string str; + ZLStringUtil::appendNumber(str, num); + return str; +} + +void PluckerBookReader::processTextFunction(char *ptr) { + switch ((unsigned char)*ptr) { + case 0x08: + safeAddControl(INTERNAL_HYPERLINK, false); + break; + case 0x0A: + safeAddHyperlinkControl(fromNumber(twoBytes(ptr + 1))); + break; + case 0x0C: + { + int sectionNum = twoBytes(ptr + 1); + int paragraphNum = twoBytes(ptr + 3); + safeAddHyperlinkControl(fromNumber(sectionNum) + '#' + fromNumber(paragraphNum)); + myReferencedParagraphs.insert(std::make_pair(sectionNum, paragraphNum)); + break; + } + case 0x11: + changeFont((FontType)*(ptr + 1)); + break; + case 0x1A: + safeBeginParagraph(); + addImageReference(fromNumber(twoBytes(ptr + 1))); + break; + case 0x22: + if (!myParagraphStarted) { + if (myForcedEntry == 0) { + myForcedEntry = new ZLTextStyleEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + } + myForcedEntry->setLength( + ZLTextStyleEntry::LENGTH_LEFT_INDENT, + *(ptr + 1), ZLTextStyleEntry::SIZE_UNIT_PIXEL + ); + myForcedEntry->setLength( + ZLTextStyleEntry::LENGTH_RIGHT_INDENT, + *(ptr + 2), ZLTextStyleEntry::SIZE_UNIT_PIXEL + ); + } + break; + case 0x29: + if (!myParagraphStarted) { + if (myForcedEntry == 0) { + myForcedEntry = new ZLTextStyleEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + } + switch (*(ptr + 1)) { + case 0: myForcedEntry->setAlignmentType(ALIGN_LEFT); break; + case 1: myForcedEntry->setAlignmentType(ALIGN_RIGHT); break; + case 2: myForcedEntry->setAlignmentType(ALIGN_CENTER); break; + case 3: myForcedEntry->setAlignmentType(ALIGN_JUSTIFY); break; + } + } + break; + case 0x33: // just break line instead of horizontal rule (TODO: draw horizontal rule?) + safeEndParagraph(); + break; + case 0x38: + safeEndParagraph(); + break; + case 0x40: + safeAddControl(EMPHASIS, true); + break; + case 0x48: + safeAddControl(EMPHASIS, false); + break; + case 0x53: // color setting is ignored + break; + case 0x5C: + addImageReference(fromNumber(twoBytes(ptr + 3))); + break; + case 0x60: // underlined text is ignored + break; + case 0x68: // underlined text is ignored + break; + case 0x70: // strike-through text is ignored + break; + case 0x78: // strike-through text is ignored + break; + case 0x83: + case 0x85: + { + ZLUnicodeUtil::Ucs4Char symbol = + (((unsigned char)*ptr) == 0x83) ? twoBytes(ptr + 2) : fourBytes(ptr + 2); + char utf8[6]; + int len = ZLUnicodeUtil::ucs4ToUtf8(utf8, symbol); + safeBeginParagraph(); + addData(std::string(utf8, len)); + myBufferIsEmpty = false; + myBytesToSkip = *(ptr + 1); + break; + } + case 0x8E: // custom font operations are ignored + case 0x8C: + case 0x8A: + case 0x88: + break; + case 0x90: // TODO: add table processing + case 0x92: // TODO: process table + case 0x97: // TODO: process table + break; + default: // this should be impossible + //std::cerr << "Oops... function #" << (int)(unsigned char)*ptr << "\n"; + break; + } +} + +void PluckerBookReader::processTextParagraph(char *start, char *end) { + changeFont(FT_REGULAR); + while (popKind()) {} + + myParagraphStarted = false; + myBytesToSkip = 0; + + char *textStart = start; + bool functionFlag = false; + for (char *ptr = start; ptr < end; ++ptr) { + if (*ptr == 0) { + functionFlag = true; + if (ptr > textStart) { + safeBeginParagraph(); + myConvertedTextBuffer.erase(); + myConverter->convert(myConvertedTextBuffer, textStart, ptr); + addData(myConvertedTextBuffer); + myBufferIsEmpty = false; + } + } else if (functionFlag) { + int paramCounter = ((unsigned char)*ptr) % 8; + if (end - ptr > paramCounter) { + processTextFunction(ptr); + ptr += paramCounter; + } else { + ptr = end - 1; + } + functionFlag = false; + if (myBytesToSkip > 0) { + ptr += myBytesToSkip; + myBytesToSkip = 0; + } + textStart = ptr + 1; + } else { + if ((unsigned char)*ptr == 0xA0) { + *ptr = 0x20; + } + if (!myParagraphStarted && textStart == ptr && std::isspace((unsigned char)*ptr)) { + ++textStart; + } + } + } + if (end > textStart) { + safeBeginParagraph(); + myConvertedTextBuffer.erase(); + myConverter->convert(myConvertedTextBuffer, textStart, end); + addData(myConvertedTextBuffer); + myBufferIsEmpty = false; + } + safeEndParagraph(); + if (myForcedEntry != 0) { + delete myForcedEntry; + myForcedEntry = 0; + } + myDelayedControls.clear(); +} + +void PluckerBookReader::processTextRecord(std::size_t size, const std::vector<int> &pars) { + char *start = myCharBuffer; + char *end = myCharBuffer; + + for (std::vector<int>::const_iterator it = pars.begin(); it != pars.end(); ++it) { + start = end; + end = start + *it; + if (end > myCharBuffer + size) { + return; + } + myParagraphStored = false; + processTextParagraph(start, end); + if (!myParagraphStored) { + myParagraphVector->push_back(-1); + } + } +} + +void PluckerBookReader::readRecord(std::size_t recordSize) { + unsigned short uid; + PdbUtil::readUnsignedShort(*myStream, uid); + if (uid == 1) { + PdbUtil::readUnsignedShort(*myStream, myCompressionVersion); + } else { + unsigned short paragraphs; + PdbUtil::readUnsignedShort(*myStream, paragraphs); + + unsigned short size; + PdbUtil::readUnsignedShort(*myStream, size); + + unsigned char type; + myStream->read((char*)&type, 1); + + unsigned char flags; + myStream->read((char*)&flags, 1); + + switch (type) { + case 0: // text (TODO: found sample file and test this code) + case 1: // compressed text + { + std::vector<int> pars; + for (int i = 0; i < paragraphs; ++i) { + unsigned short pSize; + PdbUtil::readUnsignedShort(*myStream, pSize); + pars.push_back(pSize); + myStream->seek(2, false); + } + + bool doProcess = false; + if (type == 0) { + doProcess = myStream->read(myCharBuffer, size) == size; + } else if (myCompressionVersion == 1) { + doProcess = + DocDecompressor().decompress(*myStream, myCharBuffer, recordSize - 8 - 4 * paragraphs, size) == size; + } else if (myCompressionVersion == 2) { + myStream->seek(2, false); + doProcess = + ZLZDecompressor(recordSize - 10 - 4 * paragraphs). + decompress(*myStream, myCharBuffer, size) == size; + } + if (doProcess) { + addHyperlinkLabel(fromNumber(uid)); + myParagraphVector = &myParagraphMap[uid]; + processTextRecord(size, pars); + if ((flags & 0x1) == 0) { + insertEndOfTextParagraph(); + } + } + break; + } + case 2: // image + case 3: // compressed image + { + ZLImage *image = 0; + const ZLFile imageFile(myFile.path(), ZLMimeType::IMAGE_PALM); + if (type == 2) { + image = new ZLFileImage(imageFile, myStream->offset(), recordSize - 8); + } else if (myCompressionVersion == 1) { + image = new DocCompressedFileImage(imageFile, myStream->offset(), recordSize - 8); + } else if (myCompressionVersion == 2) { + image = new ZCompressedFileImage(imageFile, myStream->offset() + 2, recordSize - 10); + } + if (image != 0) { + addImage(fromNumber(uid), image); + } + break; + } + case 9: // category record is ignored + break; + case 10: + unsigned short typeCode; + PdbUtil::readUnsignedShort(*myStream, typeCode); + //std::cerr << "type = " << (int)type << "; "; + //std::cerr << "typeCode = " << typeCode << "\n"; + break; + case 11: // style sheet record is ignored + break; + case 12: // font page record is ignored + break; + case 13: // TODO: process tables + case 14: // TODO: process tables + break; + case 15: // multiimage + { + unsigned short columns; + unsigned short rows; + PdbUtil::readUnsignedShort(*myStream, columns); + PdbUtil::readUnsignedShort(*myStream, rows); + PluckerMultiImage *image = new PluckerMultiImage(rows, columns, model().imageMap()); + for (int i = 0; i < size / 2 - 2; ++i) { + unsigned short us; + PdbUtil::readUnsignedShort(*myStream, us); + image->addId(fromNumber(us)); + } + addImage(fromNumber(uid), image); + break; + } + default: + //std::cerr << "type = " << (int)type << "\n"; + break; + } + } +} + +bool PluckerBookReader::readDocument() { + myStream = myFile.inputStream(); + if (myStream.isNull() || !myStream->open()) { + return false; + } + + PdbHeader header; + if (!header.read(myStream)) { + myStream->close(); + return false; + } + + setMainTextModel(); + myFont = FT_REGULAR; + + for (std::vector<unsigned long>::const_iterator it = header.Offsets.begin(); it != header.Offsets.end(); ++it) { + std::size_t currentOffset = myStream->offset(); + if (currentOffset > *it) { + break; + } + myStream->seek(*it - currentOffset, false); + if (myStream->offset() != *it) { + break; + } + std::size_t recordSize = ((it != header.Offsets.end() - 1) ? *(it + 1) : myStream->sizeOfOpened()) - *it; + readRecord(recordSize); + } + myStream->close(); + + for (std::set<std::pair<int,int> >::const_iterator it = myReferencedParagraphs.begin(); it != myReferencedParagraphs.end(); ++it) { + std::map<int,std::vector<int> >::const_iterator jt = myParagraphMap.find(it->first); + if (jt != myParagraphMap.end()) { + for (unsigned int k = it->second; k < jt->second.size(); ++k) { + if (jt->second[k] != -1) { + addHyperlinkLabel(fromNumber(it->first) + '#' + fromNumber(it->second), jt->second[k]); + break; + } + } + } + } + myReferencedParagraphs.clear(); + myParagraphMap.clear(); + return true; +} diff --git a/reader/src/formats/pdb/PluckerBookReader.h b/reader/src/formats/pdb/PluckerBookReader.h new file mode 100644 index 0000000..1078f37 --- /dev/null +++ b/reader/src/formats/pdb/PluckerBookReader.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PLUCKERBOOKREADER_H__ +#define __PLUCKERBOOKREADER_H__ + +#include <set> +#include <map> + +#include <ZLEncodingConverter.h> + +#include "../../bookmodel/BookReader.h" +#include "../EncodedTextReader.h" + +class PluckerBookReader : public BookReader, public EncodedTextReader { + +public: + PluckerBookReader(BookModel &model); + ~PluckerBookReader(); + + bool readDocument(); + +private: + enum FontType { + FT_REGULAR = 0, + FT_H1 = 1, + FT_H2 = 2, + FT_H3 = 3, + FT_H4 = 4, + FT_H5 = 5, + FT_H6 = 6, + FT_BOLD = 7, + FT_TT = 8, + FT_SMALL = 9, + FT_SUB = 10, + FT_SUP = 11 + }; + + void readRecord(std::size_t recordSize); + void processTextRecord(std::size_t size, const std::vector<int> &pars); + void processTextParagraph(char *start, char *end); + void processTextFunction(char *ptr); + void setFont(FontType font, bool start); + void changeFont(FontType font); + + void safeAddControl(FBTextKind kind, bool start); + void safeAddHyperlinkControl(const std::string &id); + void safeBeginParagraph(); + void safeEndParagraph(); + + void processHeader(FontType font, bool start); + +private: + const ZLFile myFile; + shared_ptr<ZLInputStream> myStream; + FontType myFont; + char *myCharBuffer; + std::string myConvertedTextBuffer; + bool myParagraphStarted; + bool myBufferIsEmpty; + ZLTextStyleEntry *myForcedEntry; + std::vector<std::pair<FBTextKind,bool> > myDelayedControls; + std::vector<std::string> myDelayedHyperlinks; + unsigned short myCompressionVersion; + unsigned char myBytesToSkip; + + std::set<std::pair<int, int> > myReferencedParagraphs; + std::map<int, std::vector<int> > myParagraphMap; + std::vector<int> *myParagraphVector; + bool myParagraphStored; +}; + +#endif /* __PLUCKERBOOKREADER_H__ */ diff --git a/reader/src/formats/pdb/PluckerImages.cpp b/reader/src/formats/pdb/PluckerImages.cpp new file mode 100644 index 0000000..db291ab --- /dev/null +++ b/reader/src/formats/pdb/PluckerImages.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> +#include <ZLZDecompressor.h> +#include <ZLStringUtil.h> + +#include "PluckerImages.h" +#include "DocDecompressor.h" + +const shared_ptr<std::string> ZCompressedFileImage::stringData() const { + shared_ptr<ZLInputStream> stream = myFile.inputStream(); + + shared_ptr<std::string> imageData = new std::string(); + + if (!stream.isNull() && stream->open()) { + stream->seek(myOffset, false); + ZLZDecompressor decompressor(myCompressedSize); + + static const std::size_t charBufferSize = 2048; + char *charBuffer = new char[charBufferSize]; + std::vector<std::string> buffer; + + std::size_t s; + do { + s = decompressor.decompress(*stream, charBuffer, charBufferSize); + if (s != 0) { + buffer.push_back(std::string()); + buffer.back().append(charBuffer, s); + } + } while (s == charBufferSize); + ZLStringUtil::append(*imageData, buffer); + + delete[] charBuffer; + } + + return imageData; +} + +const shared_ptr<std::string> DocCompressedFileImage::stringData() const { + shared_ptr<ZLInputStream> stream = myFile.inputStream(); + + shared_ptr<std::string> imageData = new std::string(); + + if (!stream.isNull() && stream->open()) { + stream->seek(myOffset, false); + char *buffer = new char[65535]; + std::size_t uncompressedSize = DocDecompressor().decompress(*stream, buffer, myCompressedSize, 65535); + imageData->append(buffer, uncompressedSize); + delete[] buffer; + } + + return imageData; +} + +shared_ptr<const ZLImage> PluckerMultiImage::subImage(unsigned int row, unsigned int column) const { + unsigned int index = row * myColumns + column; + if (index >= myIds.size()) { + return 0; + } + ZLImageMap::const_iterator entry = myImageMap.find(myIds[index]); + return (entry != myImageMap.end()) ? entry->second : 0; +} diff --git a/reader/src/formats/pdb/PluckerImages.h b/reader/src/formats/pdb/PluckerImages.h new file mode 100644 index 0000000..3269a29 --- /dev/null +++ b/reader/src/formats/pdb/PluckerImages.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PLUCKERIMAGES_H__ +#define __PLUCKERIMAGES_H__ + +#include <string> + +#include <ZLImage.h> +#include <ZLFile.h> +#include "../../bookmodel/BookModel.h" + +class ZCompressedFileImage : public ZLSingleImage { + +public: + ZCompressedFileImage(const ZLFile &file, std::size_t offset, std::size_t size); + const shared_ptr<std::string> stringData() const; + +private: + const ZLFile myFile; + const std::size_t myOffset; + const std::size_t myCompressedSize; +}; + +class DocCompressedFileImage : public ZLSingleImage { + +public: + DocCompressedFileImage(const ZLFile &file, std::size_t offset, std::size_t compressedSize); + const shared_ptr<std::string> stringData() const; + +private: + const ZLFile myFile; + const std::size_t myOffset; + const std::size_t myCompressedSize; +}; + +class PluckerMultiImage : public ZLMultiImage { + +public: + PluckerMultiImage(unsigned int rows, unsigned int columns, const ZLImageMap &imageMap); + + void addId(const std::string &id); + + unsigned int rows() const; + unsigned int columns() const; + shared_ptr<const ZLImage> subImage(unsigned int row, unsigned int column) const; + +private: + unsigned int myRows, myColumns; + const ZLImageMap &myImageMap; + std::vector<std::string> myIds; +}; + +inline ZCompressedFileImage::ZCompressedFileImage(const ZLFile &file, std::size_t offset, std::size_t compressedSize) : ZLSingleImage(file.mimeType()), myFile(file), myOffset(offset), myCompressedSize(compressedSize) {} + +inline DocCompressedFileImage::DocCompressedFileImage(const ZLFile &file, std::size_t offset, std::size_t compressedSize) : ZLSingleImage(file.mimeType()), myFile(file), myOffset(offset), myCompressedSize(compressedSize) {} + +inline PluckerMultiImage::PluckerMultiImage(unsigned int rows, unsigned int columns, const ZLImageMap &imageMap) : myRows(rows), myColumns(columns), myImageMap(imageMap) {} +inline void PluckerMultiImage::addId(const std::string &id) { myIds.push_back(id); } +inline unsigned int PluckerMultiImage::rows() const { return myRows; } +inline unsigned int PluckerMultiImage::columns() const { return myColumns; } + +#endif /* __PLUCKERIMAGES_H__ */ diff --git a/reader/src/formats/pdb/PluckerPlugin.cpp b/reader/src/formats/pdb/PluckerPlugin.cpp new file mode 100644 index 0000000..1ec89ba --- /dev/null +++ b/reader/src/formats/pdb/PluckerPlugin.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> + +#include "PdbPlugin.h" +#include "PluckerBookReader.h" +#include "PluckerTextStream.h" + +#include "../../library/Book.h" + +bool PluckerPlugin::providesMetaInfo() const { + return false; +} + +bool PluckerPlugin::acceptsFile(const ZLFile &file) const { + return PdbPlugin::fileType(file) == "DataPlkr"; +} + +bool PluckerPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = new PluckerTextStream(book.file()); + detectEncodingAndLanguage(book, *stream); + if (book.encoding().empty()) { + return false; + } + + return true; +} + +bool PluckerPlugin::readModel(BookModel &model) const { + return PluckerBookReader(model).readDocument(); +} diff --git a/reader/src/formats/pdb/PluckerTextStream.cpp b/reader/src/formats/pdb/PluckerTextStream.cpp new file mode 100644 index 0000000..01291eb --- /dev/null +++ b/reader/src/formats/pdb/PluckerTextStream.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLFile.h> +#include <ZLZDecompressor.h> + +#include "PluckerTextStream.h" +#include "PdbReader.h" +#include "DocDecompressor.h" + +PluckerTextStream::PluckerTextStream(const ZLFile &file) : PdbStream(file) { + myFullBuffer = 0; +} + +PluckerTextStream::~PluckerTextStream() { + close(); +} + +bool PluckerTextStream::open() { + if (!PdbStream::open()) { + return false; + } + + PdbUtil::readUnsignedShort(*myBase, myCompressionVersion); + + myBuffer = new char[65536]; + myFullBuffer = new char[65536]; + + myRecordIndex = 0; + + return true; +} + +bool PluckerTextStream::fillBuffer() { + while (myBufferOffset == myBufferLength) { + if (myRecordIndex + 1 > header().Offsets.size() - 1) { + return false; + } + ++myRecordIndex; + const std::size_t currentOffset = recordOffset(myRecordIndex); + if (currentOffset < myBase->offset()) { + return false; + } + myBase->seek(currentOffset, true); + const std::size_t nextOffset = recordOffset(myRecordIndex + 1); + if (nextOffset < currentOffset) { + return false; + } + processRecord(nextOffset - currentOffset); + } + return true; +} + +void PluckerTextStream::close() { + if (myFullBuffer != 0) { + delete[] myFullBuffer; + myFullBuffer = 0; + } + PdbStream::close(); +} + +void PluckerTextStream::processRecord(std::size_t recordSize) { + myBase->seek(2, false); + + unsigned short paragraphs; + PdbUtil::readUnsignedShort(*myBase, paragraphs); + + unsigned short size; + PdbUtil::readUnsignedShort(*myBase, size); + + unsigned char type; + myBase->read((char*)&type, 1); + if (type > 1) { // this record is not text record + return; + } + + myBase->seek(1, false); + + std::vector<int> pars; + for (int i = 0; i < paragraphs; ++i) { + unsigned short pSize; + PdbUtil::readUnsignedShort(*myBase, pSize); + pars.push_back(pSize); + myBase->seek(2, false); + } + + bool doProcess = false; + if (type == 0) { + doProcess = myBase->read(myFullBuffer, size) == size; + } else if (myCompressionVersion == 1) { + doProcess = + DocDecompressor().decompress(*myBase, myFullBuffer, recordSize - 8 - 4 * paragraphs, size) == size; + } else if (myCompressionVersion == 2) { + myBase->seek(2, false); + doProcess = + ZLZDecompressor(recordSize - 10 - 4 * paragraphs).decompress(*myBase, myFullBuffer, size) == size; + } + if (doProcess) { + myBufferLength = 0; + myBufferOffset = 0; + + char *start = myFullBuffer; + char *end = myFullBuffer; + + for (std::vector<int>::const_iterator it = pars.begin(); it != pars.end(); ++it) { + start = end; + end = start + *it; + if (end > myFullBuffer + size) { + break; + } + processTextParagraph(start, end); + } + } +} + +void PluckerTextStream::processTextParagraph(char *start, char *end) { + char *textStart = start; + bool functionFlag = false; + for (char *ptr = start; ptr < end; ++ptr) { + if (*ptr == 0) { + functionFlag = true; + if (ptr != textStart) { + std::memcpy(myBuffer + myBufferLength, textStart, ptr - textStart); + myBufferLength += ptr - textStart; + } + } else if (functionFlag) { + int paramCounter = ((unsigned char)*ptr) % 8; + if (end - ptr > paramCounter + 1) { + ptr += paramCounter; + } else { + ptr = end - 1; + } + functionFlag = false; + textStart = ptr + 1; + } + } + if (end != textStart) { + std::memcpy(myBuffer + myBufferLength, textStart, end - textStart); + myBufferLength += end - textStart; + } +} diff --git a/reader/src/formats/pdb/PluckerTextStream.h b/reader/src/formats/pdb/PluckerTextStream.h new file mode 100644 index 0000000..70c1182 --- /dev/null +++ b/reader/src/formats/pdb/PluckerTextStream.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PLUCKERTEXTSTREAM_H__ +#define __PLUCKERTEXTSTREAM_H__ + +#include "PdbStream.h" + +class ZLFile; + +class PluckerTextStream : public PdbStream { + +public: + PluckerTextStream(const ZLFile &file); + ~PluckerTextStream(); + bool open(); + void close(); + +private: + bool fillBuffer(); + +private: + void processRecord(std::size_t recordSize); + void processTextParagraph(char *start, char *end); + +private: + unsigned short myCompressionVersion; + char *myFullBuffer; + std::size_t myRecordIndex; +}; + +#endif /* __PLUCKERTEXTSTREAM_H__ */ diff --git a/reader/src/formats/pdb/PmlBookReader.cpp b/reader/src/formats/pdb/PmlBookReader.cpp new file mode 100644 index 0000000..e365983 --- /dev/null +++ b/reader/src/formats/pdb/PmlBookReader.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLTextParagraph.h> +#include <ZLUnicodeUtil.h> +#include <ZLStringUtil.h> +#include <ZLTextStyleEntry.h> + +#include "PmlBookReader.h" +#include "../../bookmodel/BookModel.h" + +PmlBookReader::PmlBookReader(BookReader &bookReader, const PlainTextFormat&, const std::string &encoding) : PmlReader(encoding), myBookReader(bookReader) { +} + +PmlBookReader::~PmlBookReader() { +} + +bool PmlBookReader::readDocument(ZLInputStream& stream) { + myBookReader.pushKind(REGULAR); + myBookReader.beginParagraph(); + myParagraphIsEmpty = true; + bool code = PmlReader::readDocument(stream); + myBookReader.endParagraph(); + return code; +} + +void PmlBookReader::addCharData(const char *data, std::size_t len, bool convert) { + if (!myBookReader.paragraphIsOpen()) { + myBookReader.beginParagraph(); + } + static std::string newString; + if (len != 0) { + if (!myConverter.isNull() && convert) { + myConverter->convert(newString, data, data + len); + } else { + newString.append(data, len); + } + if (myState.SmallCaps) { + myBookReader.addData(ZLUnicodeUtil::toUpper(newString)); + } else { + myBookReader.addData(newString); + } + newString.erase(); + if (myParagraphIsEmpty) { + myParagraphIsEmpty = false; + } + } +} + +void PmlBookReader::switchFontProperty(FontProperty property) { + if (!myBookReader.paragraphIsOpen()) { + myBookReader.beginParagraph(); + } + switch (property) { + case FONT_BOLD: + if (myState.Bold) { + myBookReader.pushKind(STRONG); + } else { + myBookReader.popKind(); + } + myBookReader.addControl(STRONG, myState.Bold); + break; + case FONT_ITALIC: + if (myState.Italic) { + if (!myState.Bold) { + myBookReader.pushKind(EMPHASIS); + myBookReader.addControl(EMPHASIS, true); + } else { + myBookReader.popKind(); + myBookReader.addControl(STRONG, false); + + myBookReader.pushKind(EMPHASIS); + myBookReader.addControl(EMPHASIS, true); + myBookReader.pushKind(STRONG); + myBookReader.addControl(STRONG, true); + } + } else { + if (!myState.Bold) { + myBookReader.addControl(EMPHASIS, false); + myBookReader.popKind(); + } else { + myBookReader.addControl(STRONG, false); + myBookReader.popKind(); + myBookReader.addControl(EMPHASIS, false); + myBookReader.popKind(); + + myBookReader.pushKind(STRONG); + myBookReader.addControl(STRONG, true); + } + } + break; + case FONT_UNDERLINED: + break; + case FONT_SUBSCRIPT: //don't have to be mixed with other style tags + if (myState.Subscript) { + myBookReader.pushKind(SUB); + } else { + myBookReader.popKind(); + } + myBookReader.addControl(SUB, myState.Subscript); + break; + case FONT_SUPERSCRIPT: //Should not be mixed with other style tags + if (myState.Superscript) { + myBookReader.pushKind(SUP); + } else { + myBookReader.popKind(); + } + myBookReader.addControl(SUP, myState.Superscript); + break; + } +} + +void PmlBookReader::newLine() { + if (myBookReader.paragraphIsOpen()) { + myBookReader.endParagraph(); + } + if (myParagraphIsEmpty) { + myBookReader.beginParagraph(ZLTextParagraph::EMPTY_LINE_PARAGRAPH); + myBookReader.endParagraph(); + } else { + myParagraphIsEmpty = true; + } + newParagraph(); +} + +void PmlBookReader::newPage() { + if (myBookReader.paragraphIsOpen()) { + myBookReader.endParagraph(); + } + //newLine(); + newParagraph(); +} + +void PmlBookReader::newParagraph() { + if (myBookReader.paragraphIsOpen()) { + myBookReader.endParagraph(); + } + myBookReader.beginParagraph(); + if (myState.Alignment != ALIGN_UNDEFINED) { + setAlignment(); + } + if (myState.FontSize != NORMAL) { + setFontSize(); + } + if (myState.IndentBlockOn && (myState.Indent != 0)) { + setIndent(); + } +} + +void PmlBookReader::setAlignment() { + ZLTextStyleEntry entry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + entry.setAlignmentType(myState.Alignment); + myBookReader.addStyleEntry(entry); +} + +void PmlBookReader::setIndent() { + ZLTextStyleEntry entry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + entry.setLength(ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, 0, ZLTextStyleEntry::SIZE_UNIT_PERCENT); + entry.setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, (short)myState.Indent, ZLTextStyleEntry::SIZE_UNIT_PERCENT); + myBookReader.addStyleEntry(entry); +} + +void PmlBookReader::setFontSize() { + if (!myBookReader.paragraphIsOpen()) { + myBookReader.beginParagraph(); + } + ZLTextStyleEntry entry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + switch(myState.FontSize) { + case SMALLER: + entry.setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_SMALLER, true); + break; + case LARGER: + entry.setFontModifier(ZLTextStyleEntry::FONT_MODIFIER_LARGER, true); + break; + default: + break; + } + myBookReader.addStyleEntry(entry); +} + +void PmlBookReader::addLink(FBTextKind kind, const std::string &id, bool on) { + switch (kind) { + case INTERNAL_HYPERLINK: + case FOOTNOTE: + //case EXTERNAL_HYPERLINK: + //case BOOK_HYPERLINK: + if (on) { + myBookReader.addHyperlinkControl(kind, id); + } else { + myBookReader.addControl(kind, false); + } + break; + default: + break; + } +} + +void PmlBookReader::addLinkLabel(const std::string &label) { + myBookReader.addHyperlinkLabel(label); +} + +void PmlBookReader::addImageReference(const std::string &id) { + const bool stopParagraph = myBookReader.paragraphIsOpen(); + if (stopParagraph) { + myBookReader.endParagraph(); + } + myBookReader.addImageReference(id); + if (stopParagraph) { + myBookReader.beginParagraph(); + } +} diff --git a/reader/src/formats/pdb/PmlBookReader.h b/reader/src/formats/pdb/PmlBookReader.h new file mode 100644 index 0000000..22944b4 --- /dev/null +++ b/reader/src/formats/pdb/PmlBookReader.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PMLBOOKREADER_H__ +#define __PMLBOOKREADER_H__ + +#include <string> + +#include "PmlReader.h" +#include "../../bookmodel/BookReader.h" +#include "../txt/PlainTextFormat.h" + +class PmlBookReader : public PmlReader { + +public: + PmlBookReader(BookReader &bookReader, const PlainTextFormat &format, const std::string &encoding); + ~PmlBookReader(); + + bool readDocument(ZLInputStream &stream); + +protected: + void addCharData(const char *data, std::size_t len, bool convert); + void addLink(FBTextKind kind, const std::string &id, bool on); + void addLinkLabel(const std::string &label); + void addImageReference(const std::string &id); + void switchFontProperty(FontProperty property); + void setFontSize(); + void newLine(); + void newPage(); + void newParagraph(); + +private: + void setAlignment(); + void setIndent(); + +private: + BookReader& myBookReader; + bool myParagraphIsEmpty; + + /*FontType myFont; + char *myCharBuffer; + std::string myConvertedTextBuffer; + bool myParagraphStarted; + bool myBufferIsEmpty; + ZLTextStyleEntry *myForcedEntry; + std::vector<std::pair<FBTextKind,bool> > myDelayedControls; + std::vector<std::string> myDelayedHyperlinks; + unsigned short myCompressionVersion; + unsigned char myBytesToSkip; + + std::set<std::pair<int, int> > myReferencedParagraphs; + std::map<int, std::vector<int> > myParagraphMap; + std::vector<int> *myParagraphVector; + bool myParagraphStored;*/ +}; + +#endif /* __PMLBOOKREADER_H__ */ diff --git a/reader/src/formats/pdb/PmlReader.cpp b/reader/src/formats/pdb/PmlReader.cpp new file mode 100644 index 0000000..712a6e0 --- /dev/null +++ b/reader/src/formats/pdb/PmlReader.cpp @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +/* + * Information about Palm Markup Language was taken from: + * http://www.m.ereader.com/ereader/help/dropbook/pml.htm + * http://ccit205.wikispaces.com/Palm+Markup+Language+(PML) + */ + +#include <cstdlib> +#include <cctype> + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "PmlReader.h" + +static const int pmlStreamBufferSize = 4096; + +const std::string PmlReader::ourDefaultParameter = ""; + +PmlReader::PmlReader(const std::string &encoding) : EncodedTextReader(encoding) { +} + +PmlReader::~PmlReader() { +} + +bool PmlReader::readDocument(ZLInputStream& stream) { + myStreamBuffer = new char[pmlStreamBufferSize]; + + myIsInterrupted = false; + + myState.Italic = false; + myState.Bold = false; + myState.Underlined = false; + myState.SmallCaps = false; + myState.Subscript = false; + myState.Superscript = false; + myState.Alignment = ALIGN_UNDEFINED; + myState.FontSize = NORMAL; + myState.Indent = 0; + myState.IndentBlockOn = false; + myState.BoldBlockOn = false; + myState.FootnoteLinkOn = false; + myState.InternalLinkOn = false; + myState.InvisibleText = false; + + bool code = parseDocument(stream); + + delete[] myStreamBuffer; + + return code; +} + +bool PmlReader::parseDocument(ZLInputStream &stream) { + enum { + READ_NORMAL_DATA, + READ_TAG, + READ_TAG_PARAMETER, + } parserState = READ_NORMAL_DATA; + + std::size_t tagNameLength = 0; + std::string tagName; + std::string parameterString; + + bool startParameterReading = false; + std::size_t tagCounter = 0; + static bool FLAG = true; + + while (!myIsInterrupted) { + const char *ptr = myStreamBuffer; + const char *end = myStreamBuffer + stream.read(myStreamBuffer, pmlStreamBufferSize); + if (ptr == end) { + break; + } + const char *dataStart = ptr; + bool readNextChar = true; + while (ptr != end) { + switch (parserState) { + case READ_NORMAL_DATA: + if (*ptr == '\n') { + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + newLine(); + FLAG = true; + dataStart = ptr + 1; + } else if (FLAG && std::isspace(*ptr)) { + } else { + FLAG = false; + if (*ptr == '\\') { + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + dataStart = ptr + 1; + tagName.erase(); + parserState = READ_TAG; + } + } + break; + case READ_TAG: + if ((ptr == dataStart) && (tagName.empty())) { + if (*ptr == '\\') { + processCharData(ptr, 1); + dataStart = ptr + 1; + parserState = READ_NORMAL_DATA; + } else { + tagNameLength = findTagLength(ptr); + if (tagNameLength == 0) { + dataStart = ptr + 1; + parserState = READ_NORMAL_DATA; + ++tagCounter; + } else { + --tagNameLength; + } + } + } else { + if (tagNameLength == 0) { + tagName.append(dataStart, ptr - dataStart); + if (*ptr == '=') { + dataStart = ptr + 1; + parameterString.erase(); + parserState = READ_TAG_PARAMETER; + ++tagCounter; + } else { + readNextChar = false; + processTag(tagName); + dataStart = ptr; + parserState = READ_NORMAL_DATA; + ++tagCounter; + } + } else { + --tagNameLength; + } + } + break; + case READ_TAG_PARAMETER: + if (*ptr == '"') { + if (!startParameterReading) { + startParameterReading = true; + dataStart = ptr + 1; + } else { + parameterString.append(dataStart, ptr - dataStart); + processTag(tagName, parameterString); + parserState = READ_NORMAL_DATA; + dataStart = ptr + 1; + startParameterReading = false; + } + } + break; + } + if (readNextChar) { + ++ptr; + } else { + readNextChar = true; + } + } + if (dataStart < end) { + switch (parserState) { + case READ_NORMAL_DATA: + processCharData(dataStart, end - dataStart); + case READ_TAG: + tagName.append(dataStart, end - dataStart); + break; + case READ_TAG_PARAMETER: + parameterString.append(dataStart, end - dataStart); + break; + default: + break; + } + } + } + return myIsInterrupted; +} + +std::size_t PmlReader::findTagLength(const char* ptr) { + switch(*ptr) { // tag action description | close | support | + case 'p': // new page | - | + | + case 'x': // new chapter and new page | + | + | + case 'c': // center alignment block | + | + | + case 'r': // right alignment block | + | + | + case 'i': // italize block | + | + | + case 'u': // underlined block | + | + | + case 'o': // overstrike block | + | - | + case 'v': // invisible text block | + | + | + case 't': // indent block | + | + | + case 'T': // indent with value | - | + | + case 'w': // embed text width rule | - | - | + case 'n': // switch to normal font | - | + | + case 's': // switch to std font |+ or \n| + | + case 'b': // switch to bold font (deprecated) |+ or \n| - | + case 'l': // switch to large font |+ or \n| + | + case 'B': // mark text as bold | + | + | + case 'k': // smaller font size and uppercase | + | + | + case 'm': // insert named image | - | + | + case 'q': // reference to another spot | + | + | + case 'Q': // link anchor for \q reference | - | + | + case '-': // soft hyphen | - | - | + case 'I': // reference index item | - | - | + return 1; + case 'X': // XN - new chapter, n indent level | + | - | + case 'S': // Sp - mark text as superscript | + | + | + // Sb - mark text as subscript | + | + | + // Sd - link to a sidebar | + | - | + case 'C': // CN - chapter title + indent level| - | - | + case 'F': // Fn - link to a footnote | + | + | + return 2; + default: + return 0; + } +} + + +void PmlReader::interrupt() { + myIsInterrupted = true; +} + + +void PmlReader::processTag(std::string &tagName, const std::string ¶meter) { + const char tagDeterminant = *tagName.data(); + switch (tagDeterminant) { + case 'p': + newPage(); + break; + case 'x': + //TODO add close tag processing + newPage(); + break; + case 'B': + if (!myState.BoldBlockOn) { + processFontProperty(FONT_BOLD); + } + break; + case 'i': + processFontProperty(FONT_ITALIC); + break; + case 'u': + processFontProperty(FONT_UNDERLINED); + break; + case 'v': + myState.InvisibleText = !myState.InvisibleText;; + break; + case 'c': + processAlignment(ALIGN_CENTER); + break; + case 'r': + processAlignment(ALIGN_RIGHT); + break; + case 'n': + processFontSize(NORMAL); + break; + case 'b': + myState.BoldBlockOn = !myState.BoldBlockOn; + processFontProperty(FONT_BOLD); + break; + case 's': + processFontSize(SMALLER); + break; + case 'l': + processFontSize(LARGER); + break; + case 'k': + myState.SmallCaps = !myState.SmallCaps; + processFontSize(SMALLER); + break; + case 'S': + if (tagName == "Sb") { + processFontProperty(FONT_SUBSCRIPT); + } else if (tagName == "Sp") { + processFontProperty(FONT_SUPERSCRIPT); + } else if (tagName == "Sd") { + //processSidebarLink(); + } + break; + case 't': + processIndent(); + break; + case 'T': + processIndent(parameter); + myState.IndentBlockOn = false; + break; + case 'w': + //addHorizontalRule(parameter); + break; + case 'F': + processLink(FOOTNOTE, parameter); + break; + case 'q': + processLink(INTERNAL_HYPERLINK, parameter); + break; + case 'Q': + addLinkLabel(parameter); + break; + case 'm': + addImageReference(parameter); + break; + default: + //std::cerr << "PmlReader: unsupported tag: name: " << tagName << " parameter: " << parameter << "\n"; + break; + } +} + +void PmlReader::processCharData(const char* data, std::size_t len, bool convert) { + if(!myState.InvisibleText) { + addCharData(data, len, convert); + } +} + +void PmlReader::processFontProperty(PmlReader::FontProperty property) { + switch (property) { + case FONT_BOLD: + myState.Bold = !myState.Bold; + switchFontProperty(FONT_BOLD); + break; + case FONT_ITALIC: + myState.Italic = !myState.Italic; + switchFontProperty(FONT_ITALIC); + break; + case FONT_UNDERLINED: + myState.Underlined = !myState.Underlined; + switchFontProperty(FONT_UNDERLINED); + break; + case FONT_SUBSCRIPT: + myState.Subscript = !myState.Subscript; + switchFontProperty(FONT_SUBSCRIPT); + break; + case FONT_SUPERSCRIPT: + myState.Superscript = !myState.Superscript; + switchFontProperty(FONT_SUPERSCRIPT); + break; + } +} + +void PmlReader::processAlignment(ZLTextAlignmentType alignment) { + if (myState.Alignment != alignment) { + myState.Alignment = alignment; + } else { + myState.Alignment = ALIGN_UNDEFINED; + } + newParagraph(); +} + +void PmlReader::processFontSize(FontSizeType sizeType) { + if (myState.FontSize != sizeType) { + myState.FontSize = sizeType; + } else { + myState.FontSize = NORMAL; + } + setFontSize(); +} + +void PmlReader::processIndent(const std::string& parameter) { + int indentPercentSize = 5; + if (!parameter.empty()) { + const int index = parameter.find('%'); + if (index != -1) { + const std::string indentValueStr = parameter.substr(0, index); + indentPercentSize = std::atoi(indentValueStr.data()); + } else { + indentPercentSize = 5; + } + } + if (!myState.IndentBlockOn) { + myState.Indent = indentPercentSize; + } else { + myState.Indent = 0; + } + myState.IndentBlockOn = !myState.IndentBlockOn; + newParagraph(); +} + +void PmlReader::processLink(FBTextKind kind, const std::string ¶meter) { + switch(kind) { + case FOOTNOTE: + myState.FootnoteLinkOn = !myState.FootnoteLinkOn; + addLink(FOOTNOTE, parameter, myState.FootnoteLinkOn); + break; + case INTERNAL_HYPERLINK: + myState.InternalLinkOn = !myState.InternalLinkOn; + if (parameter.size() > 1) { + // '#' character has to stand before link label , so we should omit '#' for getting label + addLink(INTERNAL_HYPERLINK, parameter.substr(1), myState.InternalLinkOn); + } else { + // In case trailing or corrupted tag we use parameter entirely + addLink(INTERNAL_HYPERLINK, parameter, myState.InternalLinkOn); + } + break; + default: + break; + } +} diff --git a/reader/src/formats/pdb/PmlReader.h b/reader/src/formats/pdb/PmlReader.h new file mode 100644 index 0000000..496c8d9 --- /dev/null +++ b/reader/src/formats/pdb/PmlReader.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +/* + * Information about Palm Markup Language was taken from next sources: + * http://www.m.ereader.com/ereader/help/dropbook/pml.htm + * http://ccit205.wikispaces.com/Palm+Markup+Language+(PML) + */ + +#ifndef __PMLREADER_H__ +#define __PMLREADER_H__ + +#include <string> + +#include <ZLEncodingConverter.h> +#include <ZLTextAlignmentType.h> + +#include "../EncodedTextReader.h" +#include "../../bookmodel/FBTextKind.h" + +class ZLInputStream; + +class PmlReader : public EncodedTextReader { + +public: + virtual bool readDocument(ZLInputStream &stream); + +protected: + PmlReader(const std::string &encoding); + virtual ~PmlReader(); + +protected: + enum FontProperty { + FONT_BOLD, + FONT_ITALIC, + FONT_UNDERLINED, + FONT_SUBSCRIPT, + FONT_SUPERSCRIPT + }; + + enum FontSizeType { + NORMAL, + SMALLER, + LARGER + }; + + + virtual void addCharData(const char *data, std::size_t len, bool convert) = 0; + virtual void addLink(FBTextKind kind, const std::string &id, bool on) = 0; + virtual void addLinkLabel(const std::string &label) = 0; + virtual void addImageReference(const std::string &id) = 0; + virtual void setFontSize() = 0; + virtual void switchFontProperty(FontProperty property) = 0; + virtual void newLine() = 0; + virtual void newPage() = 0; + virtual void newParagraph() = 0; + + void interrupt(); + +private: + bool parseDocument(ZLInputStream &stream); + void processTag(std::string &tagName, const std::string ¶meter = ourDefaultParameter); + void processCharData(const char* data, std::size_t len, bool convert = true); + void processFontProperty(FontProperty property); + void processAlignment(ZLTextAlignmentType alignment); + void processFontSize(FontSizeType sizeType); + void processIndent(const std::string ¶meter =ourDefaultParameter); + void processLink(FBTextKind kind, const std::string ¶meter); + + static std::size_t findTagLength(const char* ptr); + +protected: + struct PmlReaderState { + bool Bold; + bool Italic; + bool Underlined; + bool SmallCaps; + bool Subscript; + bool Superscript; + + ZLTextAlignmentType Alignment; + FontSizeType FontSize; + + unsigned short Indent; + bool IndentBlockOn; + bool BoldBlockOn; + bool FootnoteLinkOn; + bool InternalLinkOn; + bool InvisibleText; + }; + + PmlReaderState myState; + +private: + char* myStreamBuffer; + + bool myIsInterrupted; + const static std::string ourDefaultParameter; +}; + +#endif /* __PMLREADER_H__ */ diff --git a/reader/src/formats/pdb/SimplePdbPlugin.cpp b/reader/src/formats/pdb/SimplePdbPlugin.cpp new file mode 100644 index 0000000..f4b5c30 --- /dev/null +++ b/reader/src/formats/pdb/SimplePdbPlugin.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "PdbPlugin.h" +#include "../txt/TxtBookReader.h" +#include "../html/HtmlBookReader.h" +#include "HtmlMetainfoReader.h" +#include "../util/TextFormatDetector.h" + +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +bool SimplePdbPlugin::readMetaInfo(Book &book) const { + const ZLFile &file = book.file(); + shared_ptr<ZLInputStream> stream = createStream(file); + detectEncodingAndLanguage(book, *stream); + if (book.encoding().empty()) { + return false; + } + int readType = HtmlMetainfoReader::NONE; + if (book.title().empty()) { + readType |= HtmlMetainfoReader::TITLE; + } + if (book.authors().empty()) { + readType |= HtmlMetainfoReader::AUTHOR; + } + if ((readType != HtmlMetainfoReader::NONE) && TextFormatDetector().isHtml(*stream)) { + readType |= HtmlMetainfoReader::TAGS; + HtmlMetainfoReader metainfoReader(book, (HtmlMetainfoReader::ReadType)readType); + metainfoReader.readDocument(*stream); + } + + return true; +} + +bool SimplePdbPlugin::readModel(BookModel &model) const { + const Book &book = *model.book(); + const ZLFile &file = book.file(); + shared_ptr<ZLInputStream> stream = createStream(file); + + PlainTextFormat format(file); + if (!format.initialized()) { + PlainTextFormatDetector detector; + detector.detect(*stream, format); + } + readDocumentInternal(file, model, format, book.encoding(), *stream); + return true; +} + +void SimplePdbPlugin::readDocumentInternal(const ZLFile&, BookModel &model, const PlainTextFormat &format, const std::string &encoding, ZLInputStream &stream) const { + if (TextFormatDetector().isHtml(stream)) { + HtmlBookReader("", model, format, encoding).readDocument(stream); + } else { + TxtBookReader(model, format, encoding).readDocument(stream); + } +} diff --git a/reader/src/formats/pdb/ZTXTPlugin.cpp b/reader/src/formats/pdb/ZTXTPlugin.cpp new file mode 100644 index 0000000..1465856 --- /dev/null +++ b/reader/src/formats/pdb/ZTXTPlugin.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "PdbPlugin.h" +#include "ZTXTStream.h" +#include "../txt/PlainTextFormat.h" +#include "../util/TextFormatDetector.h" + +bool ZTXTPlugin::providesMetaInfo() const { + return false; +} + +bool ZTXTPlugin::acceptsFile(const ZLFile &file) const { + return PdbPlugin::fileType(file) == "zTXTGPlm"; +} + +shared_ptr<ZLInputStream> ZTXTPlugin::createStream(const ZLFile &file) const { + return new ZTXTStream(file); +} + +FormatInfoPage *ZTXTPlugin::createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file) { + shared_ptr<ZLInputStream> stream = createStream(file); + return new PlainTextInfoPage(dialog, file, ZLResourceKey("Text"), !TextFormatDetector().isHtml(*stream)); +} diff --git a/reader/src/formats/pdb/ZTXTStream.cpp b/reader/src/formats/pdb/ZTXTStream.cpp new file mode 100644 index 0000000..2dc549c --- /dev/null +++ b/reader/src/formats/pdb/ZTXTStream.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLZDecompressor.h> + +#include "ZTXTStream.h" + +ZTXTStream::ZTXTStream(const ZLFile &file) : PdbStream(file) { +} + +ZTXTStream::~ZTXTStream() { + close(); +} + +bool ZTXTStream::open() { + if (!PdbStream::open()) { + return false; + } + + myBase->seek(2, false); + unsigned short recordNumber; + PdbUtil::readUnsignedShort(*myBase, recordNumber); + myMaxRecordIndex = std::min(recordNumber, (unsigned short)(header().Offsets.size() - 1)); + myBase->seek(4, false); + PdbUtil::readUnsignedShort(*myBase, myMaxRecordSize); + if (myMaxRecordSize == 0) { + return false; + } + myBuffer = new char[myMaxRecordSize]; + + myRecordIndex = 0; + + return true; +} + +bool ZTXTStream::fillBuffer() { + while (myBufferOffset == myBufferLength) { + if (myRecordIndex + 1 > myMaxRecordIndex) { + return false; + } + ++myRecordIndex; + std::size_t currentOffset = recordOffset(myRecordIndex); + // Hmm, this works on examples from manybooks.net, + // but I don't understand what this code means :(( + if (myRecordIndex == 1) { + currentOffset += 2; + } + if (currentOffset < myBase->offset()) { + return false; + } + myBase->seek(currentOffset, true); + const std::size_t nextOffset = recordOffset(myRecordIndex + 1); + if (nextOffset < currentOffset) { + return false; + } + myBufferLength = ZLZDecompressor(nextOffset - currentOffset).decompress(*myBase, myBuffer, myMaxRecordSize); + myBufferOffset = 0; + } + return true; +} diff --git a/reader/src/formats/pdb/ZTXTStream.h b/reader/src/formats/pdb/ZTXTStream.h new file mode 100644 index 0000000..f89d3a0 --- /dev/null +++ b/reader/src/formats/pdb/ZTXTStream.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ZTXTSTREAM_H__ +#define __ZTXTSTREAM_H__ + +#include <ZLInputStream.h> + +#include "PdbStream.h" + +class ZLFile; + +class ZTXTStream : public PdbStream { + +public: + ZTXTStream(const ZLFile &file); + ~ZTXTStream(); + bool open(); + +private: + bool fillBuffer(); + +private: + std::size_t myMaxRecordIndex; + unsigned short myMaxRecordSize; + std::size_t myRecordIndex; +}; + +#endif /* __ZTXTSTREAM_H__ */ diff --git a/reader/src/formats/pdf/PdfBookReader.cpp b/reader/src/formats/pdf/PdfBookReader.cpp new file mode 100644 index 0000000..bd84452 --- /dev/null +++ b/reader/src/formats/pdf/PdfBookReader.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <iostream> + +#include <ZLStringUtil.h> +#include <ZLInputStream.h> + +#include "PdfBookReader.h" +#include "PdfObject.h" +#include "../../bookmodel/BookModel.h" + +static void readLine(ZLInputStream &stream, std::string &buffer) { + buffer.clear(); + char ch; + while (1) { + if (stream.read(&ch, 1) != 1) { + return; + } + if ((ch == 10) || (ch == 13)) { + if (!buffer.empty()) { + return; + } + } else { + buffer += ch; + } + } +} + +PdfBookReader::PdfBookReader(BookModel &model) : myModelReader(model) { +} + +PdfBookReader::~PdfBookReader() { +} + +shared_ptr<PdfObject> PdfBookReader::readObjectFromLocation(ZLInputStream &stream, const std::pair<int,int> &address) { + std::map<std::pair<int,int>,int>::const_iterator jt = myObjectLocationMap.find(address); + if (jt == myObjectLocationMap.end()) { + return 0; + } + stream.seek(jt->second, true); + char ch = 0; + PdfObject::readToken(stream, myBuffer, ch); + if (address.first != atoi(myBuffer.c_str())) { + return 0; + } + PdfObject::readToken(stream, myBuffer, ch); + if (address.second != atoi(myBuffer.c_str())) { + return 0; + } + PdfObject::readToken(stream, myBuffer, ch); + if (myBuffer != "obj") { + return 0; + } + return PdfObject::readObject(stream, ch); +} + +shared_ptr<PdfObject> PdfBookReader::resolveReference(shared_ptr<PdfObject> ref, ZLInputStream &stream) { + if (ref.isNull() || (ref->type() != PdfObject::REFERENCE)) { + return ref; + } + const PdfObjectReference &reference = (const PdfObjectReference&)*ref; + const std::pair<int,int> address(reference.number(), reference.generation()); + std::map<std::pair<int,int>,shared_ptr<PdfObject> >::const_iterator it = myObjectMap.find(address); + if (it != myObjectMap.end()) { + return it->second; + } + std::map<std::pair<int,int>,int>::const_iterator jt = myObjectLocationMap.find(address); + shared_ptr<PdfObject> object = readObjectFromLocation(stream, address); + myObjectMap.insert(std::make_pair(address, object)); + return object; +} + +static void stripBuffer(std::string &buffer) { + int index = buffer.find('%'); + if (index >= 0) { + buffer.erase(index); + } + ZLStringUtil::stripWhiteSpaces(buffer); +} + +bool PdfBookReader::readReferenceTable(ZLInputStream &stream, int xrefOffset) { + while (true) { + stream.seek(xrefOffset, true); + readLine(stream, myBuffer); + stripBuffer(myBuffer); + if (myBuffer != "xref") { + return false; + } + + while (true) { + readLine(stream, myBuffer); + stripBuffer(myBuffer); + if (myBuffer == "trailer") { + break; + } + const int index = myBuffer.find(' '); + const int start = atoi(myBuffer.c_str()); + const int len = atoi(myBuffer.c_str() + index + 1); + for (int i = 0; i < len; ++i) { + readLine(stream, myBuffer); + stripBuffer(myBuffer); + if (myBuffer.length() != 18) { + return false; + } + const int objectOffset = atoi(myBuffer.c_str()); + const int objectGeneration = atoi(myBuffer.c_str() + 11); + const bool objectInUse = myBuffer[17] == 'n'; + if (objectInUse) { + myObjectLocationMap[std::make_pair(start + i, objectGeneration)] = objectOffset; + } + } + } + char ch = 0; + shared_ptr<PdfObject> trailer = PdfObject::readObject(stream, ch); + if (trailer.isNull() || (trailer->type() != PdfObject::DICTIONARY)) { + return false; + } + if (myTrailer.isNull()) { + myTrailer = trailer; + } + PdfDictionaryObject &trailerDictionary = (PdfDictionaryObject&)*trailer; + shared_ptr<PdfObject> previous = trailerDictionary["Prev"]; + if (previous.isNull()) { + return true; + } + + if (previous->type() != PdfObject::INTEGER_NUMBER) { + return false; + } + xrefOffset = ((PdfIntegerObject&)*previous).value(); + } +} + +bool PdfBookReader::readBook(shared_ptr<ZLInputStream> stream) { + if (stream.isNull() || !stream->open()) { + return false; + } + + readLine(*stream, myBuffer); + if (!ZLStringUtil::stringStartsWith(myBuffer, "%PDF-")) { + return false; + } + + std::string version = myBuffer.substr(5); + std::cerr << "version = " << version << "\n"; + + std::size_t eofOffset = stream->sizeOfOpened(); + if (eofOffset < 100) { + return false; + } + + stream->seek(eofOffset - 100, true); + bool readXrefOffset = false; + std::size_t xrefOffset = (std::size_t)-1; + while (true) { + readLine(*stream, myBuffer); + if (myBuffer.empty()) { + break; + } + stripBuffer(myBuffer); + if (readXrefOffset) { + if (!myBuffer.empty()) { + xrefOffset = atoi(myBuffer.c_str()); + break; + } + } else if (myBuffer == "startxref") { + readXrefOffset = true; + } + } + + if (!readReferenceTable(*stream, xrefOffset)) { + return false; + } + + PdfDictionaryObject &trailerDictionary = (PdfDictionaryObject&)*myTrailer; + shared_ptr<PdfObject> root = resolveReference(trailerDictionary["Root"], *stream); + if (root.isNull() || (root->type() != PdfObject::DICTIONARY)) { + return false; + } + + PdfDictionaryObject &rootDictionary = (PdfDictionaryObject&)*root; + if (rootDictionary["Type"] != PdfNameObject::nameObject("Catalog")) { + return false; + } + shared_ptr<PdfObject> pageRootNode = resolveReference(rootDictionary["Pages"], *stream); + if (pageRootNode.isNull() || (pageRootNode->type() != PdfObject::DICTIONARY)) { + return false; + } + PdfDictionaryObject &pageRootNodeDictionary = (PdfDictionaryObject&)*pageRootNode; + if (pageRootNodeDictionary["Type"] != PdfNameObject::nameObject("Pages")) { + return false; + } + + /* + shared_ptr<PdfObject> count = pageRootNodeDictionary["Count"]; + if (!count.isNull() && (count->type() == PdfObject::INTEGER_NUMBER)) { + std::cerr << "count = " << ((PdfIntegerObject&)*count).value() << "\n"; + } + */ + shared_ptr<PdfObject> pages = pageRootNodeDictionary["Kids"]; + if (pages.isNull() || (pages->type() != PdfObject::ARRAY)) { + return false; + } + const PdfArrayObject& pagesArray = (const PdfArrayObject&)*pages; + const std::size_t pageNumber = pagesArray.size(); + for (std::size_t i = 0; i < pageNumber; ++i) { + processPage(pagesArray[i], *stream); + } + + return true; +} + +void PdfBookReader::processContents(shared_ptr<PdfObject> contentsObject, ZLInputStream &stream) { + contentsObject = resolveReference(contentsObject, stream); +} + +void PdfBookReader::processPage(shared_ptr<PdfObject> pageObject, ZLInputStream &stream) { + pageObject = resolveReference(pageObject, stream); + if (pageObject.isNull() || pageObject->type() != PdfObject::DICTIONARY) { + return; + } + const PdfDictionaryObject &pageDictionary = (const PdfDictionaryObject&)*pageObject; + shared_ptr<PdfObject> contents = pageDictionary["Contents"]; + if (contents.isNull()) { + return; + } + switch (contents->type()) { + default: + break; + case PdfObject::REFERENCE: + processContents(contents, stream); + break; + case PdfObject::ARRAY: + { + const PdfArrayObject &array = (const PdfArrayObject&)*contents; + const std::size_t len = array.size(); + for (std::size_t i = 0; i < len; ++i) { + processContents(array[i], stream); + } + break; + } + } +} diff --git a/reader/src/formats/pdf/PdfBookReader.h b/reader/src/formats/pdf/PdfBookReader.h new file mode 100644 index 0000000..9488dcf --- /dev/null +++ b/reader/src/formats/pdf/PdfBookReader.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PdfBOOKREADER_H__ +#define __PdfBOOKREADER_H__ + +#include <map> + +#include "../../bookmodel/BookReader.h" + +class PdfObject; +class PdfObjectReference; + +class PdfBookReader { + +public: + PdfBookReader(BookModel &model); + ~PdfBookReader(); + bool readBook(shared_ptr<ZLInputStream> stream); + +private: + bool readReferenceTable(ZLInputStream &stream, int offset); + shared_ptr<PdfObject> resolveReference(shared_ptr<PdfObject> reference, ZLInputStream &stream); + shared_ptr<PdfObject> readObjectFromLocation(ZLInputStream &stream, const std::pair<int,int> &address); + void processPage(shared_ptr<PdfObject> pageObject, ZLInputStream &stream); + void processContents(shared_ptr<PdfObject> contentsObject, ZLInputStream &stream); + +private: + BookReader myModelReader; + std::string myBuffer; + std::map<std::pair<int,int>,int> myObjectLocationMap; + std::map<std::pair<int,int>,shared_ptr<PdfObject> > myObjectMap; + shared_ptr<PdfObject> myTrailer; +}; + +#endif /* __PdfBOOKREADER_H__ */ diff --git a/reader/src/formats/pdf/PdfDescriptionReader.cpp b/reader/src/formats/pdf/PdfDescriptionReader.cpp new file mode 100644 index 0000000..98937fa --- /dev/null +++ b/reader/src/formats/pdf/PdfDescriptionReader.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "PdfDescriptionReader.h" + +PdfDescriptionReader::PdfDescriptionReader(Book &book) : myBook(book) { +} + +bool PdfDescriptionReader::readMetaInfo(shared_ptr<ZLInputStream> stream) { + return true; +} diff --git a/reader/src/formats/pdf/PdfDescriptionReader.h b/reader/src/formats/pdf/PdfDescriptionReader.h new file mode 100644 index 0000000..004cdfa --- /dev/null +++ b/reader/src/formats/pdf/PdfDescriptionReader.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PDFDESCRIPTIONREADER_H__ +#define __PDFDESCRIPTIONREADER_H__ + +#include <string> + +class Book; + +class PdfDescriptionReader { + +public: + PdfDescriptionReader(Book &book); + ~PdfDescriptionReader(); + bool readMetaInfo(shared_ptr<ZLInputStream> stream); + +private: + Book &myBook; +}; + +inline PdfDescriptionReader::~PdfDescriptionReader() {} + +#endif /* __PDFDESCRIPTIONREADER_H__ */ diff --git a/reader/src/formats/pdf/PdfObject.cpp b/reader/src/formats/pdf/PdfObject.cpp new file mode 100644 index 0000000..374a618 --- /dev/null +++ b/reader/src/formats/pdf/PdfObject.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <iostream> + +#include <ZLInputStream.h> +#include <ZLZDecompressor.h> + +#include "PdfObject.h" + +PdfObject::~PdfObject() { +} + +shared_ptr<PdfObject> PdfIntegerObject::integerObject(int value) { + if ((value < 0) || (value >= 256)) { + return new PdfIntegerObject(value); + } else { + static shared_ptr<PdfObject>* table = new shared_ptr<PdfObject>[256]; + if (table[value].isNull()) { + table[value] = new PdfIntegerObject(value); + } + return table[value]; + } +} + +PdfIntegerObject::PdfIntegerObject(int value) : myValue(value) { + std::cerr << "PdfIntegerObject " << value << "\n"; +} + +int PdfIntegerObject::value() const { + return myValue; +} + +PdfObject::Type PdfIntegerObject::type() const { + return INTEGER_NUMBER; +} + +shared_ptr<PdfObject> PdfBooleanObject::TRUE() { + static shared_ptr<PdfObject> value = new PdfBooleanObject(true); + return value; +} + +shared_ptr<PdfObject> PdfBooleanObject::FALSE() { + static shared_ptr<PdfObject> value = new PdfBooleanObject(false); + return value; +} + +PdfBooleanObject::PdfBooleanObject(bool value) : myValue(value) { + std::cerr << "PdfBooleanObject " << value << "\n"; +} + +bool PdfBooleanObject::value() const { + return myValue; +} + +PdfObject::Type PdfBooleanObject::type() const { + return BOOLEAN; +} + +PdfStringObject::PdfStringObject(const std::string &value) : myValue(value) { + std::cerr << "PdfStringObject " << value << "\n"; +} + +PdfObject::Type PdfStringObject::type() const { + return STRING; +} + +std::map<std::string,shared_ptr<PdfObject> > PdfNameObject::ourObjectMap; + +shared_ptr<PdfObject> PdfNameObject::nameObject(const std::string &id) { + // TODO: process escaped characters + std::map<std::string,shared_ptr<PdfObject> >::const_iterator it = ourObjectMap.find(id); + if (it != ourObjectMap.end()) { + return it->second; + } + std::cerr << "PdfNameObject " << id << "\n"; + shared_ptr<PdfObject> object = new PdfNameObject(); + ourObjectMap.insert(std::make_pair(id, object)); + return object; +} + +PdfNameObject::PdfNameObject() { +} + +PdfObject::Type PdfNameObject::type() const { + return NAME; +} + +PdfDictionaryObject::PdfDictionaryObject() { +} + +void PdfDictionaryObject::setObject(shared_ptr<PdfObject> id, shared_ptr<PdfObject> object) { + myMap[id] = object; +} + +shared_ptr<PdfObject> PdfDictionaryObject::operator[](shared_ptr<PdfObject> id) const { + std::map<shared_ptr<PdfObject>,shared_ptr<PdfObject> >::const_iterator it = myMap.find(id); + return (it != myMap.end()) ? it->second : 0; +} + +shared_ptr<PdfObject> PdfDictionaryObject::operator[](const std::string &id) const { + return operator[](PdfNameObject::nameObject(id)); +} + +PdfObject::Type PdfDictionaryObject::type() const { + return DICTIONARY; +} + +PdfArrayObject::PdfArrayObject() { +} + +void PdfArrayObject::addObject(shared_ptr<PdfObject> object) { + myVector.push_back(object); +} + +shared_ptr<PdfObject> PdfArrayObject::popLast() { + if (!myVector.empty()) { + shared_ptr<PdfObject> last = myVector.back(); + myVector.pop_back(); + return last; + } + return 0; +} + +int PdfArrayObject::size() const { + return myVector.size(); +} + +shared_ptr<PdfObject> PdfArrayObject::operator[](int index) const { + return myVector[index]; +} + +PdfObject::Type PdfArrayObject::type() const { + return ARRAY; +} + +PdfObjectReference::PdfObjectReference(int number, int generation) : myNumber(number), myGeneration(generation) { +} + +int PdfObjectReference::number() const { + return myNumber; +} + +int PdfObjectReference::generation() const { + return myGeneration; +} + +PdfObject::Type PdfObjectReference::type() const { + return REFERENCE; +} + +PdfStreamObject::PdfStreamObject(const PdfDictionaryObject &dictionary, ZLInputStream &dataStream) { + char ch; + skipWhiteSpaces(dataStream, ch); + + shared_ptr<PdfObject> length = dictionary["Length"]; + if (!length.isNull() && (length->type() == INTEGER_NUMBER)) { + int value = ((PdfIntegerObject&)*length).value(); + if (value > 0) { + shared_ptr<PdfObject> filter = dictionary["Filter"]; + if (filter == PdfNameObject::nameObject("FlateDecode")) { + dataStream.seek(1, false); + ZLZDecompressor decompressor(value - 2); + char buffer[2048]; + while (true) { + std::size_t size = decompressor.decompress(dataStream, buffer, 2048); + if (size == 0) { + break; + } + myData.append(buffer, size); + } + std::cerr << myData << "\n"; + } else { + myData.append(value, '\0'); + myData[0] = ch; + dataStream.read((char*)myData.data() + 1, value - 1); + } + } + } + + /* + shared_ptr<PdfObject> filter = dictionary["Filter"]; + if (!filter.isNull()) { + switch (filter->type()) { + default: + break; + case NAME: + myFilters.push_back( + (filter == PdfNameObject::nameObject("FlateDecode")) ? + FLATE : UNKNOWN + ); + break; + case ARRAY: + { + // TODO: process filters array + } + } + } + */ +} + +PdfObject::Type PdfStreamObject::type() const { + return STREAM; +} + +enum PdfCharacterType { + PDF_CHAR_REGULAR, + PDF_CHAR_WHITESPACE, + PDF_CHAR_DELIMITER +}; + +static PdfCharacterType *PdfCharacterTypeTable = 0; + +void PdfObject::skipWhiteSpaces(ZLInputStream &stream, char &ch) { + if (PdfCharacterTypeTable == 0) { + PdfCharacterTypeTable = new PdfCharacterType[256]; + for (int i = 0; i < 256; ++i) { + PdfCharacterTypeTable[i] = PDF_CHAR_REGULAR; + } + PdfCharacterTypeTable[0] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable[9] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable[10] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable[12] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable[13] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable[32] = PDF_CHAR_WHITESPACE; + PdfCharacterTypeTable['('] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable[')'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['<'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['>'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['['] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable[']'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['{'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['}'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['/'] = PDF_CHAR_DELIMITER; + PdfCharacterTypeTable['%'] = PDF_CHAR_DELIMITER; + } + + while ((PdfCharacterTypeTable[(unsigned char)ch] == PDF_CHAR_WHITESPACE) && + (stream.read(&ch, 1) == 1)) { + } +} + +void PdfObject::readToken(ZLInputStream &stream, std::string &buffer, char &ch) { + buffer.clear(); + skipWhiteSpaces(stream, ch); + while (PdfCharacterTypeTable[(unsigned char)ch] == PDF_CHAR_REGULAR) { + buffer += ch; + if (stream.read(&ch, 1) != 1) { + break; + } + } +} + +shared_ptr<PdfObject> PdfObject::readObject(ZLInputStream &stream, char &ch) { + skipWhiteSpaces(stream, ch); + + PdfObject::Type type = PdfObject::NIL; + bool hexString = false; + switch (ch) { + case '(': + hexString = false; + type = PdfObject::STRING; + break; + case '<': + stream.read(&ch, 1); + hexString = true; + type = (ch == '<') ? PdfObject::DICTIONARY : PdfObject::STRING; + break; + case '>': // end of dictionary + stream.read(&ch, 1); + if (ch == '>') { + stream.read(&ch, 1); + } + return 0; + case '/': + type = PdfObject::NAME; + break; + case '[': + type = PdfObject::ARRAY; + break; + case ']': // end of array + stream.read(&ch, 1); + return 0; + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + type = PdfObject::INTEGER_NUMBER; + break; + case 't': + case 'f': + type = PdfObject::BOOLEAN; + break; + } + + switch (type) { + case PdfObject::DICTIONARY: + { + ch = 0; + shared_ptr<PdfObject> name; + shared_ptr<PdfObject> value; + shared_ptr<PdfObject> next; + PdfDictionaryObject *dictionary = new PdfDictionaryObject(); + while (true) { + next = readObject(stream, ch); + if (next.isNull()) { + break; + } + PdfObject::Type oType = next->type(); + if (oType == PdfObject::NAME) { + name = next; + value = readObject(stream, ch); + if (value.isNull()) { + break; + } + dictionary->setObject(name, value); + } else if (oType == PdfObject::INTEGER_NUMBER) { + if (value.isNull() || (value->type() != PdfObject::INTEGER_NUMBER)) { + break; + } + skipWhiteSpaces(stream, ch); + if (ch != 'R') { + break; + } + const int number = ((PdfIntegerObject&)*value).value(); + const int generation = ((PdfIntegerObject&)*next).value(); + dictionary->setObject(name, new PdfObjectReference(number, generation)); + value = 0; + ch = 0; + } else { + break; + } + } + std::string token; + readToken(stream, token, ch); + if (token == "stream") { + shared_ptr<PdfObject> d = dictionary; + return new PdfStreamObject(*dictionary, stream); + } else { + return dictionary; + } + } + case PdfObject::NAME: + { + std::string name; + stream.read(&ch, 1); + readToken(stream, name, ch); + return PdfNameObject::nameObject(name); + } + case PdfObject::BOOLEAN: + { + std::string name; + readToken(stream, name, ch); + return (name == "true") ? PdfBooleanObject::TRUE() : PdfBooleanObject::FALSE(); + } + case PdfObject::INTEGER_NUMBER: + { + std::string str; + if ((ch == '+') || (ch == '-')) { + str += ch; + stream.read(&ch, 1); + } + while ((ch >= '0') && (ch <= '9')) { + str += ch; + stream.read(&ch, 1); + } + return PdfIntegerObject::integerObject(atoi(str.c_str())); + } + case PdfObject::STRING: + { + std::string value; + if (hexString) { + char num[3]; + num[2] = '\0'; + while (ch != '>') { + num[0] = ch; + stream.read(num + 1, 1); + value += (char)strtol(num, 0, 16); + stream.read(&ch, 1); + } + ch = 0; + } else { + // TODO: implement + } + return new PdfStringObject(value); + } + case PdfObject::ARRAY: + { + PdfArrayObject *array = new PdfArrayObject(); + ch = 0; + while (true) { + skipWhiteSpaces(stream, ch); + if (ch == 'R') { + const int size = array->size(); + if ((size >= 2) && + ((*array)[size - 1]->type() == PdfObject::INTEGER_NUMBER) && + ((*array)[size - 2]->type() == PdfObject::INTEGER_NUMBER)) { + const int generation = ((PdfIntegerObject&)*array->popLast()).value(); + const int number = ((PdfIntegerObject&)*array->popLast()).value(); + array->addObject(new PdfObjectReference(number, generation)); + ch = 0; + } + } + shared_ptr<PdfObject> object = readObject(stream, ch); + if (object.isNull()) { + break; + } + array->addObject(object); + } + std::cerr << "PdfArrayObject " << array->size() << "\n"; + return array; + } + default: + break; + } + + std::string buffer; + stream.read(&ch, 1); + while (PdfCharacterTypeTable[(unsigned char)ch] == PDF_CHAR_REGULAR) { + buffer += ch; + stream.read(&ch, 1); + } + std::cerr << "buffer = " << buffer << "\n"; + + return 0; +} diff --git a/reader/src/formats/pdf/PdfObject.h b/reader/src/formats/pdf/PdfObject.h new file mode 100644 index 0000000..76b8528 --- /dev/null +++ b/reader/src/formats/pdf/PdfObject.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PDFOBJECT_H__ +#define __PDFOBJECT_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> + +class ZLInputStream; + +class PdfObject { + +public: + static shared_ptr<PdfObject> readObject(ZLInputStream &stream, char &ch); + static void readToken(ZLInputStream &stream, std::string &buffer, char &ch); + +protected: + static void skipWhiteSpaces(ZLInputStream &stream, char &ch); + +public: + enum Type { + BOOLEAN, + INTEGER_NUMBER, + REAL_NUMBER, + STRING, + NAME, + ARRAY, + DICTIONARY, + STREAM, + NIL, + REFERENCE + }; + + virtual ~PdfObject(); + + virtual Type type() const = 0; +}; + +class PdfBooleanObject : public PdfObject { + +public: + static shared_ptr<PdfObject> TRUE(); + static shared_ptr<PdfObject> FALSE(); + +private: + PdfBooleanObject(bool value); + +public: + bool value() const; + +private: + Type type() const; + +private: + const bool myValue; +}; + +class PdfIntegerObject : public PdfObject { + +public: + static shared_ptr<PdfObject> integerObject(int value); + +private: + PdfIntegerObject(int value); + +public: + int value() const; + +private: + Type type() const; + +private: + const int myValue; +}; + +class PdfStringObject : public PdfObject { + +private: + PdfStringObject(const std::string &value); + +private: + Type type() const; + +private: + std::string myValue; + +friend shared_ptr<PdfObject> PdfObject::readObject(ZLInputStream &stream, char &ch); +}; + +class PdfNameObject : public PdfObject { + +public: + static shared_ptr<PdfObject> nameObject(const std::string &id); + +private: + static std::map<std::string,shared_ptr<PdfObject> > ourObjectMap; + +private: + PdfNameObject(); + +private: + Type type() const; +}; + +class PdfDictionaryObject : public PdfObject { + +private: + PdfDictionaryObject(); + void setObject(shared_ptr<PdfObject> id, shared_ptr<PdfObject> object); + +public: + shared_ptr<PdfObject> operator [] (shared_ptr<PdfObject> id) const; + shared_ptr<PdfObject> operator [] (const std::string &id) const; + +private: + Type type() const; + +private: + std::map<shared_ptr<PdfObject>,shared_ptr<PdfObject> > myMap; + +friend shared_ptr<PdfObject> PdfObject::readObject(ZLInputStream &stream, char &ch); +}; + +class PdfStreamObject : public PdfObject { + +private: + PdfStreamObject(const PdfDictionaryObject &dictionary, ZLInputStream &dataStream); + +private: + Type type() const; + +private: + std::string myData; + /* + enum EncodingType { + UNKNOWN, + FLATE, + }; + std::vector<EncodingType> myFilters; + */ + +friend shared_ptr<PdfObject> PdfObject::readObject(ZLInputStream &stream, char &ch); +}; + +class PdfArrayObject : public PdfObject { + +private: + PdfArrayObject(); + void addObject(shared_ptr<PdfObject> object); + shared_ptr<PdfObject> popLast(); + +public: + int size() const; + shared_ptr<PdfObject> operator [] (int index) const; + +private: + Type type() const; + +private: + std::vector<shared_ptr<PdfObject> > myVector; + +friend shared_ptr<PdfObject> PdfObject::readObject(ZLInputStream &stream, char &ch); +}; + +class PdfObjectReference : public PdfObject { + +public: + PdfObjectReference(int number, int generation); + + int number() const; + int generation() const; + +private: + Type type() const; + +private: + const int myNumber; + const int myGeneration; +}; + +#endif /* __PDFOBJECT_H__ */ diff --git a/reader/src/formats/pdf/PdfPlugin.cpp b/reader/src/formats/pdf/PdfPlugin.cpp new file mode 100644 index 0000000..06325d4 --- /dev/null +++ b/reader/src/formats/pdf/PdfPlugin.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "PdfPlugin.h" +#include "PdfDescriptionReader.h" +#include "PdfBookReader.h" +#include "../../library/Book.h" + +bool PdfPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "pdf"; +} + +bool PdfPlugin::readMetaInfo(Book &book) const { + return PdfDescriptionReader(book).readMetaInfo(ZLFile(path).inputStream()); +} + +bool PdfPlugin::readLanguageAndEncoding(Book &book) const { + return true; +} + +bool PdfPlugin::readModel(BookModel &model) const { + return PdfBookReader(model).readBook(ZLFile(book.fileName()).inputStream()); +} diff --git a/reader/src/formats/pdf/PdfPlugin.h b/reader/src/formats/pdf/PdfPlugin.h new file mode 100644 index 0000000..9c330f6 --- /dev/null +++ b/reader/src/formats/pdf/PdfPlugin.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PdfPLUGIN_H__ +#define __PdfPLUGIN_H__ + +#include "../FormatPlugin.h" + +class PdfPlugin : public FormatPlugin { + +public: + PdfPlugin(); + ~PdfPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +inline PdfPlugin::PdfPlugin() {} +inline PdfPlugin::~PdfPlugin() {} +inline bool PdfPlugin::providesMetaInfo() const { return true; } + +#endif /* __PdfPLUGIN_H__ */ diff --git a/reader/src/formats/pdf/StringStream.cpp b/reader/src/formats/pdf/StringStream.cpp new file mode 100644 index 0000000..b2369df --- /dev/null +++ b/reader/src/formats/pdf/StringStream.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include "StringStream.h" + +StringStream::StringStream(const std::string &data) : myData(data), myOffset(0) { +} + +bool StringStream::open() { + myOffset = 0; + return true; +} + +std::size_t StringStream::read(char *buffer, std::size_t maxSize) { + std::size_t size = std::min(maxSize, myData.length() - myOffset); + memcpy(buffer, myData.data() + myOffset, size); + myOffset += size; + return size; +} + +void StringStream::close() { +} + +void StringStream::seek(int offset, bool absoluteOffset) { + if (!absoluteOffset) { + offset += myOffset; + } + myOffset = std::min((std::size_t)std::max(0, offset), myData.length()); +} + +std::size_t StringStream::offset() const { + return myOffset; +} + +std::size_t StringStream::sizeOfOpened() { + return myData.length(); +} diff --git a/reader/src/formats/pdf/StringStream.h b/reader/src/formats/pdf/StringStream.h new file mode 100644 index 0000000..f46c038 --- /dev/null +++ b/reader/src/formats/pdf/StringStream.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __STRINGSTREAM_H__ +#define __STRINGSTREAM_H__ + +#include <ZLInputStream.h> + +class StringStream : public ZLInputStream { + +public: + StringStream(const std::string &data); + +public: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + const std::string &myData; + std::size_t myOffset; +}; + +#endif /* __STRINGSTREAM_H__ */ diff --git a/reader/src/formats/rtf/RtfBookReader.cpp b/reader/src/formats/rtf/RtfBookReader.cpp new file mode 100644 index 0000000..cf16bc7 --- /dev/null +++ b/reader/src/formats/rtf/RtfBookReader.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> + +#include <ZLStringUtil.h> +#include <ZLFileImage.h> +#include <ZLTextStyleEntry.h> + +#include "RtfBookReader.h" +#include "../../bookmodel/BookModel.h" + +RtfBookReader::RtfBookReader(BookModel &model, const std::string &encoding) : RtfReader(encoding), myBookReader(model) { +} + +static const std::size_t maxBufferSize = 1024; + +void RtfBookReader::addCharData(const char *data, std::size_t len, bool convert) { + if (myCurrentState.ReadText) { + if (convert || myConverter.isNull()) { + myOutputBuffer.append(data, len); + if (myOutputBuffer.size() >= maxBufferSize) { + flushBuffer(); + } + } else { + flushBuffer(); + std::string newString(data, len); + characterDataHandler(newString); + } + } +} + +void RtfBookReader::flushBuffer() { + if (!myOutputBuffer.empty()) { + if (myCurrentState.ReadText) { + if (!myConverter.isNull()) { + static std::string newString; + myConverter->convert(newString, myOutputBuffer.data(), myOutputBuffer.data() + myOutputBuffer.length()); + characterDataHandler(newString); + newString.erase(); + } else { + characterDataHandler(myOutputBuffer); + } + } + myOutputBuffer.erase(); + } +} + +void RtfBookReader::switchDestination(DestinationType destination, bool on) { + switch (destination) { + case DESTINATION_NONE: + break; + case DESTINATION_SKIP: + case DESTINATION_INFO: + case DESTINATION_TITLE: + case DESTINATION_AUTHOR: + case DESTINATION_STYLESHEET: + myCurrentState.ReadText = !on; + break; + case DESTINATION_PICTURE: + if (on) { + flushBuffer(); + if (myBookReader.paragraphIsOpen()) { + myBookReader.endParagraph(); + } + } + myCurrentState.ReadText = !on; + break; + case DESTINATION_FOOTNOTE: + flushBuffer(); + if (on) { + std::string id; + ZLStringUtil::appendNumber(id, myFootnoteIndex++); + + myStateStack.push(myCurrentState); + myCurrentState.Id = id; + myCurrentState.ReadText = true; + + myBookReader.addHyperlinkControl(FOOTNOTE, id); + myBookReader.addData(id); + myBookReader.addControl(FOOTNOTE, false); + + myBookReader.setFootnoteTextModel(id); + myBookReader.addHyperlinkLabel(id); + myBookReader.pushKind(REGULAR); + myBookReader.beginParagraph(); + } else { + myBookReader.endParagraph(); + myBookReader.popKind(); + + if (!myStateStack.empty()) { + myCurrentState = myStateStack.top(); + myStateStack.pop(); + } + + if (myStateStack.empty()) { + myBookReader.setMainTextModel(); + } else { + myBookReader.setFootnoteTextModel(myCurrentState.Id); + } + } + break; + } +} + +void RtfBookReader::insertImage(shared_ptr<ZLMimeType> mimeType, const std::string &fileName, std::size_t startOffset, std::size_t size) { + std::string id; + ZLStringUtil::appendNumber(id, myImageIndex++); + myBookReader.addImageReference(id); + const ZLFile file(fileName, mimeType); + myBookReader.addImage(id, new ZLFileImage(file, startOffset, size, ZLFileImage::ENCODING_HEX)); +} + +bool RtfBookReader::characterDataHandler(std::string &str) { + if (myCurrentState.ReadText) { + if (!myBookReader.paragraphIsOpen()) { + myBookReader.beginParagraph(); + } + myBookReader.addData(str); + } + return true; +} + +bool RtfBookReader::readDocument(const ZLFile &file) { + myImageIndex = 0; + myFootnoteIndex = 1; + + myCurrentState.ReadText = true; + + myBookReader.setMainTextModel(); + myBookReader.pushKind(REGULAR); + myBookReader.beginParagraph(); + + bool code = RtfReader::readDocument(file); + + flushBuffer(); + myBookReader.endParagraph(); + while (!myStateStack.empty()) { + myStateStack.pop(); + } + + return code; +} + +void RtfBookReader::setFontProperty(FontProperty property) { + if (!myCurrentState.ReadText) { + //DPRINT("change style not in text.\n"); + return; + } + flushBuffer(); + + switch (property) { + case FONT_BOLD: + if (myState.Bold) { + myBookReader.pushKind(STRONG); + } else { + myBookReader.popKind(); + } + myBookReader.addControl(STRONG, myState.Bold); + break; + case FONT_ITALIC: + if (myState.Italic) { + if (!myState.Bold) { + //DPRINT("add style emphasis.\n"); + myBookReader.pushKind(EMPHASIS); + myBookReader.addControl(EMPHASIS, true); + } else { + //DPRINT("add style emphasis and strong.\n"); + myBookReader.popKind(); + myBookReader.addControl(STRONG, false); + + myBookReader.pushKind(EMPHASIS); + myBookReader.addControl(EMPHASIS, true); + myBookReader.pushKind(STRONG); + myBookReader.addControl(STRONG, true); + } + } else { + if (!myState.Bold) { + //DPRINT("remove style emphasis.\n"); + myBookReader.addControl(EMPHASIS, false); + myBookReader.popKind(); + } else { + //DPRINT("remove style strong n emphasis, add strong.\n"); + myBookReader.addControl(STRONG, false); + myBookReader.popKind(); + myBookReader.addControl(EMPHASIS, false); + myBookReader.popKind(); + + myBookReader.pushKind(STRONG); + myBookReader.addControl(STRONG, true); + } + } + break; + case FONT_UNDERLINED: + break; + } +} + +void RtfBookReader::newParagraph() { + flushBuffer(); + myBookReader.endParagraph(); + myBookReader.beginParagraph(); + if (myState.Alignment != ALIGN_UNDEFINED) { + setAlignment(); + } +} + +void RtfBookReader::setEncoding(int) { +} + +void RtfBookReader::setAlignment() { + ZLTextStyleEntry entry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + entry.setAlignmentType(myState.Alignment); + myBookReader.addStyleEntry(entry); + // TODO: call addStyleCloseEntry somewhere (?) +} diff --git a/reader/src/formats/rtf/RtfBookReader.h b/reader/src/formats/rtf/RtfBookReader.h new file mode 100644 index 0000000..a977cbd --- /dev/null +++ b/reader/src/formats/rtf/RtfBookReader.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RTFBOOKREADER_H__ +#define __RTFBOOKREADER_H__ + +#include <vector> + +#include "RtfReader.h" +#include "../../bookmodel/BookReader.h" + +class ZLFile; + +class BookModel; + +class RtfBookReader : public RtfReader { + +public: + RtfBookReader(BookModel &model, const std::string &encoding); + ~RtfBookReader(); + + bool readDocument(const ZLFile &file); + + bool characterDataHandler(std::string &str); + void flushBuffer(); + + void setEncoding(int code); + void setAlignment(); + void switchDestination(DestinationType destination, bool on); + void addCharData(const char *data, std::size_t len, bool convert); + void insertImage(shared_ptr<ZLMimeType> mimeType, const std::string &fileName, std::size_t startOffset, std::size_t size); + + void setFontProperty(FontProperty property); + void newParagraph(); + +private: + BookReader myBookReader; + + std::string myOutputBuffer; + + int myImageIndex; + int myFootnoteIndex; + + struct RtfBookReaderState { + std::string Id; + bool ReadText; + }; + + RtfBookReaderState myCurrentState; + std::stack<RtfBookReaderState> myStateStack; +}; + +inline RtfBookReader::~RtfBookReader() {} + +#endif /* __RTFBOOKREADER_H__ */ diff --git a/reader/src/formats/rtf/RtfDescriptionReader.cpp b/reader/src/formats/rtf/RtfDescriptionReader.cpp new file mode 100644 index 0000000..571e66b --- /dev/null +++ b/reader/src/formats/rtf/RtfDescriptionReader.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLInputStream.h> + +#include "RtfDescriptionReader.h" + +#include "../FormatPlugin.h" +#include "../../library/Book.h" +#include "../../library/Author.h" + +RtfDescriptionReader::RtfDescriptionReader(Book &book) : RtfReader(book.encoding()), myBook(book) { +} + +void RtfDescriptionReader::setEncoding(int code) { + ZLEncodingCollection &collection = ZLEncodingCollection::Instance(); + ZLEncodingConverterInfoPtr info = collection.info(code); + if (!info.isNull()) { + myConverter = info->createConverter(); + myBook.setEncoding(info->name()); + } else { + myConverter = collection.defaultConverter(); + } +} + +bool RtfDescriptionReader::readDocument(const ZLFile &file) { + myDoRead = false; + bool code = RtfReader::readDocument(file); + if (myBook.encoding().empty()) { + myBook.setEncoding(PluginCollection::Instance().DefaultEncodingOption.value()); + } + return code; +} + +void RtfDescriptionReader::addCharData(const char *data, std::size_t len, bool convert) { + if (myDoRead && len > 0) { + if (convert) { + myConverter->convert(myBuffer, data, data + len); + } else { + myBuffer.append(data, len); + } + } +} + +void RtfDescriptionReader::switchDestination(DestinationType destination, bool on) { + switch (destination) { + case DESTINATION_INFO: + if (!on) { + interrupt(); + } + break; + case DESTINATION_TITLE: + myDoRead = on; + if (!on) { + myBook.setTitle(myBuffer); + myBuffer.erase(); + } + break; + case DESTINATION_AUTHOR: + myDoRead = on; + if (!on) { + myBook.addAuthor(myBuffer); + myBuffer.erase(); + } + break; + default: + break; + } + if (!myBook.title().empty() && !myBook.authors().empty() && !myBook.encoding().empty()) { + interrupt(); + } +} + +void RtfDescriptionReader::insertImage(shared_ptr<ZLMimeType>, const std::string&, std::size_t, std::size_t) { +} + +void RtfDescriptionReader::setFontProperty(FontProperty) { +} + +void RtfDescriptionReader::newParagraph() { +} + +void RtfDescriptionReader::setAlignment() { +} diff --git a/reader/src/formats/rtf/RtfDescriptionReader.h b/reader/src/formats/rtf/RtfDescriptionReader.h new file mode 100644 index 0000000..ff4ffa1 --- /dev/null +++ b/reader/src/formats/rtf/RtfDescriptionReader.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RTFDESCRIPTIONREADER_H__ +#define __RTFDESCRIPTIONREADER_H__ + +#include <string> + +#include "RtfReader.h" + +class Book; + +class RtfDescriptionReader : public RtfReader { + +public: + RtfDescriptionReader(Book &book); + ~RtfDescriptionReader(); + + bool readDocument(const ZLFile &file); + + void setEncoding(int code); + void setAlignment(); + void switchDestination(DestinationType destination, bool on); + void addCharData(const char *data, std::size_t len, bool convert); + void insertImage(shared_ptr<ZLMimeType> mimeType, const std::string &fileName, std::size_t startOffset, std::size_t size); + + void setFontProperty(FontProperty property); + void newParagraph(); + +private: + Book &myBook; + + bool myDoRead; + std::string myBuffer; +}; + +inline RtfDescriptionReader::~RtfDescriptionReader() {} + +#endif /* __RTFDESCRIPTIONREADER_H__ */ diff --git a/reader/src/formats/rtf/RtfPlugin.cpp b/reader/src/formats/rtf/RtfPlugin.cpp new file mode 100644 index 0000000..42ce39b --- /dev/null +++ b/reader/src/formats/rtf/RtfPlugin.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "RtfPlugin.h" +#include "RtfDescriptionReader.h" +#include "RtfBookReader.h" +#include "RtfReaderStream.h" + +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +bool RtfPlugin::providesMetaInfo() const { + return false; +} + +bool RtfPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "rtf"; +} + +bool RtfPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = new RtfReaderStream(book.file(), 50000); + + if (stream.isNull()) { + return false; + } + + detectEncodingAndLanguage(book, *stream); + + if (!RtfDescriptionReader(book).readDocument(book.file())) { + return false; + } + + return true; +} + +bool RtfPlugin::readModel(BookModel &model) const { + const Book &book = *model.book(); + return RtfBookReader(model, book.encoding()).readDocument(book.file()); +} +bool RtfPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} diff --git a/reader/src/formats/rtf/RtfPlugin.h b/reader/src/formats/rtf/RtfPlugin.h new file mode 100644 index 0000000..cb3ef9d --- /dev/null +++ b/reader/src/formats/rtf/RtfPlugin.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RTFPLUGIN_H__ +#define __RTFPLUGIN_H__ + +#include "../FormatPlugin.h" + +class RtfPlugin : public FormatPlugin { + +public: + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; +}; + +#endif /* __RTFPLUGIN_H__ */ diff --git a/reader/src/formats/rtf/RtfReader.cpp b/reader/src/formats/rtf/RtfReader.cpp new file mode 100644 index 0000000..91fea0c --- /dev/null +++ b/reader/src/formats/rtf/RtfReader.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> +#include <cctype> + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "RtfReader.h" + +std::map<std::string, RtfCommand*> RtfReader::ourKeywordMap; + +static const int rtfStreamBufferSize = 4096; + +RtfReader::RtfReader(const std::string &encoding) : EncodedTextReader(encoding) { + myNextImageMimeType = ZLMimeType::EMPTY; +} + +RtfReader::~RtfReader() { +} + +RtfCommand::~RtfCommand() { +} + +void RtfDummyCommand::run(RtfReader&, int*) const { +} + +void RtfNewParagraphCommand::run(RtfReader &reader, int*) const { + reader.newParagraph(); +} + +RtfFontPropertyCommand::RtfFontPropertyCommand(RtfReader::FontProperty property) : myProperty(property) { +} + +void RtfFontPropertyCommand::run(RtfReader &reader, int *parameter) const { + const bool start = (parameter == 0) || (*parameter != 0); + switch (myProperty) { + case RtfReader::FONT_BOLD: + if (reader.myState.Bold != start) { + reader.myState.Bold = start; + reader.setFontProperty(RtfReader::FONT_BOLD); + } + break; + case RtfReader::FONT_ITALIC: + if (reader.myState.Italic != start) { + reader.myState.Italic = start; + reader.setFontProperty(RtfReader::FONT_ITALIC); + } + break; + case RtfReader::FONT_UNDERLINED: + if (reader.myState.Underlined != start) { + reader.myState.Underlined = start; + reader.setFontProperty(RtfReader::FONT_UNDERLINED); + } + break; + } +} + +RtfAlignmentCommand::RtfAlignmentCommand(ZLTextAlignmentType alignment) : myAlignment(alignment) { +} + +void RtfAlignmentCommand::run(RtfReader &reader, int*) const { + if (reader.myState.Alignment != myAlignment) { + reader.myState.Alignment = myAlignment; + reader.setAlignment(); + } +} + +RtfCharCommand::RtfCharCommand(const std::string &chr) : myChar(chr) { +} + +void RtfCharCommand::run(RtfReader &reader, int*) const { + reader.processCharData(myChar.data(), myChar.length(), false); +} + +RtfDestinationCommand::RtfDestinationCommand(RtfReader::DestinationType destination) : myDestination(destination) { +} + +void RtfDestinationCommand::run(RtfReader &reader, int*) const { + if (reader.myState.Destination == myDestination) { + return; + } + reader.myState.Destination = myDestination; + if (myDestination == RtfReader::DESTINATION_PICTURE) { + reader.myState.ReadDataAsHex = true; + reader.myNextImageMimeType = ZLMimeType::EMPTY; + } + reader.switchDestination(myDestination, true); +} + +void RtfStyleCommand::run(RtfReader &reader, int*) const { + if (reader.myState.Destination == RtfReader::DESTINATION_STYLESHEET) { + //std::cerr << "Add style index: " << val << "\n"; + + //sprintf(style_attributes[0], "%i", val); + } else /*if (myState.Destination == rdsContent)*/ { + //std::cerr << "Set style index: " << val << "\n"; + + //sprintf(style_attributes[0], "%i", val); + } +} + +void RtfCodepageCommand::run(RtfReader &reader, int *parameter) const { + if (parameter != 0) { + reader.setEncoding(*parameter); + } +} + +void RtfSpecialCommand::run(RtfReader &reader, int*) const { + reader.mySpecialMode = true; +} + +RtfPictureCommand::RtfPictureCommand(shared_ptr<ZLMimeType> mimeType) : myMimeType(mimeType) { +} + +void RtfPictureCommand::run(RtfReader &reader, int*) const { + reader.myNextImageMimeType = myMimeType; +} + +void RtfFontResetCommand::run(RtfReader &reader, int*) const { + if (reader.myState.Bold) { + reader.myState.Bold = false; + reader.setFontProperty(RtfReader::FONT_BOLD); + } + if (reader.myState.Italic) { + reader.myState.Italic = false; + reader.setFontProperty(RtfReader::FONT_ITALIC); + } + if (reader.myState.Underlined) { + reader.myState.Underlined = false; + reader.setFontProperty(RtfReader::FONT_UNDERLINED); + } +} + +void RtfReader::addAction(const std::string &tag, RtfCommand *command) { + ourKeywordMap.insert(std::make_pair(tag, command)); +} + +void RtfReader::fillKeywordMap() { + if (ourKeywordMap.empty()) { + addAction("*", new RtfSpecialCommand()); + addAction("ansicpg", new RtfCodepageCommand()); + + static const char *keywordsToSkip[] = {"buptim", "colortbl", "comment", "creatim", "doccomm", "fonttbl", "footer", "footerf", "footerl", "footerr", "ftncn", "ftnsep", "ftnsepc", "header", "headerf", "headerl", "headerr", "keywords", "operator", "printim", "private1", "revtim", "rxe", "subject", "tc", "txe", "xe", 0}; + RtfCommand *skipCommand = new RtfDestinationCommand(RtfReader::DESTINATION_SKIP); + for (const char **i = keywordsToSkip; *i != 0; ++i) { + addAction(*i, skipCommand); + } + addAction("shppict", new RtfDummyCommand()); + addAction("info", new RtfDestinationCommand(RtfReader::DESTINATION_INFO)); + addAction("title", new RtfDestinationCommand(RtfReader::DESTINATION_TITLE)); + addAction("author", new RtfDestinationCommand(RtfReader::DESTINATION_AUTHOR)); + addAction("pict", new RtfDestinationCommand(RtfReader::DESTINATION_PICTURE)); + addAction("stylesheet", new RtfDestinationCommand(RtfReader::DESTINATION_STYLESHEET)); + addAction("footnote", new RtfDestinationCommand(RtfReader::DESTINATION_FOOTNOTE)); + + RtfCommand *newParagraphCommand = new RtfNewParagraphCommand(); + addAction("\n", newParagraphCommand); + addAction("\r", newParagraphCommand); + addAction("par", newParagraphCommand); + + addAction("\x09", new RtfCharCommand("\x09")); + addAction("_", new RtfCharCommand("-")); + addAction("\\", new RtfCharCommand("\\")); + addAction("{", new RtfCharCommand("{")); + addAction("}", new RtfCharCommand("}")); + addAction("bullet", new RtfCharCommand("\xE2\x80\xA2")); // • + addAction("endash", new RtfCharCommand("\xE2\x80\x93")); // – + addAction("emdash", new RtfCharCommand("\xE2\x80\x94")); // — + addAction("~", new RtfCharCommand("\xC0\xA0")); // + addAction("enspace", new RtfCharCommand("\xE2\x80\x82")); //   + addAction("emspace", new RtfCharCommand("\xE2\x80\x83")); //   + addAction("lquote", new RtfCharCommand("\xE2\x80\x98")); // ‘ + addAction("rquote", new RtfCharCommand("\xE2\x80\x99")); // ’ + addAction("ldblquote", new RtfCharCommand("\xE2\x80\x9C")); // “ + addAction("rdblquote", new RtfCharCommand("\xE2\x80\x9D")); // ” + + addAction("jpegblip", new RtfPictureCommand(ZLMimeType::IMAGE_JPEG)); + addAction("pngblip", new RtfPictureCommand(ZLMimeType::IMAGE_PNG)); + + addAction("s", new RtfStyleCommand()); + + addAction("qc", new RtfAlignmentCommand(ALIGN_CENTER)); + addAction("ql", new RtfAlignmentCommand(ALIGN_LEFT)); + addAction("qr", new RtfAlignmentCommand(ALIGN_RIGHT)); + addAction("qj", new RtfAlignmentCommand(ALIGN_JUSTIFY)); + addAction("pard", new RtfAlignmentCommand(ALIGN_UNDEFINED)); + + addAction("b", new RtfFontPropertyCommand(RtfReader::FONT_BOLD)); + addAction("i", new RtfFontPropertyCommand(RtfReader::FONT_ITALIC)); + addAction("u", new RtfFontPropertyCommand(RtfReader::FONT_UNDERLINED)); + addAction("plain", new RtfFontResetCommand()); + } +} + +bool RtfReader::parseDocument() { + enum { + READ_NORMAL_DATA, + READ_BINARY_DATA, + READ_HEX_SYMBOL, + READ_KEYWORD, + READ_KEYWORD_PARAMETER, + READ_END_OF_FILE + } parserState = READ_NORMAL_DATA; + + std::string keyword; + std::string parameterString; + std::string hexString; + int imageStartOffset = -1; + + while (!myIsInterrupted) { + const char *ptr = myStreamBuffer; + const char *end = myStreamBuffer + myStream->read(myStreamBuffer, rtfStreamBufferSize); + if (ptr == end) { + break; + } + const char *dataStart = ptr; + bool readNextChar = true; + while (ptr != end) { + switch (parserState) { + case READ_END_OF_FILE: + if (*ptr != '}' && !std::isspace(*ptr)) { + return false; + } + break; + case READ_BINARY_DATA: + // TODO: optimize + processCharData(ptr, 1); + --myBinaryDataSize; + if (myBinaryDataSize == 0) { + parserState = READ_NORMAL_DATA; + } + break; + case READ_NORMAL_DATA: + switch (*ptr) { + case '{': + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + dataStart = ptr + 1; + myStateStack.push(myState); + myState.ReadDataAsHex = false; + break; + case '}': + { + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + dataStart = ptr + 1; + + if (imageStartOffset >= 0) { + if (ZLMimeType::EMPTY != myNextImageMimeType) { + const int imageSize = myStream->offset() + (ptr - end) - imageStartOffset; + insertImage(myNextImageMimeType, myFileName, imageStartOffset, imageSize); + } + imageStartOffset = -1; + } + + if (myStateStack.empty()) { + parserState = READ_END_OF_FILE; + break; + } + + if (myState.Destination != myStateStack.top().Destination) { + switchDestination(myState.Destination, false); + switchDestination(myStateStack.top().Destination, true); + } + + bool oldItalic = myState.Italic; + bool oldBold = myState.Bold; + bool oldUnderlined = myState.Underlined; + ZLTextAlignmentType oldAlignment = myState.Alignment; + myState = myStateStack.top(); + myStateStack.pop(); + + if (myState.Italic != oldItalic) { + setFontProperty(RtfReader::FONT_ITALIC); + } + if (myState.Bold != oldBold) { + setFontProperty(RtfReader::FONT_BOLD); + } + if (myState.Underlined != oldUnderlined) { + setFontProperty(RtfReader::FONT_UNDERLINED); + } + if (myState.Alignment != oldAlignment) { + setAlignment(); + } + + break; + } + case '\\': + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + dataStart = ptr + 1; + keyword.erase(); + parserState = READ_KEYWORD; + break; + case 0x0d: + case 0x0a: // cr and lf are noise characters... + if (ptr > dataStart) { + processCharData(dataStart, ptr - dataStart); + } + dataStart = ptr + 1; + break; + default: + if (myState.ReadDataAsHex) { + if (imageStartOffset == -1) { + imageStartOffset = myStream->offset() + (ptr - end); + } + } + break; + } + break; + case READ_HEX_SYMBOL: + hexString += *ptr; + if (hexString.size() == 2) { + char ch = std::strtol(hexString.c_str(), 0, 16); + hexString.erase(); + processCharData(&ch, 1); + parserState = READ_NORMAL_DATA; + dataStart = ptr + 1; + } + break; + case READ_KEYWORD: + if (!std::isalpha(*ptr)) { + if ((ptr == dataStart) && (keyword.empty())) { + if (*ptr == '\'') { + parserState = READ_HEX_SYMBOL; + } else { + keyword = *ptr; + processKeyword(keyword); + parserState = READ_NORMAL_DATA; + } + dataStart = ptr + 1; + } else { + keyword.append(dataStart, ptr - dataStart); + if (*ptr == '-' || std::isdigit(*ptr)) { + dataStart = ptr; + parserState = READ_KEYWORD_PARAMETER; + } else { + readNextChar = *ptr == ' '; + processKeyword(keyword); + parserState = READ_NORMAL_DATA; + dataStart = readNextChar ? ptr + 1 : ptr; + } + } + } + break; + case READ_KEYWORD_PARAMETER: + if (!std::isdigit(*ptr)) { + parameterString.append(dataStart, ptr - dataStart); + int parameter = std::atoi(parameterString.c_str()); + parameterString.erase(); + readNextChar = *ptr == ' '; + if ((keyword == "bin") && (parameter > 0)) { + myBinaryDataSize = parameter; + parserState = READ_BINARY_DATA; + } else { + processKeyword(keyword, ¶meter); + parserState = READ_NORMAL_DATA; + } + dataStart = readNextChar ? ptr + 1 : ptr; + } + break; + } + if (readNextChar) { + ++ptr; + } else { + readNextChar = true; + } + } + if (dataStart < end) { + switch (parserState) { + case READ_NORMAL_DATA: + processCharData(dataStart, end - dataStart); + case READ_KEYWORD: + keyword.append(dataStart, end - dataStart); + break; + case READ_KEYWORD_PARAMETER: + parameterString.append(dataStart, end - dataStart); + break; + default: + break; + } + } + } + + return myIsInterrupted || myStateStack.empty(); +} + +void RtfReader::processKeyword(const std::string &keyword, int *parameter) { + const bool wasSpecialMode = mySpecialMode; + mySpecialMode = false; + if (myState.Destination == RtfReader::DESTINATION_SKIP) { + return; + } + + std::map<std::string, RtfCommand*>::const_iterator it = ourKeywordMap.find(keyword); + + if (it == ourKeywordMap.end()) { + if (wasSpecialMode) { + myState.Destination = RtfReader::DESTINATION_SKIP; + } + return; + } + + it->second->run(*this, parameter); +} + +void RtfReader::processCharData(const char *data, std::size_t len, bool convert) { + if (myState.Destination != RtfReader::DESTINATION_SKIP) { + addCharData(data, len, convert); + } +} + +void RtfReader::interrupt() { + myIsInterrupted = true; +} + +bool RtfReader::readDocument(const ZLFile &file) { + myFileName = file.path(); + myStream = file.inputStream(); + if (myStream.isNull() || !myStream->open()) { + return false; + } + + fillKeywordMap(); + + myStreamBuffer = new char[rtfStreamBufferSize]; + + myIsInterrupted = false; + + mySpecialMode = false; + + myState.Alignment = ALIGN_UNDEFINED; + myState.Italic = false; + myState.Bold = false; + myState.Underlined = false; + myState.Destination = RtfReader::DESTINATION_NONE; + myState.ReadDataAsHex = false; + + bool code = parseDocument(); + + while (!myStateStack.empty()) { + myStateStack.pop(); + } + + delete[] myStreamBuffer; + myStream->close(); + + return code; +} diff --git a/reader/src/formats/rtf/RtfReader.h b/reader/src/formats/rtf/RtfReader.h new file mode 100644 index 0000000..10b037a --- /dev/null +++ b/reader/src/formats/rtf/RtfReader.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RTFREADER_H__ +#define __RTFREADER_H__ + +#include <string> +#include <map> +#include <stack> +#include <ZLMimeType.h> + +#include <ZLEncodingConverter.h> + +#include <ZLTextAlignmentType.h> + +#include "../EncodedTextReader.h" + +class ZLFile; +class ZLInputStream; +class RtfCommand; + +class RtfReader : public EncodedTextReader { + +private: + static void fillKeywordMap(); + static void addAction(const std::string &tag, RtfCommand *command); + +private: + static std::map<std::string, RtfCommand*> ourKeywordMap; + +protected: + RtfReader(const std::string &encoding); + virtual ~RtfReader(); + +public: + virtual bool readDocument(const ZLFile &file); + +protected: + enum DestinationType { + DESTINATION_NONE, + DESTINATION_SKIP, + DESTINATION_INFO, + DESTINATION_TITLE, + DESTINATION_AUTHOR, + DESTINATION_PICTURE, + DESTINATION_STYLESHEET, + DESTINATION_FOOTNOTE, + }; + + enum FontProperty { + FONT_BOLD, + FONT_ITALIC, + FONT_UNDERLINED + }; + + virtual void addCharData(const char *data, std::size_t len, bool convert) = 0; + virtual void insertImage(shared_ptr<ZLMimeType> mimeType, const std::string &fileName, std::size_t startOffset, std::size_t size) = 0; + virtual void setEncoding(int code) = 0; + virtual void switchDestination(DestinationType destination, bool on) = 0; + virtual void setAlignment() = 0; + virtual void setFontProperty(FontProperty property) = 0; + virtual void newParagraph() = 0; + + void interrupt(); + +private: + bool parseDocument(); + void processKeyword(const std::string &keyword, int *parameter = 0); + void processCharData(const char *data, std::size_t len, bool convert = true); + +protected: + struct RtfReaderState { + bool Bold; + bool Italic; + bool Underlined; + ZLTextAlignmentType Alignment; + DestinationType Destination; + + bool ReadDataAsHex; + }; + + RtfReaderState myState; + +private: + bool mySpecialMode; + + std::string myFileName; + shared_ptr<ZLInputStream> myStream; + char *myStreamBuffer; + + std::stack<RtfReaderState> myStateStack; + + int myBinaryDataSize; + shared_ptr<ZLMimeType> myNextImageMimeType; + + int myIsInterrupted; + +friend class RtfNewParagraphCommand; +friend class RtfFontPropertyCommand; +friend class RtfAlignmentCommand; +friend class RtfCharCommand; +friend class RtfDestinationCommand; +friend class RtfStyleCommand; +friend class RtfSpecialCommand; +friend class RtfPictureCommand; +friend class RtfFontResetCommand; +friend class RtfCodepageCommand; +}; + +class RtfCommand { +protected: + virtual ~RtfCommand(); + +public: + virtual void run(RtfReader &reader, int *parameter) const = 0; +}; + +class RtfDummyCommand : public RtfCommand { +public: + void run(RtfReader &reader, int *parameter) const; +}; + +class RtfNewParagraphCommand : public RtfCommand { +public: + void run(RtfReader &reader, int *parameter) const; +}; + +class RtfFontPropertyCommand : public RtfCommand { + +public: + RtfFontPropertyCommand(RtfReader::FontProperty property); + void run(RtfReader &reader, int *parameter) const; + +private: + RtfReader::FontProperty myProperty; +}; + +class RtfAlignmentCommand : public RtfCommand { +public: + RtfAlignmentCommand(ZLTextAlignmentType alignment); + void run(RtfReader &reader, int *parameter) const; + +private: + ZLTextAlignmentType myAlignment; +}; + +class RtfCharCommand : public RtfCommand { +public: + RtfCharCommand(const std::string &chr); + void run(RtfReader &reader, int *parameter) const; + +private: + std::string myChar; +}; + +class RtfDestinationCommand : public RtfCommand { +public: + RtfDestinationCommand(RtfReader::DestinationType dest); + void run(RtfReader &reader, int *parameter) const; + +private: + RtfReader::DestinationType myDestination; +}; + +class RtfStyleCommand : public RtfCommand { +public: + void run(RtfReader &reader, int *parameter) const; +}; + +class RtfSpecialCommand : public RtfCommand { + void run(RtfReader &reader, int *parameter) const; +}; + +class RtfPictureCommand : public RtfCommand { +public: + RtfPictureCommand(shared_ptr<ZLMimeType> mimeType); + void run(RtfReader &reader, int *parameter) const; + +private: + const shared_ptr<ZLMimeType> myMimeType; +}; + +class RtfFontResetCommand : public RtfCommand { +public: + void run(RtfReader &reader, int *parameter) const; +}; + +class RtfCodepageCommand : public RtfCommand { +public: + void run(RtfReader &reader, int *parameter) const; +}; + +#endif /* __RTFREADER_H__ */ diff --git a/reader/src/formats/rtf/RtfReaderStream.cpp b/reader/src/formats/rtf/RtfReaderStream.cpp new file mode 100644 index 0000000..f4537f7 --- /dev/null +++ b/reader/src/formats/rtf/RtfReaderStream.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cstdlib> +#include <string> + +#include "RtfReader.h" +#include "RtfReaderStream.h" + +class RtfTextOnlyReader : public RtfReader { + +public: + RtfTextOnlyReader(char *buffer, std::size_t maxSize); + ~RtfTextOnlyReader(); + std::size_t readSize() const; + +protected: + void addCharData(const char *data, std::size_t len, bool convert); + void insertImage(shared_ptr<ZLMimeType> mimeType, const std::string &fileName, std::size_t startOffset, std::size_t size); + void setEncoding(int code); + void switchDestination(DestinationType destination, bool on); + void setAlignment(); + void setFontProperty(FontProperty property); + void newParagraph(); + + void interrupt(); + +private: + struct RtfTextOnlyReaderState { + bool ReadText; + }; + + RtfTextOnlyReaderState myCurrentState; + +private: + char* myBuffer; + const std::size_t myMaxSize; + std::size_t myFilledSize; +}; + +RtfTextOnlyReader::RtfTextOnlyReader(char *buffer, std::size_t maxSize) : RtfReader(std::string()), myBuffer(buffer), myMaxSize(maxSize), myFilledSize(0) { + myCurrentState.ReadText = true; +} + +RtfTextOnlyReader::~RtfTextOnlyReader() { +} + +void RtfTextOnlyReader::addCharData(const char *data, std::size_t len, bool) { + if (myBuffer == 0) { + return; + } + if (myCurrentState.ReadText) { + if (myFilledSize < myMaxSize) { + len = std::min((std::size_t)len, myMaxSize - myFilledSize); + std::memcpy(myBuffer + myFilledSize, data, len); + myFilledSize += len; + } + if (myFilledSize < myMaxSize) { + myBuffer[myFilledSize++]=' '; + } else { + interrupt(); + } + } +} + +std::size_t RtfTextOnlyReader::readSize() const { + return myFilledSize; +} + +void RtfTextOnlyReader::insertImage(shared_ptr<ZLMimeType>, const std::string&, std::size_t, std::size_t) { +} + +void RtfTextOnlyReader::setEncoding(int) { +} + +void RtfTextOnlyReader::switchDestination(DestinationType destination, bool on) { + switch (destination) { + case DESTINATION_NONE: + break; + case DESTINATION_SKIP: + case DESTINATION_INFO: + case DESTINATION_TITLE: + case DESTINATION_AUTHOR: + case DESTINATION_STYLESHEET: + myCurrentState.ReadText = !on; + break; + case DESTINATION_PICTURE: + myCurrentState.ReadText = !on; + break; + case DESTINATION_FOOTNOTE: + if (on) { + myCurrentState.ReadText = true; + } + break; + } +} + +void RtfTextOnlyReader::setAlignment() { +} + +void RtfTextOnlyReader::setFontProperty(FontProperty) { +} + +void RtfTextOnlyReader::newParagraph() { +} + +void RtfTextOnlyReader::interrupt() { +} + +RtfReaderStream::RtfReaderStream(const ZLFile& file, std::size_t maxSize) : myFile(file), myBuffer(0), mySize(maxSize) { +} + +RtfReaderStream::~RtfReaderStream() { + close(); +} + +bool RtfReaderStream::open() { + if (mySize != 0) { + myBuffer = new char[mySize]; + } + RtfTextOnlyReader reader(myBuffer, mySize); + reader.readDocument(myFile); + mySize = reader.readSize(); + myOffset = 0; + return true; +} + +std::size_t RtfReaderStream::read(char *buffer, std::size_t maxSize) { + maxSize = std::min(maxSize, mySize - myOffset); + if ((buffer != 0) && (myBuffer !=0)) { + std::memcpy(buffer, myBuffer + myOffset, maxSize); + } + myOffset += maxSize; + return maxSize; +} + +void RtfReaderStream::close() { + if (myBuffer != 0) { + delete[] myBuffer; + myBuffer = 0; + } +} + +void RtfReaderStream::seek(int offset, bool absoluteOffset) { + if (!absoluteOffset) { + offset += myOffset; + } + myOffset = std::min(mySize, (std::size_t)std::max(0, offset)); +} + +std::size_t RtfReaderStream::offset() const { + return myOffset; +} + +std::size_t RtfReaderStream::sizeOfOpened() { + return mySize; +} + diff --git a/reader/src/formats/rtf/RtfReaderStream.h b/reader/src/formats/rtf/RtfReaderStream.h new file mode 100644 index 0000000..71555b4 --- /dev/null +++ b/reader/src/formats/rtf/RtfReaderStream.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RTFREADERSTREAM_H__ +#define __RTFREADERSTREAM_H__ + +#include <string> + +#include <ZLFile.h> +#include <ZLInputStream.h> + +class RtfReaderStream : public ZLInputStream { + +public: + RtfReaderStream(const ZLFile& file, std::size_t maxSize); + ~RtfReaderStream(); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + const ZLFile myFile; + char *myBuffer; + std::size_t mySize; + std::size_t myOffset; +}; + +#endif /* __RTFREADERSTREAM_H__ */ diff --git a/reader/src/formats/tcr/PPLBookReader.cpp b/reader/src/formats/tcr/PPLBookReader.cpp new file mode 100644 index 0000000..9b7d271 --- /dev/null +++ b/reader/src/formats/tcr/PPLBookReader.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cctype> + +#include "PPLBookReader.h" +#include <ZLInputStream.h> + +static const std::size_t BUFFER_SIZE = 2048; + +PPLBookReader::PPLBookReader(BookModel &model, const std::string &encoding) : EncodedTextReader(encoding), myModelReader(model) { + myBuffer = new char[BUFFER_SIZE + 1]; +} + +PPLBookReader::~PPLBookReader() { + delete[] myBuffer; +} + +bool PPLBookReader::currentParagraphIsEmpty() const { + const char *ptr = myCurrentParagraph.data(); + const char *end = ptr + myCurrentParagraph.length(); + for (; ptr < end; ++ptr) { + if (!std::isspace((unsigned char)*ptr)) { + return false; + } + } + return true; +} + +void PPLBookReader::addParagraph() { + static const std::string END_OF_TEXT = "<* >"; + if (!myCurrentParagraph.empty()) { + if (currentParagraphIsEmpty()) { + ++myEmptyLineCounter; + if (myEmptyLineCounter >= 2) { + myModelReader.beginParagraph(ZLTextParagraph::EMPTY_LINE_PARAGRAPH); + myModelReader.endParagraph(); + } + } else if (myEmptyLineCounter < 2) { + myModelReader.beginParagraph(); + myModelReader.addControl(TITLE, true); + myModelReader.addData(myCurrentParagraph); + myModelReader.endParagraph(); + } else if (myCurrentParagraph[0] == 9) { + myModelReader.beginParagraph(); + myModelReader.addData(myCurrentParagraph); + myModelReader.endParagraph(); + } else if ((myCurrentParagraph.length() >= 2) && + (myCurrentParagraph[0] == '*') && + (myCurrentParagraph[1] == ' ')) { + myCurrentParagraph.erase(0, 2); + myModelReader.insertEndOfSectionParagraph(); + myModelReader.beginContentsParagraph(); + myModelReader.addContentsData(myCurrentParagraph); + myModelReader.endContentsParagraph(); + myModelReader.beginParagraph(); + myModelReader.addControl(SECTION_TITLE, true); + myModelReader.addData(myCurrentParagraph); + myModelReader.endParagraph(); + } else if (myCurrentParagraph.substr(0, 4) != END_OF_TEXT) { + myModelReader.beginParagraph(); + myModelReader.addControl(SUBTITLE, true); + myModelReader.addData(myCurrentParagraph); + myModelReader.endParagraph(); + } + myCurrentParagraph.erase(); + } +} + +bool PPLBookReader::readDocument(ZLInputStream &stream) { + if (!stream.open()) { + return false; + } + + myModelReader.setMainTextModel(); + myModelReader.pushKind(REGULAR); + myCurrentParagraph.erase(); + myEmptyLineCounter = 0; + + // "PPL\r\n" + stream.seek(5, false); + + std::size_t size; + do { + size = stream.read(myBuffer, BUFFER_SIZE); + myBuffer[size] = '\0'; + + const char *start = myBuffer; + const char *end = myBuffer + size; + const char *eol; + do { + eol = std::strchr(start, '\n'); + if (eol != 0) { + if (start < eol) { + myConverter->convert(myCurrentParagraph, start, eol); + } + addParagraph(); + start = eol + 1; + } else { + if (start < end) { + myConverter->convert(myCurrentParagraph, start, end); + } + } + } while (eol != 0); + } while (size == BUFFER_SIZE); + + addParagraph(); + + stream.close(); + + return true; +} diff --git a/reader/src/formats/tcr/PPLBookReader.h b/reader/src/formats/tcr/PPLBookReader.h new file mode 100644 index 0000000..98c7f9d --- /dev/null +++ b/reader/src/formats/tcr/PPLBookReader.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PPLBOOKREADER_H__ +#define __PPLBOOKREADER_H__ + +#include <shared_ptr.h> +#include <ZLEncodingConverter.h> +#include "../../bookmodel/BookReader.h" +#include "../EncodedTextReader.h" + +class ZLInputStream; +class BookModel; + +class PPLBookReader : public EncodedTextReader { + +public: + PPLBookReader(BookModel &model, const std::string &encoding); + ~PPLBookReader(); + + bool readDocument(ZLInputStream &stream); + +private: + bool currentParagraphIsEmpty() const; + void addParagraph(); + +private: + BookReader myModelReader; + + char *myBuffer; + std::string myCurrentParagraph; + int myEmptyLineCounter; +}; + +#endif /* __PPLBOOKREADER_H__ */ diff --git a/reader/src/formats/tcr/TcrPlugin.cpp b/reader/src/formats/tcr/TcrPlugin.cpp new file mode 100644 index 0000000..8ee0f14 --- /dev/null +++ b/reader/src/formats/tcr/TcrPlugin.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "TcrPlugin.h" +#include "TcrStream.h" +#include "PPLBookReader.h" +#include "../util/TextFormatDetector.h" +#include "../txt/TxtBookReader.h" +#include "../html/HtmlBookReader.h" +#include "../txt/PlainTextFormat.h" + +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +bool TcrPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "tcr"; +} + +bool TcrPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = new TcrStream(book.file()); + detectEncodingAndLanguage(book, *stream); + if (book.encoding().empty()) { + return false; + } + + return true; +} + +bool TcrPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +bool TcrPlugin::readModel(BookModel &model) const { + const Book &book = *model.book(); + const ZLFile &file = book.file(); + + shared_ptr<ZLInputStream> stream = new TcrStream(file); + + PlainTextFormat format(file); + if (!format.initialized()) { + PlainTextFormatDetector detector; + detector.detect(*stream, format); + } + + const std::string &encoding = book.encoding(); + if (TextFormatDetector().isPPL(*stream)) { + PPLBookReader(model, encoding).readDocument(*stream); + } else if (TextFormatDetector().isHtml(*stream)) { + HtmlBookReader("", model, format, encoding).readDocument(*stream); + } else { + TxtBookReader(model, format, encoding).readDocument(*stream); + } + return true; +} + +FormatInfoPage *TcrPlugin::createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file) { + shared_ptr<ZLInputStream> stream = new TcrStream(file); + if (TextFormatDetector().isPPL(*stream)) { + return 0; + } + return new PlainTextInfoPage(dialog, file, ZLResourceKey("Text"), !TextFormatDetector().isHtml(*stream)); +} diff --git a/reader/src/formats/tcr/TcrPlugin.h b/reader/src/formats/tcr/TcrPlugin.h new file mode 100644 index 0000000..9655892 --- /dev/null +++ b/reader/src/formats/tcr/TcrPlugin.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TCRPLUGIN_H__ +#define __TCRPLUGIN_H__ + +#include "../FormatPlugin.h" + +class TcrPlugin : public FormatPlugin { + +public: + TcrPlugin(); + ~TcrPlugin(); + + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); +}; + +inline TcrPlugin::TcrPlugin() {} +inline TcrPlugin::~TcrPlugin() {} +inline bool TcrPlugin::providesMetaInfo() const { return false; } + +#endif /* __TCRPLUGIN_H__ */ diff --git a/reader/src/formats/tcr/TcrStream.cpp b/reader/src/formats/tcr/TcrStream.cpp new file mode 100644 index 0000000..cf4e540 --- /dev/null +++ b/reader/src/formats/tcr/TcrStream.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLZDecompressor.h> + +#include "TcrStream.h" + +TcrStream::TcrStream(const ZLFile &file) : myBase(file.inputStream()) { +} + +TcrStream::~TcrStream() { + close(); +} + +bool TcrStream::open() { + close(); + if (myBase.isNull() || !myBase->open()) { + return false; + } + + char header[9]; + if (myBase->read(header, 9) != 9 || std::strncmp(header, "!!8-Bit!!", 9) != 0) { + myBase->close(); + return false; + } + + unsigned char entryLength; + char entryBuffer[255]; + for (int i = 0; i < 256; ++i) { + if (myBase->read((char*)&entryLength, 1) != 1 || + (entryLength > 0 && myBase->read(entryBuffer, entryLength) != entryLength)) { + myBase->close(); + return false; + } + if (entryLength > 0) { + myDictionary[i].append(entryBuffer, entryLength); + } + } + + return true; +} + +void TcrStream::close() { + if (!myBase.isNull()) { + myBase->close(); + } + for (int i = 0; i < 256; ++i) { + myDictionary[i].erase(); + } + myBuffer.erase(); +} + +std::size_t TcrStream::read(char *buffer, std::size_t maxSize) { + std::size_t size = 0; + if (myBuffer.length() > 0) { + size += std::min(maxSize, myBuffer.length()); + if (buffer != 0) { + std::strncpy(buffer, myBuffer.data(), size); + } + myBuffer.erase(0, size); + } + while (size < maxSize) { + unsigned char index; + if (myBase->read((char*)&index, 1) != 1) { + break; + } + std::size_t len = myDictionary[index].length(); + if (len > 0) { + std::size_t freeSize = maxSize - size; + if (buffer != 0) { + std::strncpy(buffer + size, myDictionary[index].data(), std::min(len, freeSize)); + } + size += std::min(len, freeSize); + if (len > freeSize) { + myBuffer = myDictionary[index].substr(freeSize); + } + } + } + myOffset += size; + return size; +} + +void TcrStream::seek(int offset, bool absoluteOffset) { + if (absoluteOffset) { + offset -= this->offset(); + } + if (offset > 0) { + read(0, offset); + } else if (offset < 0) { + offset += this->offset(); + open(); + if (offset >= 0) { + read(0, offset); + } + } +} + +std::size_t TcrStream::offset() const { + return myOffset; +} + +std::size_t TcrStream::sizeOfOpened() { + // TODO: implement + return 0; +} diff --git a/reader/src/formats/tcr/TcrStream.h b/reader/src/formats/tcr/TcrStream.h new file mode 100644 index 0000000..0a9d212 --- /dev/null +++ b/reader/src/formats/tcr/TcrStream.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TCRSTREAM_H__ +#define __TCRSTREAM_H__ + +#include <ZLInputStream.h> + +class ZLFile; + +class TcrStream : public ZLInputStream { + +public: + TcrStream(const ZLFile &file); + virtual ~TcrStream(); + bool open(); + virtual void close(); + + std::size_t read(char *buffer, std::size_t maxSize); + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +protected: + std::string myDictionary[256]; + std::string myBuffer; + shared_ptr<ZLInputStream> myBase; + std::size_t myOffset; +}; + +#endif /* __TCRSTREAM_H__ */ diff --git a/reader/src/formats/txt/PlainTextFormat.cpp b/reader/src/formats/txt/PlainTextFormat.cpp new file mode 100644 index 0000000..7c9360f --- /dev/null +++ b/reader/src/formats/txt/PlainTextFormat.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> +#include <algorithm> + +#include <ZLOptions.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> +#include <ZLFile.h> + +#include "PlainTextFormat.h" + +#include "../../options/FBCategoryKey.h" + +const std::string OPTION_Initialized = "Initialized"; +const std::string OPTION_BreakType = "BreakType"; +const std::string OPTION_IgnoredIndent = "IgnoredIndent"; +const std::string OPTION_EmptyLinesBeforeNewSection = "EmptyLinesBeforeNewSection"; +const std::string OPTION_CreateContentsTable = "CreateContentsTable"; + +PlainTextFormat::PlainTextFormat(const ZLFile &file) : + InitializedOption(FBCategoryKey::BOOKS, file.path(), OPTION_Initialized, false), + BreakTypeOption(FBCategoryKey::BOOKS, file.path(), OPTION_BreakType, 1), + IgnoredIndentOption(FBCategoryKey::BOOKS, file.path(), OPTION_IgnoredIndent, 1, 100, 1), + EmptyLinesBeforeNewSectionOption(FBCategoryKey::BOOKS, file.path(), OPTION_EmptyLinesBeforeNewSection, 1, 100, 1), + CreateContentsTableOption(FBCategoryKey::BOOKS, file.path(), OPTION_CreateContentsTable, false) { +} + +PlainTextInfoPage::PlainTextInfoPage(ZLOptionsDialog &dialog, const ZLFile &file, const ZLResourceKey &key, bool showContentsEntry) : myFormat(file) { + if (!myFormat.initialized()) { + PlainTextFormatDetector detector; + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (!stream.isNull()) { + detector.detect(*stream, myFormat); + } + } + + ZLDialogContent &tab = dialog.createTab(key); + + BreakTypeOptionEntry *breakEntry = new BreakTypeOptionEntry(*this, myFormat.BreakTypeOption); + myIgnoredIndentEntry = new ZLSimpleSpinOptionEntry(myFormat.IgnoredIndentOption, 1); + tab.addOption(ZLResourceKey("breakType"), breakEntry); + tab.addOption(ZLResourceKey("ignoreIndent"), myIgnoredIndentEntry); + breakEntry->onValueSelected(breakEntry->initialIndex()); + + if (showContentsEntry) { + CreateContentsTableOptionEntry *contentsTableEntry = new CreateContentsTableOptionEntry(*this, myFormat.CreateContentsTableOption); + myEmptyLinesBeforeNewSectionEntry = new ZLSimpleSpinOptionEntry(myFormat.EmptyLinesBeforeNewSectionOption, 1); + tab.addOption(ZLResourceKey("buildTOC"), contentsTableEntry); + tab.addOption(ZLResourceKey("emptyLines"), myEmptyLinesBeforeNewSectionEntry); + contentsTableEntry->onStateChanged(contentsTableEntry->initialState()); + } +} + +PlainTextInfoPage::~PlainTextInfoPage() { +} + +const int BUFFER_SIZE = 4096; + +void PlainTextFormatDetector::detect(ZLInputStream &stream, PlainTextFormat &format) { + if (!stream.open()) { + return; + } + + const unsigned int tableSize = 10; + + unsigned int lineCounter = 0; + int emptyLineCounter = -1; + unsigned int stringsWithLengthLessThan81Counter = 0; + unsigned int stringIndentTable[tableSize] = { 0 }; + unsigned int emptyLinesTable[tableSize] = { 0 }; + unsigned int emptyLinesBeforeShortStringTable[tableSize] = { 0 }; + + bool currentLineIsEmpty = true; + unsigned int currentLineLength = 0; + unsigned int currentLineIndent = 0; + int currentNumberOfEmptyLines = -1; + + char *buffer = new char[BUFFER_SIZE]; + int length; + char previous = 0; + do { + length = stream.read(buffer, BUFFER_SIZE); + const char *end = buffer + length; + for (const char *ptr = buffer; ptr != end; ++ptr) { + ++currentLineLength; + if (*ptr == '\n') { + ++lineCounter; + if (currentLineIsEmpty) { + ++emptyLineCounter; + ++currentNumberOfEmptyLines; + } else { + if (currentNumberOfEmptyLines >= 0) { + int index = std::min(currentNumberOfEmptyLines, (int)tableSize - 1); + emptyLinesTable[index]++; + if (currentLineLength < 51) { + emptyLinesBeforeShortStringTable[index]++; + } + } + currentNumberOfEmptyLines = -1; + } + if (currentLineLength < 81) { + ++stringsWithLengthLessThan81Counter; + } + if (!currentLineIsEmpty) { + stringIndentTable[std::min(currentLineIndent, tableSize - 1)]++; + } + + currentLineIsEmpty = true; + currentLineLength = 0; + currentLineIndent = 0; + } else if (*ptr == '\r') { + continue; + } else if (std::isspace((unsigned char)*ptr)) { + if (currentLineIsEmpty) { + ++currentLineIndent; + } + } else { + currentLineIsEmpty = false; + } + previous = *ptr; + } + } while (length == BUFFER_SIZE); + delete[] buffer; + + unsigned int nonEmptyLineCounter = lineCounter - emptyLineCounter; + + { + unsigned int indent = 0; + unsigned int lineWithIndent = 0; + for (; indent < tableSize; ++indent) { + lineWithIndent += stringIndentTable[indent]; + if (lineWithIndent > 0.1 * nonEmptyLineCounter) { + break; + } + } + format.IgnoredIndentOption.setValue(indent + 1); + } + + { + int breakType = 0; + breakType |= PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE; + if (stringsWithLengthLessThan81Counter < 0.3 * nonEmptyLineCounter) { + breakType |= PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE; + } else { + breakType |= PlainTextFormat::BREAK_PARAGRAPH_AT_LINE_WITH_INDENT; + } + format.BreakTypeOption.setValue(breakType); + } + + { + unsigned int max = 0; + unsigned index; + int emptyLinesBeforeNewSection = -1; + for (index = 2; index < tableSize; ++index) { + if (max < emptyLinesBeforeShortStringTable[index]) { + max = emptyLinesBeforeShortStringTable[index]; + emptyLinesBeforeNewSection = index; + } + } + if (emptyLinesBeforeNewSection > 0) { + for (index = tableSize - 1; index > 0; --index) { + emptyLinesTable[index - 1] += emptyLinesTable[index]; + emptyLinesBeforeShortStringTable[index - 1] += emptyLinesBeforeShortStringTable[index]; + } + for (index = emptyLinesBeforeNewSection; index < tableSize; ++index) { + if ((emptyLinesBeforeShortStringTable[index] > 2) && + (emptyLinesBeforeShortStringTable[index] > 0.7 * emptyLinesTable[index])) { + break; + } + } + emptyLinesBeforeNewSection = (index == tableSize) ? -1 : (int)index; + } + format.EmptyLinesBeforeNewSectionOption.setValue(emptyLinesBeforeNewSection); + format.CreateContentsTableOption.setValue(emptyLinesBeforeNewSection > 0); + } + + format.InitializedOption.setValue(true); +} + +BreakTypeOptionEntry::BreakTypeOptionEntry(PlainTextInfoPage &page, ZLIntegerOption &breakTypeOption) : myPage(page), myBreakTypeOption(breakTypeOption) { +} + +BreakTypeOptionEntry::~BreakTypeOptionEntry() { +} + +static std::vector<std::string> BREAK_TYPE_VALUES_VECTOR; + +int BreakTypeOptionEntry::initialIndex() const { + switch (myBreakTypeOption.value()) { + case PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE: + return 0; + case PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE: + return 1; + case PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE | PlainTextFormat::BREAK_PARAGRAPH_AT_LINE_WITH_INDENT: + default: + return 2; + } +} + +const std::string &BreakTypeOptionEntry::initialValue() const { + return values()[initialIndex()]; +} + +const std::vector<std::string> &BreakTypeOptionEntry::values() const { + if (BREAK_TYPE_VALUES_VECTOR.empty()) { + BREAK_TYPE_VALUES_VECTOR.push_back("New Line"); + BREAK_TYPE_VALUES_VECTOR.push_back("Empty Line"); + BREAK_TYPE_VALUES_VECTOR.push_back("Line With Indent"); + } + return BREAK_TYPE_VALUES_VECTOR; +} + +void BreakTypeOptionEntry::onAccept(const std::string &value) { + if (value == values()[0]) { + myBreakTypeOption.setValue(PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE); + } else if (value == values()[1]) { + myBreakTypeOption.setValue(PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE); + } else if (value == values()[2]) { + myBreakTypeOption.setValue(PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE | PlainTextFormat::BREAK_PARAGRAPH_AT_LINE_WITH_INDENT); + } +} + +void BreakTypeOptionEntry::onValueSelected(int index) { + myPage.myIgnoredIndentEntry->setVisible(index == 2); +} + +CreateContentsTableOptionEntry::CreateContentsTableOptionEntry(PlainTextInfoPage &page, ZLBooleanOption &option) : ZLSimpleBooleanOptionEntry(option), myPage(page) { +} + +CreateContentsTableOptionEntry::~CreateContentsTableOptionEntry() { +} + +void CreateContentsTableOptionEntry::onStateChanged(bool state) { + myPage.myEmptyLinesBeforeNewSectionEntry->setVisible(state); +} diff --git a/reader/src/formats/txt/PlainTextFormat.h b/reader/src/formats/txt/PlainTextFormat.h new file mode 100644 index 0000000..32ca258 --- /dev/null +++ b/reader/src/formats/txt/PlainTextFormat.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PLAINTEXTFORMAT_H__ +#define __PLAINTEXTFORMAT_H__ + +#include <ZLInputStream.h> +#include <ZLOptions.h> +#include <ZLSimpleOptionEntry.h> +#include <ZLResource.h> + +#include "../FormatPlugin.h" + +class PlainTextFormat { + +public: + enum ParagraphBreakType { + BREAK_PARAGRAPH_AT_NEW_LINE = 1, + BREAK_PARAGRAPH_AT_EMPTY_LINE = 2, + BREAK_PARAGRAPH_AT_LINE_WITH_INDENT = 4, + }; + + PlainTextFormat(const ZLFile &file); + ~PlainTextFormat() {} + + bool initialized() const { return InitializedOption.value(); } + int breakType() const { return BreakTypeOption.value(); } + int ignoredIndent() const { return IgnoredIndentOption.value(); } + int emptyLinesBeforeNewSection() const { return EmptyLinesBeforeNewSectionOption.value(); } + bool createContentsTable() const { return CreateContentsTableOption.value(); } + +private: + ZLBooleanOption InitializedOption; + ZLIntegerOption BreakTypeOption; + ZLIntegerRangeOption IgnoredIndentOption; + ZLIntegerRangeOption EmptyLinesBeforeNewSectionOption; + ZLBooleanOption CreateContentsTableOption; + +friend class PlainTextInfoPage; +friend class PlainTextFormatDetector; +}; + +class PlainTextInfoPage : public FormatInfoPage { + +public: + PlainTextInfoPage(ZLOptionsDialog &dialog, const ZLFile &file, const ZLResourceKey &key, bool showContentsEntry); + ~PlainTextInfoPage(); + +private: + PlainTextFormat myFormat; + + ZLSimpleSpinOptionEntry *myIgnoredIndentEntry; + ZLSimpleSpinOptionEntry *myEmptyLinesBeforeNewSectionEntry; + +friend class BreakTypeOptionEntry; +friend class CreateContentsTableOptionEntry; +}; + +class PlainTextFormatDetector { + +public: + PlainTextFormatDetector() {} + ~PlainTextFormatDetector() {} + + void detect(ZLInputStream &stream, PlainTextFormat &format); +}; + +class BreakTypeOptionEntry : public ZLComboOptionEntry { + +public: + BreakTypeOptionEntry(PlainTextInfoPage &page, ZLIntegerOption &breakTypeOption); + ~BreakTypeOptionEntry(); + + int initialIndex() const; + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + void onValueSelected(int index); + +private: + PlainTextInfoPage &myPage; + ZLIntegerOption &myBreakTypeOption; +}; + +class CreateContentsTableOptionEntry : public ZLSimpleBooleanOptionEntry { + +public: + CreateContentsTableOptionEntry(PlainTextInfoPage &page, ZLBooleanOption &option); + ~CreateContentsTableOptionEntry(); + void onStateChanged(bool state); + +private: + PlainTextInfoPage &myPage; +}; + +#endif /* __PLAINTEXTFORMAT_H__ */ diff --git a/reader/src/formats/txt/TxtBookReader.cpp b/reader/src/formats/txt/TxtBookReader.cpp new file mode 100644 index 0000000..c68ea2c --- /dev/null +++ b/reader/src/formats/txt/TxtBookReader.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> + +#include "TxtBookReader.h" +#include "../../bookmodel/BookModel.h" + +TxtBookReader::TxtBookReader(BookModel &model, const PlainTextFormat &format, const std::string &encoding) : TxtReader(encoding), BookReader(model), myFormat(format) { +} + +void TxtBookReader::internalEndParagraph() { + if (!myLastLineIsEmpty) { + //myLineFeedCounter = 0; + myLineFeedCounter = -1; /* Fixed by Hatred: zero value was break LINE INDENT formater - + second line print with indent like new paragraf */ + } + myLastLineIsEmpty = true; + endParagraph(); +} + +bool TxtBookReader::characterDataHandler(std::string &str) { + const char *ptr = str.data(); + const char *end = ptr + str.length(); + for (; ptr != end; ++ptr) { + if (std::isspace((unsigned char)*ptr)) { + if (*ptr != '\t') { + ++mySpaceCounter; + } else { + mySpaceCounter += myFormat.ignoredIndent() + 1; // TODO: implement single option in PlainTextFormat + } + } else { + myLastLineIsEmpty = false; + break; + } + } + if (ptr != end) { + if ((myFormat.breakType() & PlainTextFormat::BREAK_PARAGRAPH_AT_LINE_WITH_INDENT) && + myNewLine && (mySpaceCounter > myFormat.ignoredIndent())) { + internalEndParagraph(); + beginParagraph(); + } + addData(str); + if (myInsideContentsParagraph) { + addContentsData(str); + } + myNewLine = false; + } + return true; +} + +bool TxtBookReader::newLineHandler() { + if (!myLastLineIsEmpty) { + myLineFeedCounter = -1; + } + myLastLineIsEmpty = true; + ++myLineFeedCounter; + myNewLine = true; + mySpaceCounter = 0; + bool paragraphBreak = + (myFormat.breakType() & PlainTextFormat::BREAK_PARAGRAPH_AT_NEW_LINE) || + ((myFormat.breakType() & PlainTextFormat::BREAK_PARAGRAPH_AT_EMPTY_LINE) && (myLineFeedCounter > 0)); + + if (myFormat.createContentsTable()) { +// if (!myInsideContentsParagraph && (myLineFeedCounter == myFormat.emptyLinesBeforeNewSection() + 1)) { + /* Fixed by Hatred: remove '+ 1' for emptyLinesBeforeNewSection, it looks like very strange + when we should point count of empty string decrised by 1 in settings dialog */ + if (!myInsideContentsParagraph && (myLineFeedCounter == myFormat.emptyLinesBeforeNewSection())) { + myInsideContentsParagraph = true; + internalEndParagraph(); + insertEndOfSectionParagraph(); + beginContentsParagraph(); + enterTitle(); + pushKind(SECTION_TITLE); + beginParagraph(); + paragraphBreak = false; + } + if (myInsideContentsParagraph && (myLineFeedCounter == 1)) { + exitTitle(); + endContentsParagraph(); + popKind(); + myInsideContentsParagraph = false; + paragraphBreak = true; + } + } + + if (paragraphBreak) { + internalEndParagraph(); + beginParagraph(); + } + return true; +} + +void TxtBookReader::startDocumentHandler() { + setMainTextModel(); + pushKind(REGULAR); + beginParagraph(); + myLineFeedCounter = 0; + myInsideContentsParagraph = false; + enterTitle(); + myLastLineIsEmpty = true; + myNewLine = true; + mySpaceCounter = 0; +} + +void TxtBookReader::endDocumentHandler() { + internalEndParagraph(); +} diff --git a/reader/src/formats/txt/TxtBookReader.h b/reader/src/formats/txt/TxtBookReader.h new file mode 100644 index 0000000..e02ad2a --- /dev/null +++ b/reader/src/formats/txt/TxtBookReader.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TXTBOOKREADER_H__ +#define __TXTBOOKREADER_H__ + +#include <stack> + +#include "TxtReader.h" +#include "PlainTextFormat.h" +#include "../../bookmodel/BookReader.h" + +class BookModel; + +class TxtBookReader : public TxtReader, public BookReader { + +public: + TxtBookReader(BookModel &model, const PlainTextFormat &format, const std::string &encoding); + ~TxtBookReader(); + +protected: + void startDocumentHandler(); + void endDocumentHandler(); + + bool characterDataHandler(std::string &str); + bool newLineHandler(); + +private: + void internalEndParagraph(); + +private: + const PlainTextFormat &myFormat; + + int myLineFeedCounter; + bool myInsideContentsParagraph; + bool myLastLineIsEmpty; + bool myNewLine; + int mySpaceCounter; +}; + +inline TxtBookReader::~TxtBookReader() {} + +#endif /* __TXTBOOKREADER_H__ */ diff --git a/reader/src/formats/txt/TxtPlugin.cpp b/reader/src/formats/txt/TxtPlugin.cpp new file mode 100644 index 0000000..b155c2f --- /dev/null +++ b/reader/src/formats/txt/TxtPlugin.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLInputStream.h> + +#include "TxtPlugin.h" +#include "TxtBookReader.h" +#include "PlainTextFormat.h" + +#include "../../bookmodel/BookModel.h" +#include "../../library/Book.h" + +TxtPlugin::~TxtPlugin() { +} + +bool TxtPlugin::providesMetaInfo() const { + return false; +} + +bool TxtPlugin::acceptsFile(const ZLFile &file) const { + return file.extension() == "txt"; +} + +bool TxtPlugin::readMetaInfo(Book &book) const { + shared_ptr<ZLInputStream> stream = book.file().inputStream(); + if (stream.isNull()) { + return false; + } + detectEncodingAndLanguage(book, *stream); + if (book.encoding().empty()) { + return false; + } + + return true; +} + +bool TxtPlugin::readLanguageAndEncoding(Book &book) const { + (void)book; + return true; +} + +bool TxtPlugin::readModel(BookModel &model) const { + const Book &book = *model.book(); + const ZLFile &file = book.file(); + shared_ptr<ZLInputStream> stream = file.inputStream(); + if (stream.isNull()) { + return false; + } + + PlainTextFormat format(file); + if (!format.initialized()) { + PlainTextFormatDetector detector; + detector.detect(*stream, format); + } + + TxtBookReader(model, format, book.encoding()).readDocument(*stream); + return true; +} + +FormatInfoPage *TxtPlugin::createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file) { + return new PlainTextInfoPage(dialog, file, ZLResourceKey("Text"), true); +} diff --git a/reader/src/formats/txt/TxtPlugin.h b/reader/src/formats/txt/TxtPlugin.h new file mode 100644 index 0000000..e3e6e50 --- /dev/null +++ b/reader/src/formats/txt/TxtPlugin.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TXTPLUGIN_H__ +#define __TXTPLUGIN_H__ + +#include "../FormatPlugin.h" + +class TxtPlugin : public FormatPlugin { + +public: + ~TxtPlugin(); + bool providesMetaInfo() const; + bool acceptsFile(const ZLFile &file) const; + bool readMetaInfo(Book &book) const; + bool readLanguageAndEncoding(Book &book) const; + bool readModel(BookModel &model) const; + FormatInfoPage *createInfoPage(ZLOptionsDialog &dialog, const ZLFile &file); +}; + +#endif /* __TXTPLUGIN_H__ */ diff --git a/reader/src/formats/txt/TxtReader.cpp b/reader/src/formats/txt/TxtReader.cpp new file mode 100644 index 0000000..d2f5659 --- /dev/null +++ b/reader/src/formats/txt/TxtReader.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> + +#include <ZLInputStream.h> + +#include "TxtReader.h" + +class TxtReaderCore { + +public: + TxtReaderCore(TxtReader &reader); + virtual void readDocument(ZLInputStream &stream); + +protected: + TxtReader &myReader; +}; + +class TxtReaderCoreUtf16 : public TxtReaderCore { + +public: + TxtReaderCoreUtf16(TxtReader &reader); + void readDocument(ZLInputStream &stream); + +protected: + virtual char getAscii(const char *ptr) = 0; + virtual void setAscii(char *ptr, char ascii) = 0; +}; + +class TxtReaderCoreUtf16LE : public TxtReaderCoreUtf16 { + +public: + TxtReaderCoreUtf16LE(TxtReader &reader); + +protected: + char getAscii(const char *ptr); + void setAscii(char *ptr, char ascii); +}; + +class TxtReaderCoreUtf16BE : public TxtReaderCoreUtf16 { + +public: + TxtReaderCoreUtf16BE(TxtReader &reader); + +protected: + char getAscii(const char *ptr); + void setAscii(char *ptr, char ascii); +}; + +TxtReader::TxtReader(const std::string &encoding) : EncodedTextReader(encoding) { + if (ZLEncodingConverter::UTF16 == encoding) { + myCore = new TxtReaderCoreUtf16LE(*this); + } else if (ZLEncodingConverter::UTF16BE == encoding) { + myCore = new TxtReaderCoreUtf16BE(*this); + } else { + myCore = new TxtReaderCore(*this); + } +} + +TxtReader::~TxtReader() { +} + +void TxtReader::readDocument(ZLInputStream &stream) { + if (!stream.open()) { + return; + } + startDocumentHandler(); + myCore->readDocument(stream); + endDocumentHandler(); + stream.close(); +} + +TxtReaderCore::TxtReaderCore(TxtReader &reader) : myReader(reader) { +} + +TxtReaderCoreUtf16::TxtReaderCoreUtf16(TxtReader &reader) : TxtReaderCore(reader) { +} + +void TxtReaderCore::readDocument(ZLInputStream &stream) { + const std::size_t BUFSIZE = 2048; + char *buffer = new char[BUFSIZE]; + std::string str; + std::size_t length; + do { + length = stream.read(buffer, BUFSIZE); + char *start = buffer; + const char *end = buffer + length; + for (char *ptr = start; ptr != end; ++ptr) { + if (*ptr == '\n' || *ptr == '\r') { + bool skipNewLine = false; + if (*ptr == '\r' && (ptr + 1) != end && *(ptr + 1) == '\n') { + skipNewLine = true; + *ptr = '\n'; + } + if (start != ptr) { + str.erase(); + myReader.myConverter->convert(str, start, ptr + 1); + myReader.characterDataHandler(str); + } + if (skipNewLine) { + ++ptr; + } + start = ptr + 1; + myReader.newLineHandler(); + } else if (((*ptr) & 0x80) == 0 && std::isspace((unsigned char)*ptr)) { + if (*ptr != '\t') { + *ptr = ' '; + } + } else { + } + } + if (start != end) { + str.erase(); + myReader.myConverter->convert(str, start, end); + myReader.characterDataHandler(str); + } + } while (length == BUFSIZE); + delete[] buffer; +} + +void TxtReaderCoreUtf16::readDocument(ZLInputStream &stream) { + const std::size_t BUFSIZE = 2048; + char *buffer = new char[BUFSIZE]; + std::string str; + std::size_t length; + do { + length = stream.read(buffer, BUFSIZE); + char *start = buffer; + const char *end = buffer + length; + for (char *ptr = start; ptr < end; ptr += 2) { + const char chr = getAscii(ptr); + if (chr == '\n' || chr == '\r') { + bool skipNewLine = false; + if (chr == '\r' && ptr + 2 != end && getAscii(ptr + 2) == '\n') { + skipNewLine = true; + setAscii(ptr, '\n'); + } + if (start != ptr) { + str.erase(); + myReader.myConverter->convert(str, start, ptr + 2); + myReader.characterDataHandler(str); + } + if (skipNewLine) { + ptr += 2; + } + start = ptr + 2; + myReader.newLineHandler(); + } else if (chr != 0 && ((*ptr) & 0x80) == 0 && std::isspace(chr)) { + if (chr != '\t') { + setAscii(ptr, ' '); + } + } + } + if (start != end) { + str.erase(); + myReader.myConverter->convert(str, start, end); + myReader.characterDataHandler(str); + } + } while (length == BUFSIZE); + delete[] buffer; +} + +TxtReaderCoreUtf16LE::TxtReaderCoreUtf16LE(TxtReader &reader) : TxtReaderCoreUtf16(reader) { +} + +char TxtReaderCoreUtf16LE::getAscii(const char *ptr) { + return *(ptr + 1) == '\0' ? *ptr : '\0'; +} + +void TxtReaderCoreUtf16LE::setAscii(char *ptr, char ascii) { + *ptr = ascii; +} + +TxtReaderCoreUtf16BE::TxtReaderCoreUtf16BE(TxtReader &reader) : TxtReaderCoreUtf16(reader) { +} + +char TxtReaderCoreUtf16BE::getAscii(const char *ptr) { + return *ptr == '\0' ? *(ptr + 1) : '\0'; +} + +void TxtReaderCoreUtf16BE::setAscii(char *ptr, char ascii) { + *(ptr + 1) = ascii; +} diff --git a/reader/src/formats/txt/TxtReader.h b/reader/src/formats/txt/TxtReader.h new file mode 100644 index 0000000..518ba8e --- /dev/null +++ b/reader/src/formats/txt/TxtReader.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TXTREADER_H__ +#define __TXTREADER_H__ + +#include <string> + +#include <ZLEncodingConverter.h> + +#include "../EncodedTextReader.h" + +class ZLInputStream; +class TxtReaderCore; + +class TxtReader : public EncodedTextReader { + +public: + void readDocument(ZLInputStream &stream); + +protected: + TxtReader(const std::string &encoding); + virtual ~TxtReader(); + +protected: + virtual void startDocumentHandler() = 0; + virtual void endDocumentHandler() = 0; + + virtual bool characterDataHandler(std::string &str) = 0; + virtual bool newLineHandler() = 0; + +private: + shared_ptr<TxtReaderCore> myCore; + +friend class TxtReaderCore; +friend class TxtReaderCoreUtf16; +friend class TxtReaderCoreUtf16BE; +}; + +#endif /* __TXTREADER_H__ */ diff --git a/reader/src/formats/util/EntityFilesCollector.cpp b/reader/src/formats/util/EntityFilesCollector.cpp new file mode 100644 index 0000000..075bd29 --- /dev/null +++ b/reader/src/formats/util/EntityFilesCollector.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLDir.h> + +#include "EntityFilesCollector.h" + +EntityFilesCollector *EntityFilesCollector::ourInstance = 0; + +EntityFilesCollector &EntityFilesCollector::Instance() { + if (ourInstance == 0) { + ourInstance = new EntityFilesCollector(); + } + return *ourInstance; +} + +const std::vector<std::string> &EntityFilesCollector::externalDTDs(const std::string &format) { + std::map<std::string,std::vector<std::string> >::const_iterator it = myCollections.find(format); + if (it != myCollections.end()) { + return it->second; + } + + std::vector<std::string> &collection = myCollections[format]; + + std::string directoryName = + ZLibrary::ApplicationDirectory() + ZLibrary::FileNameDelimiter + + "formats" + ZLibrary::FileNameDelimiter + format; + shared_ptr<ZLDir> dtdPath = ZLFile(directoryName).directory(); + if (!dtdPath.isNull()) { + std::vector<std::string> files; + dtdPath->collectFiles(files, false); + for (std::vector<std::string>::const_iterator it = files.begin(); it != files.end(); ++it) { + if (ZLStringUtil::stringEndsWith(*it, ".ent")) { + collection.push_back(dtdPath->itemPath(*it)); + } + } + } + + return collection; +} + +EntityFilesCollector::EntityFilesCollector() { +} diff --git a/reader/src/formats/util/EntityFilesCollector.h b/reader/src/formats/util/EntityFilesCollector.h new file mode 100644 index 0000000..9967b3d --- /dev/null +++ b/reader/src/formats/util/EntityFilesCollector.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ENTITYFILESCOLLECTOR_H__ +#define __ENTITYFILESCOLLECTOR_H__ + +#include <map> +#include <vector> +#include <string> + +class EntityFilesCollector { + +public: + static EntityFilesCollector &Instance(); + + const std::vector<std::string> &externalDTDs(const std::string &format); + +private: + EntityFilesCollector(); + +private: + static EntityFilesCollector *ourInstance; + std::map<std::string,std::vector<std::string> > myCollections; +}; + +#endif /* __ENTITYFILESCOLLECTOR_H__ */ diff --git a/reader/src/formats/util/MergedStream.cpp b/reader/src/formats/util/MergedStream.cpp new file mode 100644 index 0000000..1a26a33 --- /dev/null +++ b/reader/src/formats/util/MergedStream.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "MergedStream.h" + +bool MergedStream::open() { + close(); + resetToStart(); + myOffset = 0; + myCurrentStream = nextStream(); + return !myCurrentStream.isNull() && myCurrentStream->open(); +} + +std::size_t MergedStream::read(char *buffer, std::size_t maxSize) { + std::size_t bytesToRead = maxSize; + while ((bytesToRead > 0) && !myCurrentStream.isNull()) { + std::size_t len = myCurrentStream->read(buffer, bytesToRead); + bytesToRead -= len; + if (buffer != 0) { + buffer += len; + } + if (bytesToRead != 0) { + if (buffer != 0) { + *buffer++ = '\n'; + } + bytesToRead--; + myCurrentStream = nextStream(); + if (myCurrentStream.isNull() || !myCurrentStream->open()) { + break; + } + } + } + myOffset += maxSize - bytesToRead; + return maxSize - bytesToRead; +} + +void MergedStream::close() { + myCurrentStream.reset(); +} + +void MergedStream::seek(int offset, bool absoluteOffset) { + // works for nonnegative offsets only + if (absoluteOffset) { + offset -= myOffset; + } + read(0, offset); +} + +std::size_t MergedStream::offset() const { + return myOffset; +} + +std::size_t MergedStream::sizeOfOpened() { + // coudn't be implemented + return 0; +} diff --git a/reader/src/formats/util/MergedStream.h b/reader/src/formats/util/MergedStream.h new file mode 100644 index 0000000..3f982ee --- /dev/null +++ b/reader/src/formats/util/MergedStream.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __MERGEDSTREAM_H__ +#define __MERGEDSTREAM_H__ + +#include <shared_ptr.h> +#include <ZLInputStream.h> + +class MergedStream : public ZLInputStream { + +protected: + virtual shared_ptr<ZLInputStream> nextStream() = 0; + virtual void resetToStart() = 0; + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + shared_ptr<ZLInputStream> myCurrentStream; + std::size_t myOffset; +}; + +#endif /* __MERGEDSTREAM_H__ */ diff --git a/reader/src/formats/util/MiscUtil.cpp b/reader/src/formats/util/MiscUtil.cpp new file mode 100644 index 0000000..1a91406 --- /dev/null +++ b/reader/src/formats/util/MiscUtil.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLApplication.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> + +#include "MiscUtil.h" + +FBTextKind MiscUtil::referenceType(const std::string &link) { + std::string lowerCasedLink = link; + bool isFileReference = + ZLStringUtil::stringStartsWith(lowerCasedLink, "http://") || + ZLStringUtil::stringStartsWith(lowerCasedLink, "https://") || + ZLStringUtil::stringStartsWith(lowerCasedLink, "ftp://"); + if (!isFileReference) { + return ZLStringUtil::stringStartsWith(lowerCasedLink, "mailto:") ? EXTERNAL_HYPERLINK : INTERNAL_HYPERLINK; + } + static const std::string FeedBooksPrefix0 = "http://feedbooks.com/book/stanza/"; + static const std::string FeedBooksPrefix1 = "http://www.feedbooks.com/book/stanza/"; + bool isBookHyperlink = + ZLStringUtil::stringStartsWith(lowerCasedLink, FeedBooksPrefix0) || + ZLStringUtil::stringStartsWith(lowerCasedLink, FeedBooksPrefix1) || + ZLStringUtil::stringEndsWith(lowerCasedLink, ".epub") || + ZLStringUtil::stringEndsWith(lowerCasedLink, ".mobi") || + ZLStringUtil::stringEndsWith(lowerCasedLink, ".chm") || + ZLStringUtil::stringEndsWith(lowerCasedLink, ".fb2"); + return isBookHyperlink ? BOOK_HYPERLINK : EXTERNAL_HYPERLINK; +} + +std::string MiscUtil::htmlDirectoryPrefix(const std::string &fileName) { + ZLFile file(fileName); + std::string shortName = file.name(false); + std::string path = file.path(); + int index = -1; + if ((path.length() > shortName.length()) && + (path[path.length() - shortName.length() - 1] == ':')) { + index = shortName.rfind('/'); + } + return path.substr(0, path.length() - shortName.length() + index + 1); +} + +std::string MiscUtil::htmlFileName(const std::string &fileName) { + ZLFile file(fileName); + std::string shortName = file.name(false); + std::string path = file.path(); + int index = -1; + if ((path.length() > shortName.length()) && + (path[path.length() - shortName.length() - 1] == ':')) { + index = shortName.rfind('/'); + } + return path.substr(path.length() - shortName.length() + index + 1); +} + +std::string MiscUtil::decodeHtmlURL(const std::string &encoded) { + char buffer[3]; + buffer[2] = '\0'; + + std::string decoded; + const int len = encoded.length(); + decoded.reserve(len); + for (int i = 0; i < len; i++) { + if ((encoded[i] == '%') && (i < len - 2)) { + buffer[0] = *(encoded.data() + i + 1); + buffer[1] = *(encoded.data() + i + 2); + decoded += (char)std::strtol(buffer, 0, 16); + i += 2; + } else { + decoded += encoded[i]; + } + } + return decoded; +} diff --git a/reader/src/formats/util/MiscUtil.h b/reader/src/formats/util/MiscUtil.h new file mode 100644 index 0000000..c47d84a --- /dev/null +++ b/reader/src/formats/util/MiscUtil.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __MISCUTIL_H__ +#define __MISCUTIL_H__ + +#include <string> + +#include "../../bookmodel/FBTextKind.h" + +class MiscUtil { + +private: + MiscUtil(); + +public: + static FBTextKind referenceType(const std::string &link); + static std::string htmlDirectoryPrefix(const std::string &fileName); + static std::string htmlFileName(const std::string &fileName); + static std::string decodeHtmlURL(const std::string &encodedURL); +}; + +#endif /* __MISCUTIL_H__ */ diff --git a/reader/src/formats/util/TextFormatDetector.cpp b/reader/src/formats/util/TextFormatDetector.cpp new file mode 100644 index 0000000..4a3ef67 --- /dev/null +++ b/reader/src/formats/util/TextFormatDetector.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cctype> +#include <algorithm> + +#include <ZLInputStream.h> +#include <ZLUnicodeUtil.h> + +#include "TextFormatDetector.h" + +TextFormatDetector::TextFormatDetector() { +} + +TextFormatDetector::~TextFormatDetector() { +} + +bool TextFormatDetector::isHtml(ZLInputStream &stream) const { + if (!stream.open()) { + return false; + } + + const std::size_t bufferSize = 1024; + char *buffer = new char[bufferSize]; + std::string sixBytes; + int valuableBytesCounter = 0; + bool skipFlag = true; + while (valuableBytesCounter < 6) { + std::size_t size = stream.read(buffer, bufferSize); + if (size == 0) { + break; + } + std::size_t index; + for (index = 0; skipFlag && (index < size); ++index) { + if (!std::isspace((unsigned char)buffer[index])) { + skipFlag = false; + break; + } + } + if (!skipFlag && index < size) { + int bytes = std::min(6 - valuableBytesCounter, (int)(size - index)); + sixBytes = std::string(buffer + index, bytes); + valuableBytesCounter += bytes; + } + } + stream.close(); + delete[] buffer; + return ZLUnicodeUtil::toLower(sixBytes) == "<html>"; +} + +bool TextFormatDetector::isPPL(ZLInputStream &stream) const { + if (!stream.open()) { + return false; + } + + char buffer[5]; + bool result = stream.read(buffer, 5) == 5 && std::strncmp(buffer, "PPL\r\n", 5) == 0; + stream.close(); + return result; +} diff --git a/reader/src/formats/util/TextFormatDetector.h b/reader/src/formats/util/TextFormatDetector.h new file mode 100644 index 0000000..c86b90b --- /dev/null +++ b/reader/src/formats/util/TextFormatDetector.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TEXTFORMATDETECTOR_H__ +#define __TEXTFORMATDETECTOR_H__ + +class ZLInputStream; + +class TextFormatDetector { + +public: + TextFormatDetector(); + ~TextFormatDetector(); + + bool isHtml(ZLInputStream &stream) const; + bool isPPL(ZLInputStream &stream) const; +}; + +#endif /* __TEXTFORMATDETECTOR_H__ */ diff --git a/reader/src/formats/util/XMLTextStream.cpp b/reader/src/formats/util/XMLTextStream.cpp new file mode 100644 index 0000000..19343a1 --- /dev/null +++ b/reader/src/formats/util/XMLTextStream.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> + +#include <ZLXMLReader.h> +#include <ZLUnicodeUtil.h> + +#include <ZLPlainAsynchronousInputStream.h> + +#include "XMLTextStream.h" + +class XMLTextReader : public ZLXMLReader { + +public: + XMLTextReader(std::string &buffer, const std::string &startTag); + +private: + void startElementHandler(const char *tag, const char **attributes); + void characterDataHandler(const char *text, std::size_t len); + +private: + const std::string myStartTag; + std::string &myBuffer; + bool myStarted; +}; + +XMLTextReader::XMLTextReader(std::string &buffer, const std::string &startTag) : myStartTag(ZLUnicodeUtil::toLower(startTag)), myBuffer(buffer), myStarted(myStartTag.empty()) { +} + +void XMLTextReader::startElementHandler(const char *tag, const char**) { + if (!myStarted && (myStartTag == ZLUnicodeUtil::toLower(tag))) { + myStarted = true; + } +} + +void XMLTextReader::characterDataHandler(const char *text, std::size_t len) { + if (myStarted) { + myBuffer.append(text, len); + } +} + +XMLTextStream::XMLTextStream(shared_ptr<ZLInputStream> base, const std::string &startTag) : myBase(base), myStreamBuffer(2048, '\0') { + myReader = new XMLTextReader(myDataBuffer, startTag); +} + +XMLTextStream::~XMLTextStream() { +} + +bool XMLTextStream::open() { + close(); + if (myBase.isNull() || !myBase->open()) { + return false; + } + myStream = new ZLPlainAsynchronousInputStream(); + myOffset = 0; + return true; +} + +std::size_t XMLTextStream::read(char *buffer, std::size_t maxSize) { + while (myDataBuffer.size() < maxSize) { + std::size_t len = myBase->read((char*)myStreamBuffer.data(), 2048); + /*if ((len == 0) || !myReader->readFromBuffer(myStreamBuffer.data(), len)) { + break; + }*/ + if (len == 0) { + break; + } + myStream->setBuffer(myStreamBuffer.data(), len); + if (!myReader->readDocument(myStream)) { + break; + } + } + std::size_t realSize = std::min(myDataBuffer.size(), maxSize); + if (buffer != 0) { + std::memcpy(buffer, myDataBuffer.data(), realSize); + } + myDataBuffer.erase(0, realSize); + myOffset += realSize; + return realSize; +} + +void XMLTextStream::close() { + if (!myStream.isNull()) { + myStream->setEof(); + myReader->readDocument(myStream); + myStream.reset(); + } + myBase->close(); + myDataBuffer.erase(); +} + +void XMLTextStream::seek(int offset, bool absoluteOffset) { + // works for nonnegative offsets only + if (absoluteOffset) { + offset -= myOffset; + } + read(0, offset); +} + +std::size_t XMLTextStream::offset() const { + return myOffset; +} + +std::size_t XMLTextStream::sizeOfOpened() { + // couldn't be implemented + return 0; +} diff --git a/reader/src/formats/util/XMLTextStream.h b/reader/src/formats/util/XMLTextStream.h new file mode 100644 index 0000000..f3151c6 --- /dev/null +++ b/reader/src/formats/util/XMLTextStream.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __XMLTEXTSTREAM_H__ +#define __XMLTEXTSTREAM_H__ + +#include <shared_ptr.h> +#include <ZLInputStream.h> +#include <ZLAsynchronousInputStream.h> + +class XMLTextReader; + +class XMLTextStream : public ZLInputStream { + +public: + XMLTextStream(shared_ptr<ZLInputStream> base, const std::string &startTag); + ~XMLTextStream(); + +private: + bool open(); + std::size_t read(char *buffer, std::size_t maxSize); + void close(); + void seek(int offset, bool absoluteOffset); + std::size_t offset() const; + std::size_t sizeOfOpened(); + +private: + shared_ptr<ZLInputStream> myBase; + shared_ptr<XMLTextReader> myReader; + shared_ptr<ZLAsynchronousInputStream> myStream; + std::string myStreamBuffer; + std::string myDataBuffer; + std::size_t myOffset; +}; + +#endif /* __XMLTEXTSTREAM_H__ */ diff --git a/reader/src/formats/xhtml/XHTMLReader.cpp b/reader/src/formats/xhtml/XHTMLReader.cpp new file mode 100644 index 0000000..6e4ba59 --- /dev/null +++ b/reader/src/formats/xhtml/XHTMLReader.cpp @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstring> +#include <cctype> + +#include <ZLFile.h> +#include <ZLFileUtil.h> +#include <ZLFileImage.h> +#include <ZLUnicodeUtil.h> +#include <ZLStringUtil.h> +#include <ZLXMLNamespace.h> +#include <ZLInputStream.h> +#include <ZLLogger.h> + +#include "XHTMLReader.h" +#include "../util/EntityFilesCollector.h" +#include "../util/MiscUtil.h" +#include "../css/StyleSheetParser.h" + +#include "../../bookmodel/BookReader.h" +#include "../../bookmodel/BookModel.h" + +std::map<std::string,XHTMLTagAction*> XHTMLReader::ourTagActions; + +XHTMLTagAction::~XHTMLTagAction() { +} + +BookReader &XHTMLTagAction::bookReader(XHTMLReader &reader) { + return reader.myModelReader; +} + +const std::string &XHTMLTagAction::pathPrefix(XHTMLReader &reader) { + return reader.myPathPrefix; +} + +void XHTMLTagAction::beginParagraph(XHTMLReader &reader) { + reader.beginParagraph(); +} + +void XHTMLTagAction::endParagraph(XHTMLReader &reader) { + reader.endParagraph(); +} + +class XHTMLTagStyleAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagLinkAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagParagraphAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagBodyAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagRestartParagraphAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagImageAction : public XHTMLTagAction { + +public: + XHTMLTagImageAction(shared_ptr<ZLXMLReader::AttributeNamePredicate> predicate); + XHTMLTagImageAction(const std::string &attributeName); + + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); + +private: + shared_ptr<ZLXMLReader::AttributeNamePredicate> myPredicate; +}; + +class XHTMLSvgImageAttributeNamePredicate : public ZLXMLReader::NamespaceAttributeNamePredicate { + +public: + XHTMLSvgImageAttributeNamePredicate(); + bool accepts(const ZLXMLReader &reader, const char *name) const; + +private: + bool myIsEnabled; + +friend class XHTMLTagSvgAction; +}; + +class XHTMLTagSvgAction : public XHTMLTagAction { + +public: + XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate); + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); + +private: + XHTMLSvgImageAttributeNamePredicate &myPredicate; +}; + +class XHTMLTagItemAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +class XHTMLTagHyperlinkAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); + +private: + std::stack<FBTextKind> myHyperlinkStack; +}; + +class XHTMLTagControlAction : public XHTMLTagAction { + +public: + XHTMLTagControlAction(FBTextKind control); + + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); + +private: + FBTextKind myControl; +}; + +class XHTMLTagParagraphWithControlAction : public XHTMLTagAction { + +public: + XHTMLTagParagraphWithControlAction(FBTextKind control); + + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); + +private: + FBTextKind myControl; +}; + +class XHTMLTagPreAction : public XHTMLTagAction { + +public: + void doAtStart(XHTMLReader &reader, const char **xmlattributes); + void doAtEnd(XHTMLReader &reader); +}; + +void XHTMLTagStyleAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) { + static const std::string TYPE = "text/css"; + + const char *type = reader.attributeValue(xmlattributes, "type"); + if ((type == 0) || (TYPE != type)) { + return; + } + + if (reader.myReadState == XHTMLReader::READ_NOTHING) { + reader.myReadState = XHTMLReader::READ_STYLE; + reader.myTableParser = new StyleSheetTableParser(reader.myStyleSheetTable); + ZLLogger::Instance().println("CSS", "parsing style tag content"); + } +} + +void XHTMLTagStyleAction::doAtEnd(XHTMLReader &reader) { + if (reader.myReadState == XHTMLReader::READ_STYLE) { + reader.myReadState = XHTMLReader::READ_NOTHING; + reader.myTableParser.reset(); + } +} + +void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) { + static const std::string REL = "stylesheet"; + const char *rel = reader.attributeValue(xmlattributes, "rel"); + if ((rel == 0) || (REL != rel)) { + return; + } + static const std::string TYPE = "text/css"; + + const char *type = reader.attributeValue(xmlattributes, "type"); + if ((type == 0) || (TYPE != type)) { + return; + } + + const char *href = reader.attributeValue(xmlattributes, "href"); + if (href == 0) { + return; + } + + ZLLogger::Instance().println("CSS", "style file: " + reader.myPathPrefix + MiscUtil::decodeHtmlURL(href)); + shared_ptr<ZLInputStream> cssStream = ZLFile(reader.myPathPrefix + MiscUtil::decodeHtmlURL(href)).inputStream(); + if (cssStream.isNull()) { + return; + } + ZLLogger::Instance().println("CSS", "parsing file"); + StyleSheetTableParser parser(reader.myStyleSheetTable); + parser.parse(*cssStream); + //reader.myStyleSheetTable.dump(); +} + +void XHTMLTagLinkAction::doAtEnd(XHTMLReader&) { +} + +void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) { + if (!reader.myNewParagraphInProgress) { + beginParagraph(reader); + reader.myNewParagraphInProgress = true; + } +} + +void XHTMLTagParagraphAction::doAtEnd(XHTMLReader &reader) { + endParagraph(reader); +} + +void XHTMLTagBodyAction::doAtStart(XHTMLReader &reader, const char**) { + reader.myReadState = XHTMLReader::READ_BODY; +} + +void XHTMLTagBodyAction::doAtEnd(XHTMLReader &reader) { + endParagraph(reader); + reader.myReadState = XHTMLReader::READ_NOTHING; +} + +void XHTMLTagRestartParagraphAction::doAtStart(XHTMLReader &reader, const char**) { + if (reader.myCurrentParagraphIsEmpty) { + bookReader(reader).addData(" "); + } + endParagraph(reader); + beginParagraph(reader); +} + +void XHTMLTagRestartParagraphAction::doAtEnd(XHTMLReader&) { +} + +void XHTMLTagItemAction::doAtStart(XHTMLReader &reader, const char**) { + endParagraph(reader); + // TODO: increase left indent + beginParagraph(reader); + // TODO: replace bullet sign by number inside OL tag + const std::string bullet = "\xE2\x80\xA2\xC0\xA0"; + bookReader(reader).addData(bullet); +} + +void XHTMLTagItemAction::doAtEnd(XHTMLReader &reader) { + endParagraph(reader); +} + +XHTMLTagImageAction::XHTMLTagImageAction(shared_ptr<ZLXMLReader::AttributeNamePredicate> predicate) { + myPredicate = predicate; +} + +XHTMLTagImageAction::XHTMLTagImageAction(const std::string &attributeName) { + myPredicate = new ZLXMLReader::FixedAttributeNamePredicate(attributeName); +} + +void XHTMLTagImageAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) { + const char *fileName = reader.attributeValue(xmlattributes, *myPredicate); + if (fileName == 0) { + return; + } + + const std::string fullfileName = pathPrefix(reader) + MiscUtil::decodeHtmlURL(fileName); + ZLFile imageFile(fullfileName); + if (!imageFile.exists()) { + return; + } + + bool flag = bookReader(reader).paragraphIsOpen(); + if (flag) { + endParagraph(reader); + } + if (std::strlen(fileName) > 2 && std::strncmp(fileName, "./", 2) == 0) { + fileName +=2; + } + bookReader(reader).addImageReference(fullfileName); + bookReader(reader).addImage(fullfileName, new ZLFileImage(ZLFile(fullfileName), 0)); + if (flag) { + beginParagraph(reader); + } +} + +XHTMLTagSvgAction::XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate) : myPredicate(predicate) { +} + +void XHTMLTagSvgAction::doAtStart(XHTMLReader&, const char**) { + myPredicate.myIsEnabled = true; +} + +void XHTMLTagSvgAction::doAtEnd(XHTMLReader&) { + myPredicate.myIsEnabled = false; +} + +XHTMLSvgImageAttributeNamePredicate::XHTMLSvgImageAttributeNamePredicate() : ZLXMLReader::NamespaceAttributeNamePredicate(ZLXMLNamespace::XLink, "href"), myIsEnabled(false) { +} + +bool XHTMLSvgImageAttributeNamePredicate::accepts(const ZLXMLReader &reader, const char *name) const { + return myIsEnabled && NamespaceAttributeNamePredicate::accepts(reader, name); +} + +void XHTMLTagImageAction::doAtEnd(XHTMLReader&) { +} + +XHTMLTagControlAction::XHTMLTagControlAction(FBTextKind control) : myControl(control) { +} + +void XHTMLTagControlAction::doAtStart(XHTMLReader &reader, const char**) { + bookReader(reader).pushKind(myControl); + bookReader(reader).addControl(myControl, true); +} + +void XHTMLTagControlAction::doAtEnd(XHTMLReader &reader) { + bookReader(reader).addControl(myControl, false); + bookReader(reader).popKind(); +} + +void XHTMLTagHyperlinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) { + const char *href = reader.attributeValue(xmlattributes, "href"); + if (href != 0 && href[0] != '\0') { + const FBTextKind hyperlinkType = MiscUtil::referenceType(href); + std::string link = MiscUtil::decodeHtmlURL(href); + if (hyperlinkType == INTERNAL_HYPERLINK) { + if (link[0] == '#') { + link = reader.myReferenceAlias + link; + } else { + link = reader.normalizedReference(reader.myReferenceDirName + link); + } + } + myHyperlinkStack.push(hyperlinkType); + bookReader(reader).addHyperlinkControl(hyperlinkType, link); + } else { + myHyperlinkStack.push(REGULAR); + } + const char *name = reader.attributeValue(xmlattributes, "name"); + if (name != 0) { + bookReader(reader).addHyperlinkLabel( + reader.myReferenceAlias + "#" + MiscUtil::decodeHtmlURL(name) + ); + } +} + +void XHTMLTagHyperlinkAction::doAtEnd(XHTMLReader &reader) { + FBTextKind kind = myHyperlinkStack.top(); + if (kind != REGULAR) { + bookReader(reader).addControl(kind, false); + } + myHyperlinkStack.pop(); +} + +XHTMLTagParagraphWithControlAction::XHTMLTagParagraphWithControlAction(FBTextKind control) : myControl(control) { +} + +void XHTMLTagParagraphWithControlAction::doAtStart(XHTMLReader &reader, const char**) { + if (myControl == TITLE && bookReader(reader).model().bookTextModel()->paragraphsNumber() > 1) { + bookReader(reader).insertEndOfSectionParagraph(); + } + bookReader(reader).pushKind(myControl); + beginParagraph(reader); +} + +void XHTMLTagParagraphWithControlAction::doAtEnd(XHTMLReader &reader) { + endParagraph(reader); + bookReader(reader).popKind(); +} + +void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) { + reader.myPreformatted = true; + beginParagraph(reader); + bookReader(reader).addControl(PREFORMATTED, true); +} + +void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) { + endParagraph(reader); + reader.myPreformatted = false; +} + +XHTMLTagAction *XHTMLReader::addAction(const std::string &tag, XHTMLTagAction *action) { + XHTMLTagAction *old = ourTagActions[tag]; + ourTagActions[tag] = action; + return old; +} + +void XHTMLReader::fillTagTable() { + if (ourTagActions.empty()) { + //addAction("html", new XHTMLTagAction()); + addAction("body", new XHTMLTagBodyAction()); + //addAction("title", new XHTMLTagAction()); + //addAction("meta", new XHTMLTagAction()); + //addAction("script", new XHTMLTagAction()); + + //addAction("font", new XHTMLTagAction()); + addAction("style", new XHTMLTagStyleAction()); + + addAction("p", new XHTMLTagParagraphAction()); + addAction("h1", new XHTMLTagParagraphWithControlAction(H1)); + addAction("h2", new XHTMLTagParagraphWithControlAction(H2)); + addAction("h3", new XHTMLTagParagraphWithControlAction(H3)); + addAction("h4", new XHTMLTagParagraphWithControlAction(H4)); + addAction("h5", new XHTMLTagParagraphWithControlAction(H5)); + addAction("h6", new XHTMLTagParagraphWithControlAction(H6)); + + //addAction("ol", new XHTMLTagAction()); + //addAction("ul", new XHTMLTagAction()); + //addAction("dl", new XHTMLTagAction()); + addAction("li", new XHTMLTagItemAction()); + + addAction("strong", new XHTMLTagControlAction(STRONG)); + addAction("b", new XHTMLTagControlAction(BOLD)); + addAction("em", new XHTMLTagControlAction(EMPHASIS)); + addAction("i", new XHTMLTagControlAction(ITALIC)); + addAction("code", new XHTMLTagControlAction(CODE)); + addAction("tt", new XHTMLTagControlAction(CODE)); + addAction("kbd", new XHTMLTagControlAction(CODE)); + addAction("var", new XHTMLTagControlAction(CODE)); + addAction("samp", new XHTMLTagControlAction(CODE)); + addAction("cite", new XHTMLTagControlAction(CITE)); + addAction("sub", new XHTMLTagControlAction(SUB)); + addAction("sup", new XHTMLTagControlAction(SUP)); + addAction("dd", new XHTMLTagControlAction(DEFINITION_DESCRIPTION)); + addAction("dfn", new XHTMLTagControlAction(DEFINITION)); + addAction("strike", new XHTMLTagControlAction(STRIKETHROUGH)); + + addAction("a", new XHTMLTagHyperlinkAction()); + + addAction("img", new XHTMLTagImageAction("src")); + addAction("object", new XHTMLTagImageAction("data")); + XHTMLSvgImageAttributeNamePredicate *predicate = new XHTMLSvgImageAttributeNamePredicate(); + addAction("image", new XHTMLTagImageAction(predicate)); + addAction("svg", new XHTMLTagSvgAction(*predicate)); + + //addAction("area", new XHTMLTagAction()); + //addAction("map", new XHTMLTagAction()); + + //addAction("base", new XHTMLTagAction()); + //addAction("blockquote", new XHTMLTagAction()); + addAction("br", new XHTMLTagRestartParagraphAction()); + //addAction("center", new XHTMLTagAction()); + addAction("div", new XHTMLTagParagraphAction()); + addAction("dt", new XHTMLTagParagraphAction()); + //addAction("head", new XHTMLTagAction()); + //addAction("hr", new XHTMLTagAction()); + addAction("link", new XHTMLTagLinkAction()); + //addAction("param", new XHTMLTagAction()); + //addAction("q", new XHTMLTagAction()); + //addAction("s", new XHTMLTagAction()); + + addAction("pre", new XHTMLTagPreAction()); + //addAction("big", new XHTMLTagAction()); + //addAction("small", new XHTMLTagAction()); + //addAction("u", new XHTMLTagAction()); + + //addAction("table", new XHTMLTagAction()); + addAction("td", new XHTMLTagParagraphAction()); + addAction("th", new XHTMLTagParagraphAction()); + //addAction("tr", new XHTMLTagAction()); + //addAction("caption", new XHTMLTagAction()); + //addAction("span", new XHTMLTagAction()); + } +} + +XHTMLReader::XHTMLReader(BookReader &modelReader) : myModelReader(modelReader) { +} + +bool XHTMLReader::readFile(const ZLFile &file, const std::string &referenceName) { + fillTagTable(); + + myPathPrefix = MiscUtil::htmlDirectoryPrefix(file.path()); + myReferenceAlias = fileAlias(referenceName); + myModelReader.addHyperlinkLabel(myReferenceAlias); + + const int index = referenceName.rfind('/', referenceName.length() - 1); + myReferenceDirName = referenceName.substr(0, index + 1); + + myPreformatted = false; + myNewParagraphInProgress = false; + myReadState = READ_NOTHING; + myCurrentParagraphIsEmpty = true; + + myStyleSheetTable.clear(); + myCSSStack.clear(); + myStyleEntryStack.clear(); + myStylesToRemove = 0; + + myDoPageBreakAfterStack.clear(); + myStyleParser = new StyleSheetSingleStyleParser(); + myTableParser.reset(); + + return readDocument(file); +} + +bool XHTMLReader::addStyleEntry(const std::string tag, const std::string aClass) { + shared_ptr<ZLTextStyleEntry> entry = myStyleSheetTable.control(tag, aClass); + if (!entry.isNull()) { + myModelReader.addStyleEntry(*entry); + myStyleEntryStack.push_back(entry); + return true; + } + return false; +} + +void XHTMLReader::startElementHandler(const char *tag, const char **attributes) { + static const std::string HASH = "#"; + const char *id = attributeValue(attributes, "id"); + if (id != 0) { + myModelReader.addHyperlinkLabel(myReferenceAlias + HASH + id); + } + + const std::string sTag = ZLUnicodeUtil::toLower(tag); + + const char *aClass = attributeValue(attributes, "class"); + const std::string sClass = (aClass != 0) ? aClass : ""; + + if (myStyleSheetTable.doBreakBefore(sTag, sClass)) { + myModelReader.insertEndOfSectionParagraph(); + } + myDoPageBreakAfterStack.push_back(myStyleSheetTable.doBreakAfter(sTag, sClass)); + + XHTMLTagAction *action = ourTagActions[sTag]; + if (action != 0) { + action->doAtStart(*this, attributes); + } + + const int sizeBefore = myStyleEntryStack.size(); + addStyleEntry(sTag, ""); + addStyleEntry("", sClass); + addStyleEntry(sTag, sClass); + const char *style = attributeValue(attributes, "style"); + if (style != 0) { + ZLLogger::Instance().println("CSS", std::string("parsing style attribute: ") + style); + shared_ptr<ZLTextStyleEntry> entry = myStyleParser->parseString(style); + myModelReader.addStyleEntry(*entry); + myStyleEntryStack.push_back(entry); + } else { + } + myCSSStack.push_back(myStyleEntryStack.size() - sizeBefore); +} + +void XHTMLReader::endElementHandler(const char *tag) { + for (int i = myCSSStack.back(); i > 0; --i) { + myModelReader.addStyleCloseEntry(); + } + myStylesToRemove = myCSSStack.back(); + myCSSStack.pop_back(); + + XHTMLTagAction *action = ourTagActions[ZLUnicodeUtil::toLower(tag)]; + if (action != 0) { + action->doAtEnd(*this); + myNewParagraphInProgress = false; + } + + for (; myStylesToRemove > 0; --myStylesToRemove) { + myStyleEntryStack.pop_back(); + } + + if (myDoPageBreakAfterStack.back()) { + myModelReader.insertEndOfSectionParagraph(); + } + myDoPageBreakAfterStack.pop_back(); +} + +void XHTMLReader::beginParagraph() { + myCurrentParagraphIsEmpty = true; + myModelReader.beginParagraph(); + bool doBlockSpaceBefore = false; + for (std::vector<shared_ptr<ZLTextStyleEntry> >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end(); ++it) { + myModelReader.addStyleEntry(**it); + doBlockSpaceBefore = + doBlockSpaceBefore || + (*it)->isFeatureSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE); + } + + if (doBlockSpaceBefore) { + ZLTextStyleEntry blockingEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + blockingEntry.setLength( + ZLTextStyleEntry::LENGTH_SPACE_BEFORE, + 0, + ZLTextStyleEntry::SIZE_UNIT_PIXEL + ); + myModelReader.addStyleEntry(blockingEntry); + } +} + +void XHTMLReader::endParagraph() { + bool doBlockSpaceAfter = false; + for (std::vector<shared_ptr<ZLTextStyleEntry> >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end() - myStylesToRemove; ++it) { + doBlockSpaceAfter = + doBlockSpaceAfter || + (*it)->isFeatureSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER); + } + if (doBlockSpaceAfter) { + ZLTextStyleEntry blockingEntry(ZLTextStyleEntry::STYLE_OTHER_ENTRY); + blockingEntry.setLength( + ZLTextStyleEntry::LENGTH_SPACE_AFTER, + 0, + ZLTextStyleEntry::SIZE_UNIT_PIXEL + ); + myModelReader.addStyleEntry(blockingEntry); + } + for (; myStylesToRemove > 0; --myStylesToRemove) { + myModelReader.addStyleEntry(*myStyleEntryStack.back()); + myStyleEntryStack.pop_back(); + } + myModelReader.endParagraph(); +} + +void XHTMLReader::characterDataHandler(const char *text, std::size_t len) { + switch (myReadState) { + case READ_NOTHING: + break; + case READ_STYLE: + if (!myTableParser.isNull()) { + myTableParser->parse(text, len); + } + break; + case READ_BODY: + if (myPreformatted) { + if (*text == '\r' || *text == '\n') { + endParagraph(); + text += 1; + len -= 1; + beginParagraph(); + myModelReader.addControl(PREFORMATTED, true); + } + std::size_t spaceCounter = 0; + while (spaceCounter < len && std::isspace((unsigned char)*(text + spaceCounter))) { + ++spaceCounter; + } + myModelReader.addFixedHSpace(spaceCounter); + text += spaceCounter; + len -= spaceCounter; + } else if (myNewParagraphInProgress || !myModelReader.paragraphIsOpen()) { + while (std::isspace((unsigned char)*text)) { + ++text; + if (--len == 0) { + break; + } + } + } + if (len > 0) { + myCurrentParagraphIsEmpty = false; + if (!myModelReader.paragraphIsOpen()) { + myModelReader.beginParagraph(); + } + myModelReader.addData(std::string(text, len)); + myNewParagraphInProgress = false; + } + break; + } +} + +const std::vector<std::string> &XHTMLReader::externalDTDs() const { + return EntityFilesCollector::Instance().externalDTDs("xhtml"); +} + +bool XHTMLReader::processNamespaces() const { + return true; +} + +const std::string XHTMLReader::normalizedReference(const std::string &reference) const { + const std::size_t index = reference.find('#'); + if (index == std::string::npos) { + return fileAlias(reference); + } else { + return fileAlias(reference.substr(0, index)) + reference.substr(index); + } +} + +const std::string &XHTMLReader::fileAlias(const std::string &fileName) const { + std::map<std::string,std::string>::const_iterator it = myFileNumbers.find(fileName); + if (it != myFileNumbers.end()) { + return it->second; + } + + const std::string correctedFileName = + ZLFileUtil::normalizeUnixPath(MiscUtil::decodeHtmlURL(fileName)); + it = myFileNumbers.find(correctedFileName); + if (it != myFileNumbers.end()) { + return it->second; + } + + std::string num; + ZLStringUtil::appendNumber(num, myFileNumbers.size()); + myFileNumbers.insert(std::make_pair(correctedFileName, num)); + it = myFileNumbers.find(correctedFileName); + return it->second; +} diff --git a/reader/src/formats/xhtml/XHTMLReader.h b/reader/src/formats/xhtml/XHTMLReader.h new file mode 100644 index 0000000..08d4c02 --- /dev/null +++ b/reader/src/formats/xhtml/XHTMLReader.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __XHTMLREADER_H__ +#define __XHTMLREADER_H__ + +#include <string> +#include <map> +#include <vector> + +#include <ZLXMLReader.h> + +#include "../css/StyleSheetTable.h" +#include "../css/StyleSheetParser.h" + +class ZLFile; + +class BookReader; +class XHTMLReader; + +class XHTMLTagAction { + +public: + virtual ~XHTMLTagAction(); + + virtual void doAtStart(XHTMLReader &reader, const char **xmlattributes) = 0; + virtual void doAtEnd(XHTMLReader &reader) = 0; + +protected: + static BookReader &bookReader(XHTMLReader &reader); + static const std::string &pathPrefix(XHTMLReader &reader); + static void beginParagraph(XHTMLReader &reader); + static void endParagraph(XHTMLReader &reader); +}; + +class XHTMLReader : public ZLXMLReader { + +public: + static XHTMLTagAction *addAction(const std::string &tag, XHTMLTagAction *action); + static void fillTagTable(); + +private: + static std::map<std::string,XHTMLTagAction*> ourTagActions; + +public: + XHTMLReader(BookReader &modelReader); + bool readFile(const ZLFile &file, const std::string &referenceName); + const std::string &fileAlias(const std::string &fileName) const; + const std::string normalizedReference(const std::string &reference) const; + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + + const std::vector<std::string> &externalDTDs() const; + + bool processNamespaces() const; + + void beginParagraph(); + void endParagraph(); + bool addStyleEntry(const std::string tag, const std::string aClass); + +private: + mutable std::map<std::string,std::string> myFileNumbers; + + BookReader &myModelReader; + std::string myPathPrefix; + std::string myReferenceAlias; + std::string myReferenceDirName; + bool myPreformatted; + bool myNewParagraphInProgress; + StyleSheetTable myStyleSheetTable; + std::vector<int> myCSSStack; + std::vector<shared_ptr<ZLTextStyleEntry> > myStyleEntryStack; + int myStylesToRemove; + std::vector<bool> myDoPageBreakAfterStack; + bool myCurrentParagraphIsEmpty; + shared_ptr<StyleSheetSingleStyleParser> myStyleParser; + shared_ptr<StyleSheetTableParser> myTableParser; + enum { + READ_NOTHING, + READ_STYLE, + READ_BODY + } myReadState; + + friend class XHTMLTagAction; + friend class XHTMLTagStyleAction; + friend class XHTMLTagLinkAction; + friend class XHTMLTagHyperlinkAction; + friend class XHTMLTagPreAction; + friend class XHTMLTagParagraphAction; + friend class XHTMLTagBodyAction; + friend class XHTMLTagRestartParagraphAction; +}; + +#endif /* __XHTMLREADER_H__ */ diff --git a/reader/src/library/Author.cpp b/reader/src/library/Author.cpp new file mode 100644 index 0000000..2478bdd --- /dev/null +++ b/reader/src/library/Author.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> + +#include "Author.h" + +std::set<shared_ptr<Author>,AuthorComparator> Author::ourAuthorSet; + +shared_ptr<Author> Author::getAuthor(const std::string &name, const std::string &sortKey) { + std::string strippedName = name; + ZLUnicodeUtil::utf8Trim(strippedName); + if (strippedName.empty()) { + return 0; + } + std::string strippedKey = sortKey; + ZLUnicodeUtil::utf8Trim(strippedKey); + + if (strippedKey.empty()) { + const std::size_t index = strippedName.find(','); + if (index != std::string::npos) { + strippedKey = strippedName.substr(0, index); + ZLUnicodeUtil::utf8Trim(strippedKey); + } + } + + if (strippedKey.empty()) { + std::size_t index = strippedName.rfind(' '); + if (index == std::string::npos) { + strippedKey = strippedName; + } else { + strippedKey = strippedName.substr(index + 1); + const std::size_t size = strippedName.size(); + while (index < size && strippedName[index] == ' ') { + --index; + } + strippedName = strippedName.substr(0, index + 1) + ' ' + strippedKey; + } + } + + shared_ptr<Author> author = + new Author(strippedName, ZLUnicodeUtil::toLower(strippedKey)); + std::set<shared_ptr<Author>,AuthorComparator>::const_iterator it = + ourAuthorSet.find(author); + if (it != ourAuthorSet.end()) { + return *it; + } else { + ourAuthorSet.insert(author); + return author; + } +} diff --git a/reader/src/library/Author.h b/reader/src/library/Author.h new file mode 100644 index 0000000..04907f8 --- /dev/null +++ b/reader/src/library/Author.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __AUTHOR_H__ +#define __AUTHOR_H__ + +#include <string> +#include <map> +#include <set> + +#include <shared_ptr.h> + +#include "Lists.h" + +class Author; + +class AuthorComparator { + +public: + bool operator () ( + const shared_ptr<Author> author0, + const shared_ptr<Author> author1 + ) const; +}; + +class Author { + +private: + static std::set<shared_ptr<Author>,AuthorComparator> ourAuthorSet; + +public: + static shared_ptr<Author> getAuthor(const std::string &name, const std::string &sortKey = ""); + +private: + Author(const std::string &name, const std::string &sortkey); + +public: + const std::string &name() const; + const std::string &sortKey() const; + +private: + const std::string myName; + const std::string mySortKey; + +private: // disable copying: + Author(const Author &); + const Author &operator = (const Author &); +}; + +inline Author::Author(const std::string &name, const std::string &sortkey) : myName(name), mySortKey(sortkey) {} + +inline const std::string &Author::name() const { return myName; } +inline const std::string &Author::sortKey() const { return mySortKey; } + +#endif /* __AUTHOR_H__ */ diff --git a/reader/src/library/Book.cpp b/reader/src/library/Book.cpp new file mode 100644 index 0000000..ca3afd0 --- /dev/null +++ b/reader/src/library/Book.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> +#include <set> + +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLLanguageList.h> + +#include "Book.h" +#include "Author.h" +#include "Tag.h" + +#include "../formats/FormatPlugin.h" +#include "../migration/BookInfo.h" + +const std::string Book::AutoEncoding = "auto"; + +Book::Book(const ZLFile &file, int id) : myBookId(id), myFile(file) { +} + +Book::~Book() { +} + +shared_ptr<Book> Book::createBook( + const ZLFile &file, + int id, + const std::string &encoding, + const std::string &language, + const std::string &title +) { + Book *book = new Book(file, id); + book->setEncoding(encoding); + book->setLanguage(language); + book->setTitle(title); + return book; +} + +shared_ptr<Book> Book::loadFromFile(const ZLFile &file) { + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(file, false); + if (plugin.isNull()) { + return 0; + } + + shared_ptr<Book> book = new Book(file, 0); + if (!plugin->readMetaInfo(*book)) { + return 0; + } + plugin->readLanguageAndEncoding(*book); + + if (book->title().empty()) { + book->setTitle(ZLFile::fileNameToUtf8(file.name(true))); + } + + if (book->encoding().empty()) { + book->setEncoding(AutoEncoding); + } + + if (book->language().empty()) { + book->setLanguage(PluginCollection::Instance().DefaultLanguageOption.value()); + } + + return book; +} + +bool Book::addTag(shared_ptr<Tag> tag) { + if (tag.isNull()) { + return false; + } + TagList::const_iterator it = std::find(myTags.begin(), myTags.end(), tag); + if (it == myTags.end()) { + myTags.push_back(tag); + return true; + } + return false; +} + +bool Book::addTag(const std::string &fullName) { + return addTag(Tag::getTagByFullName(fullName)); +} + +bool Book::removeTag(shared_ptr<Tag> tag, bool includeSubTags) { + bool changed = false; + for (TagList::iterator it = myTags.begin(); it != myTags.end();) { + if (tag == *it || (includeSubTags && tag->isAncestorOf(*it))) { + it = myTags.erase(it); + changed = true; + } else { + ++it; + } + } + return changed; +} + +bool Book::renameTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (includeSubTags) { + std::set<shared_ptr<Tag> > tagSet; + bool changed = false; + for (TagList::const_iterator it = myTags.begin(); it != myTags.end(); ++it) { + if (*it == from) { + tagSet.insert(to); + changed = true; + } else { + shared_ptr<Tag> newtag = Tag::cloneSubTag(*it, from, to); + if (newtag.isNull()) { + tagSet.insert(*it); + } else { + tagSet.insert(newtag); + changed = true; + } + } + } + if (changed) { + myTags.clear(); + myTags.insert(myTags.end(), tagSet.begin(), tagSet.end()); + return true; + } + } else { + TagList::iterator it = std::find(myTags.begin(), myTags.end(), from); + if (it != myTags.end()) { + TagList::const_iterator jt = std::find(myTags.begin(), myTags.end(), to); + if (jt == myTags.end()) { + *it = to; + } else { + myTags.erase(it); + } + return true; + } + } + return false; +} + +bool Book::cloneTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (includeSubTags) { + std::set<shared_ptr<Tag> > tagSet; + for (TagList::const_iterator it = myTags.begin(); it != myTags.end(); ++it) { + if (*it == from) { + tagSet.insert(to); + } else { + shared_ptr<Tag> newtag = Tag::cloneSubTag(*it, from, to); + if (!newtag.isNull()) { + tagSet.insert(newtag); + } + } + } + if (!tagSet.empty()) { + tagSet.insert(myTags.begin(), myTags.end()); + myTags.clear(); + myTags.insert(myTags.end(), tagSet.begin(), tagSet.end()); + return true; + } + } else { + TagList::const_iterator it = std::find(myTags.begin(), myTags.end(), from); + if (it != myTags.end()) { + TagList::const_iterator jt = std::find(myTags.begin(), myTags.end(), to); + if (jt == myTags.end()) { + myTags.push_back(to); + return true; + } + } + } + return false; +} + +shared_ptr<Book> Book::loadFromBookInfo(const ZLFile &file) { + BookInfo info(file.path()); + + shared_ptr<Book> book = createBook( + file, 0, + info.EncodingOption.value(), + info.LanguageOption.value(), + info.TitleOption.value() + ); + + book->setSeries( + info.SeriesTitleOption.value(), + Number(info.IndexInSeriesOption.value()) + ); + + if (book->language().empty()) { + book->setLanguage(PluginCollection::Instance().DefaultLanguageOption.value()); + } + + const std::string &tagList = info.TagsOption.value(); + if (!tagList.empty()) { + std::size_t index = 0; + do { + std::size_t newIndex = tagList.find(',', index); + book->addTag(Tag::getTagByFullName(tagList.substr(index, newIndex - index))); + index = newIndex + 1; + } while (index != 0); + } + + const std::string &authorList = info.AuthorDisplayNameOption.value(); + if (!authorList.empty()) { + std::size_t index = 0; + do { + std::size_t newIndex = authorList.find(',', index); + book->addAuthor(authorList.substr(index, newIndex - index)); + index = newIndex + 1; + } while (index != 0); + } + + return book; +} + +bool Book::replaceAuthor(shared_ptr<Author> from, shared_ptr<Author> to) { + AuthorList::iterator it = std::find(myAuthors.begin(), myAuthors.end(), from); + if (it == myAuthors.end()) { + return false; + } + if (to.isNull()) { + myAuthors.erase(it); + } else { + *it = to; + } + return true; +} + +void Book::setTitle(const std::string &title) { + myTitle = title; +} + +void Book::setLanguage(const std::string &language) { + if (!myLanguage.empty()) { + const std::vector<std::string> &codes = ZLLanguageList::languageCodes(); + std::vector<std::string>::const_iterator it = + std::find(codes.begin(), codes.end(), myLanguage); + std::vector<std::string>::const_iterator jt = + std::find(codes.begin(), codes.end(), language); + if (it != codes.end() && jt == codes.end()) { + return; + } + } + myLanguage = language; +} + +void Book::setEncoding(const std::string &encoding) { + myEncoding = encoding; +} + +void Book::setSeries(const std::string &title, const Number &index) { + mySeriesTitle = title; + myIndexInSeries = index; +} + +void Book::removeAllTags() { + myTags.clear(); +} + +void Book::addAuthor(const std::string &displayName, const std::string &sortKey) { + addAuthor(Author::getAuthor(displayName, sortKey)); +} + +void Book::addAuthor(shared_ptr<Author> author) { + if (!author.isNull()) { + myAuthors.push_back(author); + } +} + +void Book::removeAllAuthors() { + myAuthors.clear(); +} diff --git a/reader/src/library/Book.h b/reader/src/library/Book.h new file mode 100644 index 0000000..daed2e0 --- /dev/null +++ b/reader/src/library/Book.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOK_H__ +#define __BOOK_H__ + +#include <string> + +#include <shared_ptr.h> + +#include <ZLFile.h> + +#include "Lists.h" +#include "Number.h" + +class Author; +class Tag; + +class Book { + +public: + static const std::string AutoEncoding; + +public: + static shared_ptr<Book> createBook( + const ZLFile &file, + int id, + const std::string &encoding, + const std::string &language, + const std::string &title + ); + + static shared_ptr<Book> loadFromFile(const ZLFile &file); + + // this method is used in Migration only + static shared_ptr<Book> loadFromBookInfo(const ZLFile &file); + +private: + Book(const ZLFile &file, int id); + +public: + ~Book(); + +public: // unmodifiable book methods + const std::string &title() const; + const ZLFile &file() const; + const std::string &language() const; + const std::string &encoding() const; + const std::string &seriesTitle() const; + const Number &indexInSeries() const; + + const TagList &tags() const; + const AuthorList &authors() const; + +public: // modifiable book methods + void setTitle(const std::string &title); + void setLanguage(const std::string &language); + void setEncoding(const std::string &encoding); + void setSeries(const std::string &title, const Number &index); + +public: + bool addTag(shared_ptr<Tag> tag); + bool addTag(const std::string &fullName); + bool removeTag(shared_ptr<Tag> tag, bool includeSubTags); + bool renameTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + bool cloneTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + void removeAllTags(); + + void addAuthor(shared_ptr<Author> author); + void addAuthor(const std::string &displayName, const std::string &sortKey = std::string()); + bool replaceAuthor(shared_ptr<Author> from, shared_ptr<Author> to); + void removeAllAuthors(); + +public: + int bookId() const; + void setBookId(int bookId); + +private: + int myBookId; + + const ZLFile myFile; + std::string myTitle; + std::string myLanguage; + std::string myEncoding; + std::string mySeriesTitle; + Number myIndexInSeries; + TagList myTags; + AuthorList myAuthors; + +private: // disable copying + Book(const Book &); + const Book &operator = (const Book &); +}; + +class BookComparator { + +public: + bool operator () ( + const shared_ptr<Book> book0, + const shared_ptr<Book> book1 + ) const; +}; + +class BookByFileNameComparator { + +public: + bool operator () ( + const shared_ptr<Book> book0, + const shared_ptr<Book> book1 + ) const; +}; + +inline const std::string &Book::title() const { return myTitle; } +inline const ZLFile &Book::file() const { return myFile; } +inline const std::string &Book::language() const { return myLanguage; } +inline const std::string &Book::encoding() const { return myEncoding; } +inline const std::string &Book::seriesTitle() const { return mySeriesTitle; } +inline const Number &Book::indexInSeries() const { return myIndexInSeries; } + +inline const TagList &Book::tags() const { return myTags; } +inline const AuthorList &Book::authors() const { return myAuthors; } + +inline int Book::bookId() const { return myBookId; } +inline void Book::setBookId(int bookId) { myBookId = bookId; } + +#endif /* __BOOK_H__ */ diff --git a/reader/src/library/Comparators.cpp b/reader/src/library/Comparators.cpp new file mode 100644 index 0000000..30b4059 --- /dev/null +++ b/reader/src/library/Comparators.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include "Book.h" +#include "Author.h" +#include "Tag.h" + +bool BookComparator::operator() ( + const shared_ptr<Book> book0, + const shared_ptr<Book> book1 +) const { + const std::string &seriesTitle0 = book0->seriesTitle(); + const std::string &seriesTitle1 = book1->seriesTitle(); + int comp = seriesTitle0.compare(seriesTitle1); + if (comp == 0) { + if (!seriesTitle0.empty()) { + if (book0->indexInSeries() < book1->indexInSeries() && + !(book0->indexInSeries() == book1->indexInSeries())) { + return true; + } + } + return book0->title() < book1->title(); + } + if (seriesTitle0.empty()) { + return book0->title() < seriesTitle1; + } + if (seriesTitle1.empty()) { + return seriesTitle0 <= book1->title(); + } + return comp < 0; +} + +bool BookByFileNameComparator::operator() ( + const shared_ptr<Book> book0, + const shared_ptr<Book> book1 +) const { + return book0->file() < book1->file(); +} + +bool AuthorComparator::operator() ( + const shared_ptr<Author> author0, + const shared_ptr<Author> author1 +) const { + if (author0.isNull()) { + return !author1.isNull(); + } + if (author1.isNull()) { + return false; + } + + const int comp = author0->sortKey().compare(author1->sortKey()); + return comp != 0 ? comp < 0 : author0->name() < author1->name(); +} + +bool TagComparator::operator() ( + shared_ptr<Tag> tag0, + shared_ptr<Tag> tag1 +) const { + if (tag0.isNull()) { + return !tag1.isNull(); + } + if (tag1.isNull()) { + return false; + } + + std::size_t level0 = tag0->level(); + std::size_t level1 = tag1->level(); + if (level0 > level1) { + for (; level0 > level1; --level0) { + tag0 = tag0->parent(); + } + if (tag0 == tag1) { + return false; + } + } else if (level0 < level1) { + for (; level0 < level1; --level1) { + tag1 = tag1->parent(); + } + if (tag0 == tag1) { + return true; + } + } + while (tag0->parent() != tag1->parent()) { + tag0 = tag0->parent(); + tag1 = tag1->parent(); + } + return tag0->name() < tag1->name(); +} diff --git a/reader/src/library/Library.cpp b/reader/src/library/Library.cpp new file mode 100644 index 0000000..8ee1f36 --- /dev/null +++ b/reader/src/library/Library.cpp @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <queue> +#include <algorithm> + +#include <ZLibrary.h> +#include <ZLStringUtil.h> +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLDialogManager.h> + +#include "Library.h" +#include "Book.h" +#include "Author.h" +#include "Tag.h" + +#include "../formats/FormatPlugin.h" + +#include "../database/booksdb/BooksDBUtil.h" +#include "../database/booksdb/BooksDB.h" + +shared_ptr<Library> Library::ourInstance; +const std::size_t Library::MaxRecentListSize = 10; + +Library &Library::Instance() { + if (ourInstance.isNull()) { + ourInstance = new Library(); + } + return *ourInstance; +} + +static const std::string OPTIONS = "Options"; + +Library::Library() : + PathOption(ZLCategoryKey::CONFIG, OPTIONS, "BookPath", ""), + ScanSubdirsOption(ZLCategoryKey::CONFIG, OPTIONS, "ScanSubdirs", true), + CollectAllBooksOption(ZLCategoryKey::CONFIG, OPTIONS, "CollectAllBooks", false), + myBuildMode(BUILD_ALL), + myRevision(0) { + BooksDBUtil::getRecentBooks(myRecentBooks); +} + +void Library::collectBookFileNames(std::set<std::string> &bookFileNames) const { + std::set<std::string> dirs; + collectDirNames(dirs); + + while (!dirs.empty()) { + std::string dirname = *dirs.begin(); + dirs.erase(dirs.begin()); + + ZLFile dirfile(dirname); + std::vector<std::string> files; + bool inZip = false; + + shared_ptr<ZLDir> dir = dirfile.directory(); + if (dir.isNull()) { + continue; + } + + if (dirfile.isArchive()) { + ZLFile phys(dirfile.physicalFilePath()); + if (!BooksDBUtil::checkInfo(phys)) { + BooksDBUtil::resetZipInfo(phys); + BooksDBUtil::saveInfo(phys); + } + BooksDBUtil::listZipEntries(dirfile, files); + inZip = true; + } else { + dir->collectFiles(files, true); + } + if (!files.empty()) { + const bool collectBookWithoutMetaInfo = CollectAllBooksOption.value(); + for (std::vector<std::string>::const_iterator jt = files.begin(); jt != files.end(); ++jt) { + const std::string fileName = (inZip) ? (*jt) : (dir->itemPath(*jt)); + ZLFile file(fileName); + if (PluginCollection::Instance().plugin(file, !collectBookWithoutMetaInfo) != 0) { + bookFileNames.insert(fileName); + } else if (file.isArchive()) { + if (myScanSubdirs || !inZip) { + dirs.insert(fileName); + } + } + } + } + } +} + +void Library::rebuildBookSet() const { + myBooks.clear(); + myExternalBooks.clear(); + + std::map<std::string, shared_ptr<Book> > booksMap; + BooksDBUtil::getBooks(booksMap); + + std::set<std::string> fileNamesSet; + collectBookFileNames(fileNamesSet); + + // collect books from book path + for (std::set<std::string>::iterator it = fileNamesSet.begin(); it != fileNamesSet.end(); ++it) { + std::map<std::string, shared_ptr<Book> >::iterator jt = booksMap.find(*it); + if (jt == booksMap.end()) { + insertIntoBookSet(BooksDBUtil::getBook(*it)); + } else { + insertIntoBookSet(jt->second); + booksMap.erase(jt); + } + } + + // other books from our database + for (std::map<std::string, shared_ptr<Book> >::iterator jt = booksMap.begin(); jt != booksMap.end(); ++jt) { + shared_ptr<Book> book = jt->second; + if (!book.isNull()) { + if (BooksDB::Instance().checkBookList(*book)) { + insertIntoBookSet(book); + myExternalBooks.insert(book); + } + } + } +} + +std::size_t Library::revision() const { + if (myBuildMode == BUILD_NOTHING && + (myScanSubdirs != ScanSubdirsOption.value() || + myPath != PathOption.value())) { + myPath = PathOption.value(); + myScanSubdirs = ScanSubdirsOption.value(); + myBuildMode = BUILD_ALL; + } + + return (myBuildMode == BUILD_NOTHING) ? myRevision : myRevision + 1; +} + +class LibrarySynchronizer : public DBRunnable { + +public: + LibrarySynchronizer(Library::BuildMode mode) : myBuildMode(mode) { } + +private: + bool run() { + Library &library = Library::Instance(); + + if (myBuildMode & Library::BUILD_COLLECT_FILES_INFO) { + library.rebuildBookSet(); + } + + if (myBuildMode & Library::BUILD_UPDATE_BOOKS_INFO) { + library.rebuildMaps(); + } + return true; + } + +private: + const Library::BuildMode myBuildMode; +}; + +class LibrarySynchronizerWrapper : public ZLRunnable { + +public: + LibrarySynchronizerWrapper(Library::BuildMode mode) : myRunnable(mode) { } + +private: + void run() { + BooksDB::Instance().executeAsTransaction(myRunnable); + } + +private: + LibrarySynchronizer myRunnable; +}; + +void Library::synchronize() const { + if (myScanSubdirs != ScanSubdirsOption.value() || + myPath != PathOption.value()) { + myPath = PathOption.value(); + myScanSubdirs = ScanSubdirsOption.value(); + myBuildMode = BUILD_ALL; + } + + if (myBuildMode == BUILD_NOTHING) { + return; + } + + LibrarySynchronizerWrapper synchronizer(myBuildMode); + myBuildMode = BUILD_NOTHING; + ZLDialogManager::Instance().wait(ZLResourceKey("loadingBookList"), synchronizer); + + ++myRevision; +} + +void Library::rebuildMaps() const { + myAuthors.clear(); + myBooksByAuthor.clear(); + myTags.clear(); + myBooksByTag.clear(); + + for (BookSet::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + if ((*it).isNull()) { + continue; + } + + const AuthorList &bookAuthors = (*it)->authors(); + if (bookAuthors.empty()) { + myBooksByAuthor[0].push_back(*it); + } else { + for(AuthorList::const_iterator jt = bookAuthors.begin(); jt != bookAuthors.end(); ++jt) { + myBooksByAuthor[*jt].push_back(*it); + } + } + + const TagList &bookTags = (*it)->tags(); + if (bookTags.empty()) { + myBooksByTag[0].push_back(*it); + } else { + for(TagList::const_iterator kt = bookTags.begin(); kt != bookTags.end(); ++kt) { + myBooksByTag[*kt].push_back(*it); + } + } + } + for (BooksByAuthor::iterator mit = myBooksByAuthor.begin(); mit != myBooksByAuthor.end(); ++mit) { + myAuthors.push_back(mit->first); + std::sort(mit->second.begin(), mit->second.end(), BookComparator()); + } + for (BooksByTag::iterator mjt = myBooksByTag.begin(); mjt != myBooksByTag.end(); ++mjt) { + myTags.push_back(mjt->first); + std::sort(mjt->second.begin(), mjt->second.end(), BookComparator()); + } +} + +void Library::collectDirNames(std::set<std::string> &nameSet) const { + std::queue<std::string> nameQueue; + + std::string path = myPath; + int pos = path.find(ZLibrary::PathDelimiter); + while (pos != -1) { + nameQueue.push(path.substr(0, pos)); + path.erase(0, pos + 1); + pos = path.find(ZLibrary::PathDelimiter); + } + if (!path.empty()) { + nameQueue.push(path); + } + + std::set<std::string> resolvedNameSet; + while (!nameQueue.empty()) { + std::string name = nameQueue.front(); + nameQueue.pop(); + ZLFile f(name); + const std::string resolvedName = f.resolvedPath(); + if (resolvedNameSet.find(resolvedName) == resolvedNameSet.end()) { + if (myScanSubdirs) { + shared_ptr<ZLDir> dir = f.directory(); + if (!dir.isNull()) { + std::vector<std::string> subdirs; + dir->collectSubDirs(subdirs, true); + for (std::vector<std::string>::const_iterator it = subdirs.begin(); it != subdirs.end(); ++it) { + nameQueue.push(dir->itemPath(*it)); + } + } + } + resolvedNameSet.insert(resolvedName); + nameSet.insert(name); + } + } +} + +void Library::updateBook(shared_ptr<Book> book) { + BooksDB::Instance().saveBook(book); + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); +} + +void Library::addBook(shared_ptr<Book> book) { + if (!book.isNull()) { + BooksDB::Instance().saveBook(book); + insertIntoBookSet(book); + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); + } +} + +void Library::removeBook(shared_ptr<Book> book) { + if (!book.isNull()) { + BookSet::iterator it = myBooks.find(book); + if (it != myBooks.end()) { + myBooks.erase(it); + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); + } + BooksDB::Instance().deleteFromBookList(*book); + bool recentListChanged = false; + for (BookList::iterator it = myRecentBooks.begin(); it != myRecentBooks.end();) { + if ((*it)->file() == book->file()) { + it = myRecentBooks.erase(it); + recentListChanged = true; + } else { + ++it; + } + } + if (recentListChanged) { + BooksDB::Instance().saveRecentBooks(myRecentBooks); + } + } +} + +const AuthorList &Library::authors() const { + synchronize(); + return myAuthors; +} + +const TagList &Library::tags() const { + synchronize(); + return myTags; +} + +const BookList &Library::books(shared_ptr<Author> author) const { + synchronize(); + return myBooksByAuthor[author]; +} + +const BookList &Library::books(shared_ptr<Tag> tag) const { + synchronize(); + return myBooksByTag[tag]; +} + +void Library::collectSeriesTitles(shared_ptr<Author> author, std::set<std::string> &titles) const { + const BookList &bookList = books(author); + for (BookList::const_iterator it = bookList.begin(); it != bookList.end(); ++it) { + const std::string ¤t = (*it)->seriesTitle(); + if (!current.empty()) { + titles.insert(current); + } + } +} + +void Library::removeTag(shared_ptr<Tag> tag, bool includeSubTags) { + for (BookSet::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + if ((*it)->removeTag(tag, includeSubTags)) { + BooksDB::Instance().saveTags(*it); + } + } + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); +} + +void Library::renameTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (to != from) { + synchronize(); + for (BookSet::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + BooksDBUtil::renameTag(*it, from, to, includeSubTags); + } + } + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); +} + +void Library::cloneTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (to != from) { + synchronize(); + for (BookSet::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + BooksDBUtil::cloneTag(*it, from, to, includeSubTags); + } + } + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); +} + +bool Library::hasBooks(shared_ptr<Tag> tag) const { + synchronize(); + const BooksByTag::const_iterator it = myBooksByTag.find(tag); + return it != myBooksByTag.end() && !it->second.empty(); +} + +bool Library::hasSubtags(shared_ptr<Tag> tag) const { + const TagList &tagList = tags(); + const TagList::const_iterator it = + std::upper_bound(tagList.begin(), tagList.end(), tag, TagComparator()); + return it != tagList.end() && tag->isAncestorOf(*it); +} + +void Library::replaceAuthor(shared_ptr<Author> from, shared_ptr<Author> to) { + if (to != from) { + for (BookSet::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + if ((*it)->replaceAuthor(from, to)) { + BooksDB::Instance().saveAuthors(*it); + } + } + myBuildMode = (BuildMode)(myBuildMode | BUILD_UPDATE_BOOKS_INFO); + } +} + +Library::RemoveType Library::canRemove(shared_ptr<Book> book) const { + synchronize(); + return (RemoveType)( + (myExternalBooks.find(book) != myExternalBooks.end() ? + REMOVE_FROM_LIBRARY : REMOVE_DONT_REMOVE) | + (BooksDBUtil::canRemoveFile(book->file().path()) ? + REMOVE_FROM_DISK : REMOVE_DONT_REMOVE) + ); +} + +void Library::insertIntoBookSet(shared_ptr<Book> book) const { + if (!book.isNull()) { + myBooks.insert(book); + } +} + +const BookList &Library::recentBooks() const { + return myRecentBooks; +} + +void Library::addBookToRecentList(shared_ptr<Book> book) { + if (book.isNull()) { + return; + } + for (BookList::iterator it = myRecentBooks.begin(); it != myRecentBooks.end(); ++it) { + if ((*it)->file() == book->file()) { + if (it == myRecentBooks.begin()) { + return; + } + myRecentBooks.erase(it); + break; + } + } + myRecentBooks.insert(myRecentBooks.begin(), book); + if (myRecentBooks.size() > MaxRecentListSize) { + myRecentBooks.erase(myRecentBooks.begin() + MaxRecentListSize, myRecentBooks.end()); + } + BooksDB::Instance().saveRecentBooks(myRecentBooks); +} diff --git a/reader/src/library/Library.h b/reader/src/library/Library.h new file mode 100644 index 0000000..86eda4b --- /dev/null +++ b/reader/src/library/Library.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARY_H__ +#define __LIBRARY_H__ + +#include <string> +#include <vector> +#include <set> +#include <map> + +#include <shared_ptr.h> + +#include <ZLOptions.h> + +#include "Book.h" +#include "Author.h" +#include "Tag.h" +#include "Lists.h" + +class Library { + +public: + static Library &Instance(); + +private: + static shared_ptr<Library> ourInstance; + static const std::size_t MaxRecentListSize; + +public: + ZLStringOption PathOption; + ZLBooleanOption ScanSubdirsOption; + ZLBooleanOption CollectAllBooksOption; + +private: + Library(); + +public: + const AuthorList &authors() const; + const TagList &tags() const; + const BookList &books(shared_ptr<Author> author) const; + const BookList &books(shared_ptr<Tag> tag) const; + const BookList &recentBooks() const; + + enum RemoveType { + REMOVE_DONT_REMOVE = 0, + REMOVE_FROM_LIBRARY = 1, + REMOVE_FROM_DISK = 2, + REMOVE_FROM_LIBRARY_AND_DISK = REMOVE_FROM_LIBRARY | REMOVE_FROM_DISK + }; + + RemoveType canRemove(shared_ptr<Book> book) const; + + void collectSeriesTitles(shared_ptr<Author> author, std::set<std::string> &titles) const; + + std::size_t revision() const; + + void addBook(shared_ptr<Book> book); + void removeBook(shared_ptr<Book> book); + void updateBook(shared_ptr<Book> book); + void addBookToRecentList(shared_ptr<Book> book); + + void replaceAuthor(shared_ptr<Author> from, shared_ptr<Author> to); + + bool hasBooks(shared_ptr<Tag> tag) const; + bool hasSubtags(shared_ptr<Tag> tag) const; + void removeTag(shared_ptr<Tag> tag, bool includeSubTags); + void renameTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + void cloneTag(shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + +private: + void collectDirNames(std::set<std::string> &names) const; + void collectBookFileNames(std::set<std::string> &bookFileNames) const; + + void synchronize() const; + + void rebuildBookSet() const; + void rebuildMaps() const; + + void insertIntoBookSet(shared_ptr<Book> book) const; + +private: + mutable BookSet myBooks; + mutable BookSet myExternalBooks; + + mutable AuthorList myAuthors; + mutable TagList myTags; + typedef std::map<shared_ptr<Author>,BookList,AuthorComparator> BooksByAuthor; + mutable BooksByAuthor myBooksByAuthor; + typedef std::map<shared_ptr<Tag>,BookList,TagComparator> BooksByTag; + mutable BooksByTag myBooksByTag; + mutable BookList myRecentBooks; + + mutable std::string myPath; + mutable bool myScanSubdirs; + + enum BuildMode { + BUILD_NOTHING = 0, + BUILD_UPDATE_BOOKS_INFO = 1 << 0, + BUILD_COLLECT_FILES_INFO = 1 << 1, + BUILD_ALL = 0x03 + }; + mutable BuildMode myBuildMode; + mutable std::size_t myRevision; + +friend class LibrarySynchronizer; +friend class LibrarySynchronizerWrapper; +}; + +#endif /* __LIBRARY_H__ */ diff --git a/reader/src/library/Lists.h b/reader/src/library/Lists.h new file mode 100644 index 0000000..9768841 --- /dev/null +++ b/reader/src/library/Lists.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LISTS_H__ +#define __LISTS_H__ + +#include <vector> +#include <set> + +#include <shared_ptr.h> + +class Book; +class Author; +class Tag; +class BookByFileNameComparator; + +typedef std::vector<shared_ptr<Book> > BookList; +typedef std::set<shared_ptr<Book>,BookByFileNameComparator> BookSet; +typedef std::vector<shared_ptr<Author> > AuthorList; +typedef std::vector<shared_ptr<Tag> > TagList; +typedef std::set<shared_ptr<Tag> > TagSet; + +#endif /* __LISTS_H__ */ diff --git a/reader/src/library/Number.cpp b/reader/src/library/Number.cpp new file mode 100644 index 0000000..003104e --- /dev/null +++ b/reader/src/library/Number.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> + +#include "Number.h" + +static std::string ZERO = "0"; + +Number::Number() : myNumber(ZERO) { +} + +Number::Number(std::string number) : myNumber(validate(number)) { +} + +Number::Number(int number) { + ZLStringUtil::appendNumber(myNumber, number); +} + +std::string Number::validate(const std::string &value) { + std::string result = value; + while (result.size() > 1 && ZLStringUtil::stringStartsWith(result, ZERO)) { + result = result.substr(1); + } + return result; +} + +const std::string &Number::value() const { + return myNumber; +} + +void Number::setValue(const std::string &value) { + myNumber = validate(value); +} + +bool Number::operator <(const Number &number) const { + int index = std::strtol(myNumber.c_str(), 0, 10); + int otherIndex = std::strtol(number.value().c_str(), 0, 10); + return index < otherIndex; +} + +bool Number::operator ==(const Number &number) const { + int index = std::strtol(myNumber.c_str(), 0, 10); + int otherIndex = std::strtol(number.value().c_str(), 0, 10); + return index == otherIndex; +} diff --git a/reader/src/library/Number.h b/reader/src/library/Number.h new file mode 100644 index 0000000..858b4be --- /dev/null +++ b/reader/src/library/Number.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NUMBER_H__ +#define __NUMBER_H__ + +#include <string> + +class Number { +public: + Number(); + Number(std::string number); + Number(int number); + + static std::string validate(const std::string& value); + + const std::string &value() const; + void setValue(const std::string &value); + + //TODO implement validation + + bool operator< (const Number &number) const; + bool operator== (const Number &number) const; + +private: + std::string myNumber; +}; + +#endif /* __NUMBER_H__ */ diff --git a/reader/src/library/Tag.cpp b/reader/src/library/Tag.cpp new file mode 100644 index 0000000..c76db47 --- /dev/null +++ b/reader/src/library/Tag.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <set> +#include <algorithm> + +#include <ZLUnicodeUtil.h> + +#include "Tag.h" + +TagList Tag::ourRootTags; +std::map <int,shared_ptr<Tag> > Tag::ourTagsById; + +const std::string Tag::DELIMITER = "/"; + +shared_ptr<Tag> Tag::getTag(const std::string &name, shared_ptr<Tag> parent, int tagId) { + if (name.empty()) { + return 0; + } + TagList &tags = parent.isNull() ? ourRootTags : parent->myChildren; + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + if ((*it)->name() == name) { + return *it; + } + } + shared_ptr<Tag> t = new Tag(name, parent, tagId); + tags.push_back(t); + if (tagId > 0) { + ourTagsById[tagId] = t; + } + return t; +} + +shared_ptr<Tag> Tag::getTagByFullName(const std::string &fullName) { + std::string tag = fullName; + ZLUnicodeUtil::utf8Trim(tag); + std::size_t index = tag.rfind(DELIMITER); + if (index == std::string::npos) { + return getTag(tag); + } else { + std::string lastName = tag.substr(index + 1); + ZLUnicodeUtil::utf8Trim(lastName); + return getTag(lastName, getTagByFullName(tag.substr(0, index))); + } +} + +shared_ptr<Tag> Tag::getTagById(int tagId) { + std::map<int,shared_ptr<Tag> >::const_iterator it = ourTagsById.find(tagId); + return it != ourTagsById.end() ? it->second : 0; +} + +shared_ptr<Tag> Tag::cloneSubTag(shared_ptr<Tag> tag, shared_ptr<Tag> oldparent, shared_ptr<Tag> newparent) { + std::vector<std::string> levels; + + while (tag != oldparent) { + levels.push_back(tag->name()); + tag = tag->parent(); + if (tag.isNull()) { + return 0; + } + } + + if (levels.empty()) { + return 0; + } + + shared_ptr<Tag> res = newparent; + while (!levels.empty()) { + res = getTag(levels.back(), res); + levels.pop_back(); + } + return res; +} + +void Tag::collectAncestors(shared_ptr<Tag> tag, TagList &parents) { + for (; !tag.isNull(); tag = tag->parent()) { + parents.push_back(tag); + } + std::reverse(parents.begin(), parents.end()); +} + +void Tag::collectTagNames(std::vector<std::string> &tags) { + std::set<std::string> tagsSet; + TagList stack(ourRootTags); + while (!stack.empty()) { + shared_ptr<Tag> tag = stack.back(); + stack.pop_back(); + tagsSet.insert(tag->fullName()); + stack.insert(stack.end(), tag->myChildren.begin(), tag->myChildren.end()); + } + tags.insert(tags.end(), tagsSet.begin(), tagsSet.end()); +} + +Tag::Tag(const std::string &name, shared_ptr<Tag> parent, int tagId) : myName(name), myParent(parent), myLevel(parent.isNull() ? 0 : parent->level() + 1), myTagId(tagId) { +} + +const std::string &Tag::fullName() const { + if (myParent.isNull()) { + return myName; + } + if (myFullName.empty()) { + myFullName = myParent->fullName() + DELIMITER + myName; + } + return myFullName; +} + +bool Tag::isAncestorOf(shared_ptr<Tag> tag) const { + if (tag->level() <= level()) { + return false; + } + while (tag->level() > level()) { + tag = tag->parent(); + } + return &*tag == this; +} + +void Tag::setTagId(shared_ptr<Tag> tag, int tagId) { + if (tag.isNull() || tag->myTagId != 0) { + return; + } + tag->myTagId = tagId; + ourTagsById[tagId] = tag; +} diff --git a/reader/src/library/Tag.h b/reader/src/library/Tag.h new file mode 100644 index 0000000..0bd1f79 --- /dev/null +++ b/reader/src/library/Tag.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TAG_H__ +#define __TAG_H__ + +#include <string> +#include <map> + +#include <shared_ptr.h> + +#include "Lists.h" + +class Tag { + +private: + static TagList ourRootTags; + static std::map<int,shared_ptr<Tag> > ourTagsById; + +public: + static shared_ptr<Tag> getTag(const std::string &name, shared_ptr<Tag> parent = 0, int tagId = 0); + static shared_ptr<Tag> getTagByFullName(const std::string &fullName); + static shared_ptr<Tag> getTagById(int tagId); + + static void setTagId(shared_ptr<Tag>, int tagId); + + static shared_ptr<Tag> cloneSubTag(shared_ptr<Tag> tag, shared_ptr<Tag> oldparent, shared_ptr<Tag> newparent); + + static void collectAncestors(shared_ptr<Tag> tag, TagList &parents); + + static void collectTagNames(std::vector<std::string> &tags); + +private: + static const std::string DELIMITER; + +private: + Tag(const std::string &name, shared_ptr<Tag> parent, int tagId); + +public: + const std::string &fullName() const; + const std::string &name() const; + + shared_ptr<Tag> parent() const; + +public: + bool isAncestorOf(shared_ptr<Tag> tag) const; + + int tagId() const; + std::size_t level() const; + +private: + const std::string myName; + mutable std::string myFullName; + + shared_ptr<Tag> myParent; + TagList myChildren; + const std::size_t myLevel; + + int myTagId; + +private: // disable copying + Tag(const Tag &); + const Tag &operator = (const Tag &); +}; + +class TagComparator { + +public: + bool operator () ( + shared_ptr<Tag> tag0, + shared_ptr<Tag> tag1 + ) const; +}; + +inline const std::string &Tag::name() const { return myName; } + +inline shared_ptr<Tag> Tag::parent() const { return myParent; } + +inline int Tag::tagId() const { return myTagId; } +inline std::size_t Tag::level() const { return myLevel; } + +#endif /* __TAG_H__ */ diff --git a/reader/src/libraryActions/AuthorInfoDialog.cpp b/reader/src/libraryActions/AuthorInfoDialog.cpp new file mode 100644 index 0000000..fdc2252 --- /dev/null +++ b/reader/src/libraryActions/AuthorInfoDialog.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLDialogManager.h> +#include <ZLDialog.h> +#include <ZLOptionEntry.h> + +#include "AuthorInfoDialog.h" + +#include "../library/Library.h" +#include "../library/Author.h" + +class AuthorNameEntry : public ZLComboOptionEntry { + +public: + AuthorNameEntry(AuthorInfoDialog &dialog, std::size_t index); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + void onValueSelected(int index); + +public: + std::size_t Index; + +private: + AuthorInfoDialog &myInfoDialog; + mutable std::vector<std::string> myValues; + std::string myValue; +}; + +class AuthorSortKeyEntry : public ZLStringOptionEntry { +public: + AuthorSortKeyEntry(AuthorInfoDialog &dialog); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + AuthorInfoDialog &myInfoDialog; +}; + +AuthorNameEntry::AuthorNameEntry(AuthorInfoDialog &dialog, std::size_t index) : ZLComboOptionEntry(true), Index(index), myInfoDialog(dialog) { +} + +const std::string &AuthorNameEntry::initialValue() const { + return myInfoDialog.initialAuthor()->name(); +} + +void AuthorNameEntry::onAccept(const std::string &value) { + myInfoDialog.name() = value; +} + +const std::vector<std::string> &AuthorNameEntry::values() const { + if (myValues.empty()) { + const AuthorList &authors = myInfoDialog.authors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + myValues.push_back((*it)->name()); + } + } + return myValues; +} + +void AuthorNameEntry::onValueSelected(int index) { + Index = index; + myInfoDialog.sortKeyEntry().resetView(); +} + +AuthorSortKeyEntry::AuthorSortKeyEntry(AuthorInfoDialog &dialog) : myInfoDialog(dialog) { +} + +const std::string &AuthorSortKeyEntry::initialValue() const { + const AuthorList &authors = myInfoDialog.authors(); + std::size_t index = std::min(myInfoDialog.nameEntry().Index, authors.size() - 1); + return authors[index]->sortKey(); +} + +void AuthorSortKeyEntry::onAccept(const std::string &value) { + myInfoDialog.sortKey() = value; +} + + + +bool AuthorInfoDialog::run(shared_ptr<Author> author) { + AuthorInfoDialog dlg(author); + if (dlg.dialog().run()) { + dlg.dialog().acceptValues(); + shared_ptr<Author> newAuthor = Author::getAuthor(dlg.name(), dlg.sortKey()); + Library::Instance().replaceAuthor(author, newAuthor); + return true; + } + return false; +} + + +AuthorInfoDialog::AuthorInfoDialog(shared_ptr<Author> author) : myInitialAuthor(author) { + const AuthorList &authors = Library::Instance().authors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (!it->isNull()) { + myAuthors.push_back(*it); + } + } + AuthorList::iterator jt = std::lower_bound(myAuthors.begin(), myAuthors.end(), myInitialAuthor, AuthorComparator()); + if (jt == myAuthors.end() || *jt != myInitialAuthor) { + myAuthors.insert(jt, myInitialAuthor); + } + + myDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("AuthorInfoDialog")); + + myNameEntry = new AuthorNameEntry(*this, jt - myAuthors.begin()); + mySortKeyEntry = new AuthorSortKeyEntry(*this); + + myDialog->addOption(ZLResourceKey("name"), myNameEntry); + myDialog->addOption(ZLResourceKey("sortKey"), mySortKeyEntry); + + myDialog->addButton(ZLDialogManager::OK_BUTTON, true); + myDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); +} + +ZLDialog &AuthorInfoDialog::dialog() { + return *myDialog; +} + +shared_ptr<Author> AuthorInfoDialog::initialAuthor() { + return myInitialAuthor; +} + +const AuthorList &AuthorInfoDialog::authors() const { + return myAuthors; +} + +std::string &AuthorInfoDialog::name() { + return myName; +} + +std::string &AuthorInfoDialog::sortKey() { + return mySortKey; +} + +AuthorNameEntry &AuthorInfoDialog::nameEntry() { + return *myNameEntry; +} + +AuthorSortKeyEntry &AuthorInfoDialog::sortKeyEntry() { + return *mySortKeyEntry; +} diff --git a/reader/src/libraryActions/AuthorInfoDialog.h b/reader/src/libraryActions/AuthorInfoDialog.h new file mode 100644 index 0000000..e4194aa --- /dev/null +++ b/reader/src/libraryActions/AuthorInfoDialog.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __AUTHORINFODIALOG_H__ +#define __AUTHORINFODIALOG_H__ + +#include <string> + +#include "../library/Lists.h" + +class ZLDialog; +class AuthorNameEntry; +class AuthorSortKeyEntry; + +class AuthorInfoDialog { + +public: + static bool run(shared_ptr<Author> author); + +private: + AuthorInfoDialog(shared_ptr<Author> author); + + ZLDialog &dialog(); + +public: + shared_ptr<Author> initialAuthor(); + const AuthorList &authors() const; + + std::string &name(); + std::string &sortKey(); + + AuthorNameEntry &nameEntry(); + AuthorSortKeyEntry &sortKeyEntry(); + +private: + const shared_ptr<Author> myInitialAuthor; + AuthorList myAuthors; + + shared_ptr<ZLDialog> myDialog; + + AuthorNameEntry *myNameEntry; + AuthorSortKeyEntry *mySortKeyEntry; + + std::string myName; + std::string mySortKey; +}; + +#endif /* __AUTHORINFODIALOG_H__ */ diff --git a/reader/src/libraryActions/BooksUtil.cpp b/reader/src/libraryActions/BooksUtil.cpp new file mode 100644 index 0000000..93f9f06 --- /dev/null +++ b/reader/src/libraryActions/BooksUtil.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLStringUtil.h> + +#include "BooksUtil.h" + +#include "../library/Library.h" +#include "../library/Tag.h" +#include "../reader/Reader.h" + +void BooksUtil::removeTag(shared_ptr<Tag> tag) { + ZLResourceKey boxKey("removeTagBox"); + const std::string message = + ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), tag->fullName()); + enum { REMOVE_TAG, REMOVE_SUBTREE, DONT_REMOVE } code = DONT_REMOVE; + + Library &library = Library::Instance(); + if (library.hasSubtags(tag)) { + if (library.hasBooks(tag)) { + switch (ZLDialogManager::Instance().questionBox(boxKey, message, + ZLResourceKey("thisOnly"), + ZLResourceKey("withSubtags"), + ZLDialogManager::CANCEL_BUTTON + )) { + case 0: + code = REMOVE_TAG; + break; + case 1: + code = REMOVE_SUBTREE; + break; + } + } else { + if (ZLDialogManager::Instance().questionBox(boxKey, message, + ZLResourceKey("withSubtags"), ZLDialogManager::CANCEL_BUTTON) == 0) { + code = REMOVE_SUBTREE; + } + } + } else { + if (ZLDialogManager::Instance().questionBox(boxKey, message, + ZLDialogManager::YES_BUTTON, ZLDialogManager::CANCEL_BUTTON) == 0) { + code = REMOVE_TAG; + } + } + if (code != DONT_REMOVE) { + library.removeTag(tag, code == REMOVE_SUBTREE); + // TODO: select current node (?) again + Reader::Instance().refreshWindow(); + } +} + +void BooksUtil::collectTagsFromLibrary(TagList &tags) { + const TagList &lTags = Library::Instance().tags(); + TagSet tagSet; + + for (TagList::const_iterator it = lTags.begin(); it != lTags.end(); ++it) { + shared_ptr<Tag> tag = *it; + if (tag.isNull()) { + tagSet.insert(tag); + tags.push_back(tag); + } else { + TagList tagStack; + do { + tagStack.push_back(tag); + tag = tag->parent(); + } while (!tag.isNull() && tagSet.find(tag) == tagSet.end()); + tagSet.insert(tagStack.begin(), tagStack.end()); + tags.insert(tags.end(), tagStack.rbegin(), tagStack.rend()); + } + } +} diff --git a/reader/src/libraryActions/BooksUtil.h b/reader/src/libraryActions/BooksUtil.h new file mode 100644 index 0000000..b12c8e8 --- /dev/null +++ b/reader/src/libraryActions/BooksUtil.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKSUTIL_H__ +#define __BOOKSUTIL_H__ + +#include <shared_ptr.h> + +#include "../library/Lists.h" + +class Tag; + +class BooksUtil { + +public: + static void removeTag(shared_ptr<Tag> tag); + static void collectTagsFromLibrary(TagList &tags); + +private: + BooksUtil(); +}; + +#endif /* __BOOKSUTIL_H__ */ diff --git a/reader/src/libraryActions/LibraryAuthorActions.cpp b/reader/src/libraryActions/LibraryAuthorActions.cpp new file mode 100644 index 0000000..5f4363d --- /dev/null +++ b/reader/src/libraryActions/LibraryAuthorActions.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LibraryAuthorActions.h" +#include "AuthorInfoDialog.h" + +#include "../library/Author.h" +#include "../reader/Reader.h" + +AuthorEditInfoAction::AuthorEditInfoAction(shared_ptr<Author> author) : myAuthor(author) { +} + +AuthorEditInfoAction::~AuthorEditInfoAction() { +} + +void AuthorEditInfoAction::run() { + if (AuthorInfoDialog::run(myAuthor)) { + // TODO: select current node (?) again + Reader::Instance().refreshWindow(); + } +} + +ZLResourceKey AuthorEditInfoAction::key() const { + return ZLResourceKey("edit"); +} diff --git a/reader/src/libraryActions/LibraryAuthorActions.h b/reader/src/libraryActions/LibraryAuthorActions.h new file mode 100644 index 0000000..2fddb7a --- /dev/null +++ b/reader/src/libraryActions/LibraryAuthorActions.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYAUTHORACTIONS_H__ +#define __LIBRARYAUTHORACTIONS_H__ + +#include <shared_ptr.h> + +#include <ZLRunnable.h> + +class Author; + +class AuthorEditInfoAction : public ZLRunnableWithKey { + +public: + AuthorEditInfoAction(shared_ptr<Author> author); + ~AuthorEditInfoAction(); + void run(); + ZLResourceKey key() const; + +private: + const shared_ptr<Author> myAuthor; +}; + +#endif /* __LIBRARYAUTHORACTIONS_H__ */ diff --git a/reader/src/libraryActions/LibraryBookActions.cpp b/reader/src/libraryActions/LibraryBookActions.cpp new file mode 100644 index 0000000..0c490c4 --- /dev/null +++ b/reader/src/libraryActions/LibraryBookActions.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> + +#include "LibraryBookActions.h" +#include "../library/Book.h" +#include "../reader/Reader.h" +#include "../optionsDialog/bookInfo/BookInfoDialog.h" + +BookReadAction::BookReadAction(shared_ptr<Book> book) : myBook(book) { +} + +void BookReadAction::run() { + Reader &reader = Reader::Instance(); + reader.openBook(myBook); + reader.showBookTextView(); +} + +ZLResourceKey BookReadAction::key() const { + return ZLResourceKey("read"); +} + +BookRemoveAction::BookRemoveAction(shared_ptr<Book> book) : myBook(book) { +} + +void BookRemoveAction::run() { + switch (removeBookDialog()) { + case Library::REMOVE_FROM_DISK: + { + const std::string path = myBook->file().physicalFilePath(); + ZLFile physicalFile(path); + if (!physicalFile.remove()) { + ZLResourceKey boxKey("removeFileErrorBox"); + const std::string message = + ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), path); + ZLDialogManager::Instance().errorBox(boxKey, message); + } + } + // yes, we go through this label + case Library::REMOVE_FROM_LIBRARY: + Library::Instance().removeBook(myBook); + Reader::Instance().refreshWindow(); + case Library::REMOVE_DONT_REMOVE: + break; + } +} + +ZLResourceKey BookRemoveAction::key() const { + return ZLResourceKey("delete"); +} + +bool BookRemoveAction::makesSense() const { + return Library::Instance().canRemove(myBook) != Library::REMOVE_DONT_REMOVE; +} + +int BookRemoveAction::removeBookDialog() const { + ZLResourceKey boxKey("removeBookBox"); + const ZLResource &msgResource = ZLResource::resource("dialog")[boxKey]; + + switch (Library::Instance().canRemove(myBook)) { + case Library::REMOVE_DONT_REMOVE: + return Library::REMOVE_DONT_REMOVE; + case Library::REMOVE_FROM_DISK: + { + ZLFile physFile(myBook->file().physicalFilePath()); + const std::string message = ZLStringUtil::printf(msgResource["deleteFile"].value(), physFile.name(false)); + if (ZLDialogManager::Instance().questionBox(boxKey, message, ZLDialogManager::YES_BUTTON, ZLDialogManager::NO_BUTTON) == 0) { + return Library::REMOVE_FROM_DISK; + } + return Library::REMOVE_DONT_REMOVE; + } + case Library::REMOVE_FROM_LIBRARY: + { + const std::string message = ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), myBook->title()); + if (ZLDialogManager::Instance().questionBox(boxKey, message, ZLDialogManager::YES_BUTTON, ZLDialogManager::NO_BUTTON) == 0) { + return Library::REMOVE_FROM_LIBRARY; + } + return Library::REMOVE_DONT_REMOVE; + } + case Library::REMOVE_FROM_LIBRARY_AND_DISK: + { + ZLResourceKey removeFileKey("removeFile"); + ZLResourceKey removeLinkKey("removeLink"); + + const std::string message = ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), myBook->title()); + switch(ZLDialogManager::Instance().questionBox(boxKey, message, removeLinkKey, removeFileKey, ZLDialogManager::CANCEL_BUTTON)) { + case 0: + return Library::REMOVE_FROM_LIBRARY; + case 1: + return Library::REMOVE_FROM_DISK; + case 2: + return Library::REMOVE_DONT_REMOVE; + } + } + } + return Library::REMOVE_DONT_REMOVE; +} + +BookEditInfoAction::BookEditInfoAction(shared_ptr<Book> book) : myBook(book) { +} + +void BookEditInfoAction::run() { + if (BookInfoDialog(myBook).dialog().run()) { + // TODO: select current node (?) again + Reader::Instance().refreshWindow(); + } +} + +ZLResourceKey BookEditInfoAction::key() const { + return ZLResourceKey("edit"); +} diff --git a/reader/src/libraryActions/LibraryBookActions.h b/reader/src/libraryActions/LibraryBookActions.h new file mode 100644 index 0000000..873fbb7 --- /dev/null +++ b/reader/src/libraryActions/LibraryBookActions.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYBOOKACTIONS_H__ +#define __LIBRARYBOOKACTIONS_H__ + +#include <shared_ptr.h> + +#include <ZLRunnable.h> + +class Book; + +class BookReadAction : public ZLRunnableWithKey { + +public: + BookReadAction(shared_ptr<Book> book); + void run(); + ZLResourceKey key() const; + +private: + const shared_ptr<Book> myBook; +}; + +class BookEditInfoAction : public ZLRunnableWithKey { + +public: + BookEditInfoAction(shared_ptr<Book> book); + void run(); + ZLResourceKey key() const; + +private: + const shared_ptr<Book> myBook; +}; + +class BookRemoveAction : public ZLRunnableWithKey { + +public: + BookRemoveAction(shared_ptr<Book> book); + +private: + void run(); + ZLResourceKey key() const; + bool makesSense() const; + + int removeBookDialog() const; + +private: + const shared_ptr<Book> myBook; +}; + +#endif /* __LIBRARYBOOKACTIONS_H__ */ diff --git a/reader/src/libraryActions/LibraryTagActions.cpp b/reader/src/libraryActions/LibraryTagActions.cpp new file mode 100644 index 0000000..0fe945e --- /dev/null +++ b/reader/src/libraryActions/LibraryTagActions.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLDialogManager.h> +#include <ZLDialog.h> +#include <ZLOptionEntry.h> + +#include "LibraryTagActions.h" + +#include "BooksUtil.h" + +#include "../library/Library.h" +#include "../library/Tag.h" +#include "../library/Lists.h" + +class TagNameEntry : public ZLComboOptionEntry { + +public: + TagNameEntry(const std::vector<std::string> &values, const std::string &initialValue); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + +private: + const std::vector<std::string> &myValues; + std::string myValue; +}; + +class TagIncludeSubtagsEntry : public ZLBooleanOptionEntry { + +public: + TagIncludeSubtagsEntry(); + + bool initialState() const; + void onAccept(bool state); + +private: + bool myValue; +}; + +TagEditOrCloneAction::TagEditOrCloneAction(shared_ptr<Tag> tag) : myTag(tag) { +} + +void TagEditOrCloneAction::run() { + shared_ptr<ZLDialog> dialog = ZLDialogManager::Instance().createDialog(ZLResourceKey(resourceKeyName())); + + TagList tags; + BooksUtil::collectTagsFromLibrary(tags); + std::vector<std::string> names; + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + if (!it->isNull()) { + names.push_back((*it)->fullName()); + } + } + TagNameEntry *tagNameEntry = new TagNameEntry(names, myTag->fullName()); + dialog->addOption(ZLResourceKey("name"), tagNameEntry); + + TagIncludeSubtagsEntry *includeSubtagsEntry = new TagIncludeSubtagsEntry(); + const Library &library = Library::Instance(); + if (library.hasSubtags(myTag)) { + if (!library.hasBooks(myTag)) { + includeSubtagsEntry->setActive(false); + } + dialog->addOption(ZLResourceKey("includeSubtags"), includeSubtagsEntry); + } + + dialog->addButton(ZLDialogManager::OK_BUTTON, true); + dialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); + + if (dialog->run()) { + dialog->acceptValues(); + onAccept(tagNameEntry->initialValue(), includeSubtagsEntry->initialState()); + } +} + +TagEditAction::TagEditAction(shared_ptr<Tag> tag) : TagEditOrCloneAction(tag) { +} + +void TagEditAction::onAccept(const std::string &name, bool includeSubTags) { + Library::Instance().renameTag(myTag, Tag::getTagByFullName(name), includeSubTags); +} + +ZLResourceKey TagEditAction::key() const { + return ZLResourceKey("edit"); +} + +std::string TagEditAction::resourceKeyName() const { + return "editTagDialog"; +} + +TagCloneAction::TagCloneAction(shared_ptr<Tag> tag) : TagEditOrCloneAction(tag) { +} + +void TagCloneAction::onAccept(const std::string &name, bool includeSubTags) { + Library::Instance().cloneTag(myTag, Tag::getTagByFullName(name), includeSubTags); +} + +ZLResourceKey TagCloneAction::key() const { + return ZLResourceKey("clone"); +} + +std::string TagCloneAction::resourceKeyName() const { + return "cloneTagDialog"; +} + +TagRemoveAction::TagRemoveAction(shared_ptr<Tag> tag) : myTag(tag) { +} + +void TagRemoveAction::run() { + BooksUtil::removeTag(myTag); +} + +ZLResourceKey TagRemoveAction::key() const { + return ZLResourceKey("delete"); +} + +TagNameEntry::TagNameEntry(const std::vector<std::string> &values, const std::string &initialValue) : ZLComboOptionEntry(true), myValues(values), myValue(initialValue) { +} + +const std::string &TagNameEntry::initialValue() const { + return myValue; +} + +const std::vector<std::string> &TagNameEntry::values() const { + return myValues; +} + +void TagNameEntry::onAccept(const std::string &value) { + myValue = value; +} + +TagIncludeSubtagsEntry::TagIncludeSubtagsEntry() : myValue(true) { +} + +bool TagIncludeSubtagsEntry::initialState() const { + return myValue; +} + +void TagIncludeSubtagsEntry::onAccept(bool state) { + myValue = state; +} diff --git a/reader/src/libraryActions/LibraryTagActions.h b/reader/src/libraryActions/LibraryTagActions.h new file mode 100644 index 0000000..de9d6a9 --- /dev/null +++ b/reader/src/libraryActions/LibraryTagActions.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYTAGACTIONS_H__ +#define __LIBRARYTAGACTIONS_H__ + +#include <shared_ptr.h> + +#include <ZLRunnable.h> + +class Tag; + +class TagEditOrCloneAction : public ZLRunnableWithKey { + +public: + TagEditOrCloneAction(shared_ptr<Tag> tag); + +private: + void run(); + +protected: + virtual void onAccept(const std::string &name, bool includeSubTags) = 0; + virtual std::string resourceKeyName() const = 0; + +protected: + const shared_ptr<Tag> myTag; +}; + +class TagEditAction : public TagEditOrCloneAction { + +public: + TagEditAction(shared_ptr<Tag> tag); + +private: + ZLResourceKey key() const; + void onAccept(const std::string &name, bool includeSubTags); + std::string resourceKeyName() const; +}; + +class TagCloneAction : public TagEditOrCloneAction { + +public: + TagCloneAction(shared_ptr<Tag> tag); + +private: + ZLResourceKey key() const; + void onAccept(const std::string &name, bool includeSubTags); + std::string resourceKeyName() const; +}; + +class TagRemoveAction : public ZLRunnableWithKey { + +public: + TagRemoveAction(shared_ptr<Tag> tag); + +private: + void run(); + ZLResourceKey key() const; + +private: + const shared_ptr<Tag> myTag; +}; + +#endif /* __LIBRARYTAGACTIONS_H__ */ diff --git a/reader/src/libraryTree/AuthorNode.cpp b/reader/src/libraryTree/AuthorNode.cpp new file mode 100644 index 0000000..a22970f --- /dev/null +++ b/reader/src/libraryTree/AuthorNode.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLImage.h> +#include <ZLOptionsDialog.h> + +#include "LibraryNodes.h" + +#include "../library/Author.h" +#include "../libraryActions/LibraryAuthorActions.h" + +const ZLTypeId AuthorNode::TYPE_ID(ReaderNode::TYPE_ID); + +const ZLResource &AuthorNode::resource() const { + return ZLResource::resource("libraryView")["authorNode"]; +} + +const ZLTypeId &AuthorNode::typeId() const { + return TYPE_ID; +} + +AuthorNode::AuthorNode(ZLBlockTreeView::RootNode *parent, std::size_t atPosition, shared_ptr<Author> author) : ReaderNode(parent, atPosition), myAuthor(author) { +} + +void AuthorNode::init() { + registerExpandTreeAction(); + if (!myAuthor.isNull()) { + registerAction(new AuthorEditInfoAction(myAuthor)); + } +} + +shared_ptr<Author> AuthorNode::author() const { + return myAuthor; +} + +std::string AuthorNode::title() const { + return myAuthor.isNull() ? + resource()["unknownAuthor"].value() : myAuthor->name(); +} + +shared_ptr<const ZLImage> AuthorNode::extractCoverImage() const { + return defaultCoverImage("booktree-author.png"); +} diff --git a/reader/src/libraryTree/BookNode.cpp b/reader/src/libraryTree/BookNode.cpp new file mode 100644 index 0000000..8ef323d --- /dev/null +++ b/reader/src/libraryTree/BookNode.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLImage.h> + +#include "LibraryNodes.h" + +#include "../library/Book.h" +#include "../library/Author.h" +#include "../library/Tag.h" +#include "../libraryActions/LibraryBookActions.h" + +#include "../reader/Reader.h" +#include "../formats/FormatPlugin.h" + +const ZLTypeId BookNode::TYPE_ID(ReaderNode::TYPE_ID); + +const ZLTypeId &BookNode::typeId() const { + return TYPE_ID; +} + +const ZLResource &BookNode::resource() const { + return ZLResource::resource("libraryView")["bookNode"]; +} + +BookNode::BookNode(AuthorNode *parent, shared_ptr<Book> book) : ReaderNode(parent), myBook(book) { +} + +BookNode::BookNode(SeriesNode *parent, shared_ptr<Book> book) : ReaderNode(parent), myBook(book) { +} + +BookNode::BookNode(TagNode *parent, std::size_t atPosition, shared_ptr<Book> book) : ReaderNode(parent, atPosition), myBook(book) { +} + +void BookNode::init() { + registerAction(new BookReadAction(myBook)); + registerAction(new BookEditInfoAction(myBook)); + registerAction(new BookRemoveAction(myBook)); +} + +shared_ptr<Book> BookNode::book() const { + return myBook; +} + +std::string BookNode::title() const { + return myBook->title(); +} + +std::string BookNode::summary() const { + ReaderNode *parent = (ReaderNode*)this->parent(); + while (!parent->isInstanceOf(AuthorNode::TYPE_ID) && + !parent->isInstanceOf(TagNode::TYPE_ID)) { + parent = (ReaderNode*)parent->parent(); + } + if (parent->isInstanceOf(AuthorNode::TYPE_ID)) { + const TagList &tags = myBook->tags(); + if (tags.empty()) { + return std::string(); + } else { + std::string tagsText; + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + if (!tagsText.empty()) { + tagsText += ", "; + } + tagsText += (*it)->name(); + } + return tagsText; + } + } else { + const AuthorList &authors = myBook->authors(); + if (authors.empty()) { + return ZLResource::resource("libraryView")["authorNode"]["unknownAuthor"].value(); + } else { + std::string authorsText; + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (!authorsText.empty()) { + authorsText += ", "; + } + authorsText += (*it)->name(); + } + return authorsText; + } + } +} + +bool BookNode::highlighted() const { + return myBook->file() == Reader::Instance().currentBook()->file(); +} + +shared_ptr<const ZLImage> BookNode::extractCoverImage() const { + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(*myBook); + if (!plugin.isNull()) { + shared_ptr<const ZLImage> cover = plugin->coverImage(myBook->file()); + if (!cover.isNull()) { + return cover; + } + } + return defaultCoverImage("booktree-book.png"); +} diff --git a/reader/src/libraryTree/LibraryByAuthorView.cpp b/reader/src/libraryTree/LibraryByAuthorView.cpp new file mode 100644 index 0000000..4b0bb56 --- /dev/null +++ b/reader/src/libraryTree/LibraryByAuthorView.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LibraryView.h" +#include "LibraryNodes.h" + +#include "../library/Library.h" +#include "../library/Book.h" +#include "../library/Author.h" + +LibraryByAuthorView::LibraryByAuthorView(ZLPaintContext &context) : LibraryView(context) { +} + +void LibraryByAuthorView::addAuthorSubtree(shared_ptr<Author> author, std::size_t atPosition) { + static const std::set<shared_ptr<Book> > emptySet; + fillAuthorSubtree(new AuthorNode(&rootNode(), atPosition, author), emptySet); +} + +void LibraryByAuthorView::fillAuthorSubtree(AuthorNode *authorNode, const std::set<shared_ptr<Book> > &visibleBooks) { + const BookList &books = Library::Instance().books(authorNode->author()); + SeriesNode *seriesNode = 0; + for (BookList::const_iterator it = books.begin(); it != books.end(); ++it) { + std::string series = (*it)->seriesTitle(); + + if (!series.empty() && (seriesNode == 0 || seriesNode->book()->seriesTitle() != series)) { + BookList::const_iterator jt = it + 1; + if (jt == books.end() || (*jt)->seriesTitle() != series) { + series.clear(); + } + } + + if (series.empty()) { + seriesNode = 0; + new BookNode(authorNode, *it); + } else { + if (seriesNode == 0 || seriesNode->book()->seriesTitle() != series) { + seriesNode = new SeriesNode(authorNode); + } + new BookNode(seriesNode, *it); + if (visibleBooks.find(*it) != visibleBooks.end()) { + seriesNode->open(true); + } + } + } +} + +bool LibraryByAuthorView::isSubtreeUpToDate(AuthorNode *authorNode) { + const BookList &books = Library::Instance().books(authorNode->author()); + BookList::const_iterator it = books.begin(); + + const ZLBlockTreeNode::List &nodes = authorNode->children(); + for (ZLBlockTreeNode::List::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt) { + ReaderNode &node = *(ReaderNode*)*nIt; + if (node.isInstanceOf(BookNode::TYPE_ID)) { + shared_ptr<Book> book = ((BookNode&)node).book(); + if (it == books.end() || *it != book || !book->seriesTitle().empty()) { + return false; + } + ++it; + } else /* if (node.isInstanceOf(SeriesNode::TYPE_ID)) */ { + const ZLBlockTreeNode::List &bNodes = node.children(); + for (ZLBlockTreeNode::List::const_iterator bookIt = bNodes.begin(); bookIt != bNodes.end(); ++bookIt) { + shared_ptr<Book> book = ((BookNode*)*bookIt)->book(); + if (it == books.end() || *it != book || book->seriesTitle().empty()) { + return false; + } + ++it; + } + } + } + return it == books.end(); +} + +void LibraryByAuthorView::updateAuthorSubtree(AuthorNode *authorNode) { + std::set<shared_ptr<Book> > visibleBooks; + + const ZLBlockTreeNode::List &nodes = authorNode->children(); + for (ZLBlockTreeNode::List::const_iterator nIt = nodes.begin(); nIt != nodes.end(); ++nIt) { + ReaderNode &node = *(ReaderNode*)*nIt; + if (node.isInstanceOf(BookNode::TYPE_ID)) { + visibleBooks.insert(((BookNode&)node).book()); + } else if (node.isOpen()) { + const ZLBlockTreeNode::List &bNodes = node.children(); + for (ZLBlockTreeNode::List::const_iterator bookIt = bNodes.begin(); bookIt != bNodes.end(); ++bookIt) { + visibleBooks.insert(((BookNode*)*bookIt)->book()); + } + } + } + + authorNode->clear(); + fillAuthorSubtree(authorNode, visibleBooks); +} + +void LibraryByAuthorView::makeUpToDate() { + ZLBlockTreeNode *topNode = firstVisibleNode(); + AuthorNode *topAuthorNode = 0; + if (topNode != &rootNode()) { + ReaderNode *lNode = (ReaderNode*)topNode; + while (!lNode->isInstanceOf(AuthorNode::TYPE_ID)) { + lNode = (ReaderNode*)lNode->parent(); + } + topAuthorNode = (AuthorNode*)lNode; + } + + bool topAuthorNodeIsUpdated = false; + const AuthorList &authors = Library::Instance().authors(); + std::set<ZLBlockTreeNode*> nodesToDelete; + ZLBlockTreeNode::List rootChildren = rootNode().children(); + AuthorComparator comparator; + + ZLBlockTreeNode::List::iterator nodeIt = rootChildren.begin(); + std::size_t nodeCount = 0; + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + bool processed = false; + while (nodeIt != rootChildren.end()) { + AuthorNode *authorNode = (AuthorNode*)*nodeIt; + if (authorNode->author() == *it) { + if (!isSubtreeUpToDate(authorNode)) { + updateAuthorSubtree(authorNode); + if (authorNode == topAuthorNode) { + topAuthorNodeIsUpdated = true; + } + } + ++nodeIt; + ++nodeCount; + processed = true; + break; + } else if (comparator(authorNode->author(), *it)) { + nodesToDelete.insert(*nodeIt); + ++nodeIt; + ++nodeCount; + } else { + break; + } + } + if (!processed) { + addAuthorSubtree(*it, nodeCount); + ++nodeCount; + } + } + + nodesToDelete.insert(nodeIt, rootChildren.end()); + + if (topAuthorNodeIsUpdated) { + setFirstVisibleNode(topAuthorNode); + } else if (nodesToDelete.find(topAuthorNode) != nodesToDelete.end()) { + ZLBlockTreeNode *visible = topAuthorNode->previous(); + while (nodesToDelete.find(visible) != nodesToDelete.end()) { + visible = visible->previous(); + } + setFirstVisibleNode(visible); + } + + for (std::set<ZLBlockTreeNode*>::iterator it = nodesToDelete.begin(); it != nodesToDelete.end(); ++it) { + delete *it; + } +} diff --git a/reader/src/libraryTree/LibraryByTagView.cpp b/reader/src/libraryTree/LibraryByTagView.cpp new file mode 100644 index 0000000..76913f1 --- /dev/null +++ b/reader/src/libraryTree/LibraryByTagView.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LibraryView.h" +#include "LibraryNodes.h" + +#include "../library/Library.h" +#include "../library/Book.h" +#include "../library/Tag.h" +#include "../libraryActions/BooksUtil.h" + +LibraryByTagView::LibraryByTagView(ZLPaintContext &context) : LibraryView(context) { +} + +void LibraryByTagView::collectTagNodes(const ZLBlockTreeNode &root, std::map<shared_ptr<Tag>,TagNode*,TagComparator> &nodeMap) { + const ZLBlockTreeNode::List &children = root.children(); + for (ZLBlockTreeNode::List::const_iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->isInstanceOf(TagNode::TYPE_ID)) { + TagNode *tagNode = (TagNode*)*it; + nodeMap[tagNode->tag()] = tagNode; + collectTagNodes(*tagNode, nodeMap); + } + } +} + +void LibraryByTagView::updateBookList(TagNode *tagNode) { + const BookList &books = Library::Instance().books(tagNode->tag()); + const ZLBlockTreeNode::List &subNodes = tagNode->children(); + BookList::const_iterator jt = books.begin(); + ZLBlockTreeNode::List::const_iterator kt = subNodes.begin(); + for (; jt != books.end() && kt != subNodes.end(); ++jt, ++kt) { + if (!(*kt)->isInstanceOf(BookNode::TYPE_ID)) { + break; + } + if (((BookNode*)(*kt))->book()->file() != (*jt)->file()) { + break; + } + } + + std::size_t index = jt - books.begin(); + while (tagNode->children().size() > index) { + ZLBlockTreeNode *bookNode = tagNode->children()[index]; + if (!bookNode->isInstanceOf(BookNode::TYPE_ID)) { + break; + } + delete bookNode; + } + + for (; jt != books.end(); ++jt) { + new BookNode(tagNode, index++, *jt); + } +} + +void LibraryByTagView::makeUpToDate() { + TagList tags; + BooksUtil::collectTagsFromLibrary(tags); + + std::map<shared_ptr<Tag>,TagNode*,TagComparator> nodeMap; + collectTagNodes(rootNode(), nodeMap); + + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + shared_ptr<Tag> tag = *it; + TagNode *tagNode = nodeMap[tag]; + if (tagNode == 0) { + tagNode = + (tag.isNull() || tag->parent().isNull()) ? + new TagNode(&rootNode(), tag) : + new TagNode(nodeMap[tag->parent()], tag); + nodeMap[tag] = tagNode; + } + updateBookList(tagNode); + } + + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + nodeMap.erase(nodeMap.find(*it)); + } + + for (std::map<shared_ptr<Tag>,TagNode*,TagComparator>::reverse_iterator it = nodeMap.rbegin(); it != nodeMap.rend(); ++it) { + delete it->second; + } +} diff --git a/reader/src/libraryTree/LibraryNodes.h b/reader/src/libraryTree/LibraryNodes.h new file mode 100644 index 0000000..fbd9fa3 --- /dev/null +++ b/reader/src/libraryTree/LibraryNodes.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYNODES_H__ +#define __LIBRARYNODES_H__ + +#include "../blockTree/ReaderNode.h" + +class ZLImage; + +class Author; +class Book; +class Tag; + +class AuthorNode : public ReaderNode { + +public: + static const ZLTypeId TYPE_ID; + +public: + AuthorNode(ZLBlockTreeView::RootNode *parent, std::size_t atPosition, shared_ptr<Author> author); + void init(); + + shared_ptr<Author> author() const; + +private: + const ZLResource &resource() const; + const ZLTypeId &typeId() const; + shared_ptr<const ZLImage> extractCoverImage() const; + std::string title() const; + +private: + shared_ptr<Author> myAuthor; +}; + +class SeriesNode : public ReaderNode { + +public: + static const ZLTypeId TYPE_ID; + +public: + SeriesNode(AuthorNode *parent); + void init(); + + shared_ptr<Book> book() const; + +private: + const ZLResource &resource() const; + const ZLTypeId &typeId() const; + shared_ptr<const ZLImage> extractCoverImage() const; + std::string title() const; +}; + +class TagNode : public ReaderNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + static std::size_t positionToInsert(ZLBlockTreeNode *parent, shared_ptr<Tag> tag); + +public: + TagNode(ZLBlockTreeView::RootNode *parent, shared_ptr<Tag> tag); + TagNode(TagNode *parent, shared_ptr<Tag> tag); + void init(); + + shared_ptr<Tag> tag() const; + +private: + const ZLResource &resource() const; + const ZLTypeId &typeId() const; + shared_ptr<const ZLImage> extractCoverImage() const; + std::string title() const; + +private: + const shared_ptr<Tag> myTag; +}; + +class BookNode : public ReaderNode { + +public: + static const ZLTypeId TYPE_ID; + +public: + BookNode(AuthorNode *parent, shared_ptr<Book> book); + BookNode(SeriesNode *parent, shared_ptr<Book> book); + BookNode(TagNode *parent, std::size_t atPosition, shared_ptr<Book> book); + + shared_ptr<Book> book() const; + +private: + void init(); + bool highlighted() const; + const ZLResource &resource() const; + const ZLTypeId &typeId() const; + shared_ptr<const ZLImage> extractCoverImage() const; + std::string title() const; + std::string summary() const; + +private: + const shared_ptr<Book> myBook; +}; + +#endif /* __LIBRARYNODES_H__ */ diff --git a/reader/src/libraryTree/LibraryView.cpp b/reader/src/libraryTree/LibraryView.cpp new file mode 100644 index 0000000..067c865 --- /dev/null +++ b/reader/src/libraryTree/LibraryView.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <queue> + +#include <ZLResource.h> + +#include "LibraryView.h" +#include "LibraryNodes.h" + +#include "../library/Library.h" +#include "../library/Book.h" +#include "../options/FBOptions.h" + +LibraryView::LibraryView(ZLPaintContext &context) : ZLBlockTreeView(context), myCollectionRevision(0) { +} + +void LibraryView::paint() { + const std::size_t revision = Library::Instance().revision(); + if (myCollectionRevision < revision) { + myCollectionRevision = revision; + makeUpToDate(); + } + + ZLBlockTreeView::paint(); +} + +const std::string &LibraryView::caption() const { + return ZLResource::resource("library")["caption"].value(); +} + +ZLColor LibraryView::backgroundColor() const { + return FBOptions::Instance().BackgroundColorOption.value(); +} + +void LibraryView::showBook(shared_ptr<Book> book) { + makeUpToDate(); + ZLBlockTreeNode::List bookNodes; + std::queue<ZLBlockTreeNode*> nodesQueue; + nodesQueue.push(&rootNode()); + while (!nodesQueue.empty()) { + const ZLBlockTreeNode::List &children = nodesQueue.front()->children(); + nodesQueue.pop(); + for (ZLBlockTreeNode::List::const_iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->isInstanceOf(BookNode::TYPE_ID)) { + // TODO: replace with == for shared_ptr<Book> + //if (((BookNode*)*it)->book() == book) { + if (((BookNode*)*it)->book()->file() == book->file()) { + bookNodes.push_back(*it); + } + } else { + nodesQueue.push(*it); + } + } + } + if (bookNodes.empty()) { + return; + } + ZLBlockTreeNode *nodeToShow = bookNodes[0]; + VisibilityMode mode = INVISIBLE; + for (ZLBlockTreeNode::List::iterator it = bookNodes.begin(); it != bookNodes.end(); ++it) { + VisibilityMode nodeMode = visibilityMode(*it); + if ((nodeMode == VISIBLE && mode != VISIBLE) || + (nodeMode != INVISIBLE && mode == INVISIBLE)) { + nodeToShow = *it; + mode = nodeMode; + } + } + ensureVisible(nodeToShow); +} diff --git a/reader/src/libraryTree/LibraryView.h b/reader/src/libraryTree/LibraryView.h new file mode 100644 index 0000000..40715f6 --- /dev/null +++ b/reader/src/libraryTree/LibraryView.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYVIEW_H__ +#define __LIBRARYVIEW_H__ + +#include <map> +#include <set> + +#include <ZLBlockTreeView.h> + +#include "../library/Lists.h" + +class Book; +class Author; +class Tag; +class TagComparator; + +class AuthorNode; +class TagNode; + +class LibraryView : public ZLBlockTreeView { + +protected: + LibraryView(ZLPaintContext &context); + +public: + void showBook(shared_ptr<Book>); + +private: + ZLColor backgroundColor() const; + const std::string &caption() const; + +private: + void paint(); + +protected: + virtual void makeUpToDate() = 0; + +private: + std::size_t myCollectionRevision; +}; + +class LibraryByAuthorView : public LibraryView { + +public: + LibraryByAuthorView(ZLPaintContext &context); + +private: + void makeUpToDate(); + + void addAuthorSubtree(shared_ptr<Author> author, std::size_t atPosition); + void fillAuthorSubtree(AuthorNode *node, const std::set<shared_ptr<Book> > &visibleBooks); + bool isSubtreeUpToDate(AuthorNode *node); + void updateAuthorSubtree(AuthorNode *node); +}; + +class LibraryByTagView : public LibraryView { + +public: + LibraryByTagView(ZLPaintContext &context); + +private: + void makeUpToDate(); + + void collectTagNodes(const ZLBlockTreeNode &root, std::map<shared_ptr<Tag>,TagNode*,TagComparator> &nodeMap); + void updateBookList(TagNode *tagNode); +}; + +#endif /* __LIBRARYVIEW_H__ */ diff --git a/reader/src/libraryTree/SeriesNode.cpp b/reader/src/libraryTree/SeriesNode.cpp new file mode 100644 index 0000000..8646aac --- /dev/null +++ b/reader/src/libraryTree/SeriesNode.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLImage.h> +#include <ZLResource.h> + +#include "LibraryNodes.h" + +#include "../library/Book.h" + +const ZLTypeId SeriesNode::TYPE_ID(ReaderNode::TYPE_ID); + +const ZLResource &SeriesNode::resource() const { + return ZLResource::resource("libraryView")["seriesNode"]; +} + +const ZLTypeId &SeriesNode::typeId() const { + return TYPE_ID; +} + +SeriesNode::SeriesNode(AuthorNode *parent) : ReaderNode(parent) { +} + +void SeriesNode::init() { + registerExpandTreeAction(); +} + +shared_ptr<Book> SeriesNode::book() const { + return ((BookNode&)*children().front()).book(); +} + +std::string SeriesNode::title() const { + return book()->seriesTitle(); +} + +shared_ptr<const ZLImage> SeriesNode::extractCoverImage() const { + const std::vector<ZLBlockTreeNode*> &books = children(); + for (std::vector<ZLBlockTreeNode*>::const_iterator it = books.begin(); it != books.end(); ++it) { + shared_ptr<const ZLImage> bookCover = ((ReaderNode*)*it)->coverImage(); + if (!bookCover.isNull()) { + return bookCover; + } + } + return 0; +} diff --git a/reader/src/libraryTree/TagNode.cpp b/reader/src/libraryTree/TagNode.cpp new file mode 100644 index 0000000..a873ea5 --- /dev/null +++ b/reader/src/libraryTree/TagNode.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLImage.h> + +#include "LibraryNodes.h" + +#include "../library/Tag.h" +#include "../libraryActions/LibraryTagActions.h" + +const ZLTypeId TagNode::TYPE_ID(ReaderNode::TYPE_ID); + +const ZLTypeId &TagNode::typeId() const { + return TYPE_ID; +} + +const ZLResource &TagNode::resource() const { + return ZLResource::resource("libraryView")["tagNode"]; +} + +std::size_t TagNode::positionToInsert(ZLBlockTreeNode *parent, shared_ptr<Tag> tag) { + const ZLBlockTreeNode::List &children = parent->children(); + ZLBlockTreeNode::List::const_reverse_iterator it = children.rbegin(); + for (; it != children.rend(); ++it) { + if (!(*it)->isInstanceOf(TagNode::TYPE_ID) || + TagComparator()(((TagNode*)*it)->tag(), tag)) { + break; + } + } + return children.rend() - it; +} + +TagNode::TagNode(ZLBlockTreeView::RootNode *parent, shared_ptr<Tag> tag) : ReaderNode(parent, positionToInsert(parent, tag)), myTag(tag) { +} + +TagNode::TagNode(TagNode *parent, shared_ptr<Tag> tag) : ReaderNode(parent, positionToInsert(parent, tag)), myTag(tag) { +} + +void TagNode::init() { + registerExpandTreeAction(); + if (!myTag.isNull()) { + registerAction(new TagEditAction(myTag)); + registerAction(new TagCloneAction(myTag)); + registerAction(new TagRemoveAction(myTag)); + } +} + +shared_ptr<Tag> TagNode::tag() const { + return myTag; +} + +std::string TagNode::title() const { + if (myTag.isNull()) { + return resource()["noTags"].value(); + } + return myTag->name(); +} + +shared_ptr<const ZLImage> TagNode::extractCoverImage() const { + return defaultCoverImage("booktree-tag.png"); +} diff --git a/reader/src/migration/BookInfo.cpp b/reader/src/migration/BookInfo.cpp new file mode 100644 index 0000000..5a13647 --- /dev/null +++ b/reader/src/migration/BookInfo.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "BookInfo.h" + +#include "../options/FBCategoryKey.h" + +static const std::string EMPTY = ""; + +BookInfo::BookInfo(const std::string &fileName) : + AuthorDisplayNameOption(FBCategoryKey::BOOKS, fileName, "AuthorDisplayName", EMPTY), + AuthorSortKeyOption(FBCategoryKey::BOOKS, fileName, "AuthorSortKey", EMPTY), + TitleOption(FBCategoryKey::BOOKS, fileName, "Title", EMPTY), + SeriesTitleOption(FBCategoryKey::BOOKS, fileName, "Sequence", EMPTY), + IndexInSeriesOption(FBCategoryKey::BOOKS, fileName, "Series Number in Sequence", EMPTY), + LanguageOption(FBCategoryKey::BOOKS, fileName, "Language", EMPTY), + EncodingOption(FBCategoryKey::BOOKS, fileName, "Encoding", EMPTY), + TagsOption(FBCategoryKey::BOOKS, fileName, "TagList", EMPTY) { +} + +void BookInfo::reset() { + AuthorDisplayNameOption.setValue(EMPTY); + AuthorSortKeyOption.setValue(EMPTY); + TitleOption.setValue(EMPTY); + SeriesTitleOption.setValue(EMPTY); + IndexInSeriesOption.setValue(EMPTY); + LanguageOption.setValue(EMPTY); + EncodingOption.setValue(EMPTY); + TagsOption.setValue(EMPTY); +} + +bool BookInfo::isFull() const { + return + !AuthorDisplayNameOption.value().empty() && + !AuthorSortKeyOption.value().empty() && + !TitleOption.value().empty() && + !EncodingOption.value().empty(); +} + +const BookInfo &BookInfo::operator = (const BookInfo &bi) { + AuthorDisplayNameOption.setValue(bi.AuthorDisplayNameOption.value()); + AuthorSortKeyOption.setValue(bi.AuthorSortKeyOption.value()); + TitleOption.setValue(bi.TitleOption.value()); + SeriesTitleOption.setValue(bi.SeriesTitleOption.value()); + IndexInSeriesOption.setValue(bi.IndexInSeriesOption.value()); + LanguageOption.setValue(bi.LanguageOption.value()); + EncodingOption.setValue(bi.EncodingOption.value()); + TagsOption.setValue(bi.TagsOption.value()); + return bi; +} diff --git a/reader/src/migration/BookInfo.h b/reader/src/migration/BookInfo.h new file mode 100644 index 0000000..997e9ea --- /dev/null +++ b/reader/src/migration/BookInfo.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKINFO_H__ +#define __BOOKINFO_H__ + +#include <string> + +#include <ZLOptions.h> + + +struct BookInfo { + BookInfo(const std::string &fileName); + ~BookInfo(); + + bool isFull() const; + void reset(); + + ZLStringOption AuthorDisplayNameOption; + ZLStringOption AuthorSortKeyOption; + ZLStringOption TitleOption; + ZLStringOption SeriesTitleOption; + ZLStringOption IndexInSeriesOption; + ZLStringOption LanguageOption; + ZLStringOption EncodingOption; + ZLStringOption TagsOption; + + const BookInfo &operator = (const BookInfo &bi); +}; + +inline BookInfo::~BookInfo() {} + +#endif /* __BOOKINFO_H__ */ diff --git a/reader/src/migration/FB2MigrationReader.cpp b/reader/src/migration/FB2MigrationReader.cpp new file mode 100644 index 0000000..875c0a5 --- /dev/null +++ b/reader/src/migration/FB2MigrationReader.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLInputStream.h> +#include <ZLUnicodeUtil.h> + +#include "FB2MigrationReader.h" +#include "../formats/fb2/FB2TagManager.h" + +FB2MigrationReader::FB2MigrationReader(BookInfo &info, bool updateSeries) : myInfo(info), myUpdateSeries(updateSeries), myUpdateTags(info.TagsOption.value().empty()) { +} + +void FB2MigrationReader::characterDataHandler(const char *text, std::size_t len) { + if (myReadState == READ_GENRE) { + myGenreBuffer.append(text, len); + } +} + +void FB2MigrationReader::startElementHandler(int tag, const char **attributes) { + switch (tag) { + case _BODY: + interrupt(); + break; + case _TITLE_INFO: + myReadState = READ_SOMETHING; + break; + case _GENRE: + if ((myReadState == READ_SOMETHING) && myUpdateTags) { + myReadState = READ_GENRE; + } + break; + case _SEQUENCE: + if ((myReadState == READ_SOMETHING) && myUpdateSeries) { + const char *name = attributeValue(attributes, "name"); + if (name != 0) { + std::string seriesTitle = name; + ZLUnicodeUtil::utf8Trim(seriesTitle); + myInfo.SeriesTitleOption.setValue(seriesTitle); + const char *number = attributeValue(attributes, "number"); + myInfo.IndexInSeriesOption.setValue((number != 0) ? std::string(number) : std::string()); + } + } + break; + default: + break; + } +} + +void FB2MigrationReader::endElementHandler(int tag) { + switch (tag) { + case _TITLE_INFO: + myReadState = READ_NOTHING; + break; + case _GENRE: + if (myReadState == READ_GENRE) { + ZLUnicodeUtil::utf8Trim(myGenreBuffer); + if (!myGenreBuffer.empty()) { + const std::vector<std::string> &tags = + FB2TagManager::Instance().humanReadableTags(myGenreBuffer); + if (!tags.empty()) { + myTags.insert(tags.begin(), tags.end()); + } else { + myTags.insert(myGenreBuffer); + } + myGenreBuffer.erase(); + } + myReadState = READ_SOMETHING; + } + break; + default: + break; + } +} + +void FB2MigrationReader::doRead(const ZLFile &file) { + myReadState = READ_NOTHING; + readDocument(file); + if (myUpdateTags) { + std::string tagList; + for (std::set<std::string>::const_iterator it = myTags.begin(); it != myTags.end(); ++it) { + if (it != myTags.begin()) { + tagList += ","; + } + tagList += *it; + } + myInfo.TagsOption.setValue(tagList); + } +} diff --git a/reader/src/migration/FB2MigrationReader.h b/reader/src/migration/FB2MigrationReader.h new file mode 100644 index 0000000..d8e7dd2 --- /dev/null +++ b/reader/src/migration/FB2MigrationReader.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FB2MIGRATIONREADER_H__ +#define __FB2MIGRATIONREADER_H__ + +#include <set> +#include <string> + +#include "../formats/fb2/FB2Reader.h" + +#include "BookInfo.h" + +class FB2MigrationReader : public FB2Reader { + +public: + FB2MigrationReader(BookInfo &info, bool updateSeries); + + void doRead(const ZLFile &file); + + void startElementHandler(int tag, const char **attributes); + void endElementHandler(int tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + BookInfo &myInfo; + + enum { + READ_NOTHING, + READ_SOMETHING, + READ_GENRE + } myReadState; + + bool myUpdateSeries; + bool myUpdateTags; + + std::string myGenreBuffer; + std::set<std::string> myTags; +}; + +#endif /* __FB2MIGRATIONREADER_H__ */ diff --git a/reader/src/migration/HtmlDCTagsReader.cpp b/reader/src/migration/HtmlDCTagsReader.cpp new file mode 100644 index 0000000..4929686 --- /dev/null +++ b/reader/src/migration/HtmlDCTagsReader.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> + +#include "HtmlDCTagsReader.h" + +HtmlDCTagsReader::HtmlDCTagsReader(BookInfo &info) : HtmlReader(info.EncodingOption.value()), myInfo(info) { +} + +bool HtmlDCTagsReader::tagHandler(const HtmlReader::HtmlTag &tag) { + if (tag.Name == "BODY") { + return false; + } else if (tag.Name == "DC:SUBJECT") { + myReadTag = tag.Start; + ZLStringUtil::stripWhiteSpaces(myBuffer); + if (!tag.Start && !myBuffer.empty()) { + if (!myTagList.empty()) { + myTagList += ","; + } + myTagList += myBuffer; + myBuffer.erase(); + } + } + return true; +} + +void HtmlDCTagsReader::startDocumentHandler() { + myReadTag = false; +} + +void HtmlDCTagsReader::endDocumentHandler() { + myInfo.TagsOption.setValue(myTagList); +} + +bool HtmlDCTagsReader::characterDataHandler(const char *text, std::size_t len, bool convert) { + if (myReadTag) { + if (convert) { + myConverter->convert(myBuffer, text, text + len); + } else { + myBuffer.append(text, len); + } + } + return true; +} diff --git a/reader/src/migration/HtmlDCTagsReader.h b/reader/src/migration/HtmlDCTagsReader.h new file mode 100644 index 0000000..5cd7f9a --- /dev/null +++ b/reader/src/migration/HtmlDCTagsReader.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __HTMLDCTAGSREADER_H__ +#define __HTMLDCTAGSREADER_H__ + +#include "../formats/html/HtmlReader.h" +#include "BookInfo.h" + +class HtmlDCTagsReader : public HtmlReader { + +public: + HtmlDCTagsReader(BookInfo &info); + +private: + void startDocumentHandler(); + void endDocumentHandler(); + + bool tagHandler(const HtmlTag &tag); + bool characterDataHandler(const char *text, std::size_t len, bool convert); + +private: + BookInfo &myInfo; + + bool myReadTag; + + std::string myBuffer; + std::string myTagList; +}; + +#endif /* __HTMLDCTAGSREADER_H__ */ diff --git a/reader/src/migration/Migration.cpp b/reader/src/migration/Migration.cpp new file mode 100644 index 0000000..4226c62 --- /dev/null +++ b/reader/src/migration/Migration.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> + +#include "../options/FBCategoryKey.h" + +#include "Migration.h" + +void Migration::moveOption( + const ZLCategoryKey &oldCategory, const std::string &oldGroup, const std::string &oldName, + const ZLCategoryKey &newCategory, const std::string &newGroup, const std::string &newName, + const std::string &defaultValue +) { + ZLStringOption newOption(newCategory, newGroup, newName, defaultValue); + const std::string newValue = newOption.value(); + ZLStringOption oldOption(oldCategory, oldGroup, oldName, newValue); + const std::string oldValue = oldOption.value(); + if (newValue != oldValue) { + newOption.setValue(oldValue); + oldOption.setValue(newValue); + } +} + +bool Migration::isLikeToFileName(const std::string &str) { + return + ZLStringUtil::stringStartsWith(str, "/") || + ZLStringUtil::stringStartsWith(str, "\\\\") || + ((str.length() > 2) && (str.substr(1, 2) == ":\\")); +} + +Migration::Migration(const std::string &version) : myVersion(version) { +} + +Migration::~Migration() { +} + +int Migration::extractVersionInformation(const std::string &name) { + int major = std::atoi(name.c_str()); + int minor = 0; + int point = 0; + int index = name.find('.'); + if (index > 0) { + minor = std::atoi(name.c_str() + index + 1); + index = name.find('.', index + 1); + if (index > 0) { + point = std::atoi(name.c_str() + index + 1); + } + } + return 10000 * major + 100 * minor + point; +} + +void Migration::doMigration() { + ZLStringOption versionOption(FBCategoryKey::SYSTEM, "Version", "ReaderVersion", "0"); + if (extractVersionInformation(versionOption.value()) < + extractVersionInformation(myVersion)) { + doMigrationInternal(); + } +} diff --git a/reader/src/migration/Migration.h b/reader/src/migration/Migration.h new file mode 100644 index 0000000..507da79 --- /dev/null +++ b/reader/src/migration/Migration.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __MIGRATION_H__ +#define __MIGRATION_H__ + +#include <string> +#include <map> + +#include <shared_ptr.h> +#include <ZLOptions.h> + +class Migration { + +public: + static int extractVersionInformation(const std::string &name); + +protected: + static void moveOption( + const ZLCategoryKey &oldCategory, const std::string &oldGroup, const std::string &oldName, + const ZLCategoryKey &newCategory, const std::string &newGroup, const std::string &newName, + const std::string &defaultValue + ); + static bool isLikeToFileName(const std::string &str); + +public: + Migration(const std::string &version); + virtual ~Migration(); + void doMigration(); + +protected: + virtual void doMigrationInternal() = 0; + +private: + const std::string myVersion; + +friend class Migration_0_11_0_Runnable; +}; + +class Migration_0_8_11 : public Migration { + +public: + Migration_0_8_11(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_8_13 : public Migration { + +public: + Migration_0_8_13(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_8_16 : public Migration { + +public: + Migration_0_8_16(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_10_4 : public Migration { + +public: + Migration_0_10_4(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_11_0 : public Migration { + +public: + Migration_0_11_0(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_99_0 : public Migration { + +public: + Migration_0_99_0(); + +protected: + void doMigrationInternal(); +}; + +class Migration_0_99_1 : public Migration { + +public: + Migration_0_99_1(); + +protected: + void doMigrationInternal(); +}; + +#endif /* __MIGRATION_H__ */ diff --git a/reader/src/migration/Migration_0_10_4.cpp b/reader/src/migration/Migration_0_10_4.cpp new file mode 100644 index 0000000..b4cedbf --- /dev/null +++ b/reader/src/migration/Migration_0_10_4.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <vector> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "Migration.h" +#include "../options/FBCategoryKey.h" + +Migration_0_10_4::Migration_0_10_4() : Migration("0.10.4") { +} + +void Migration_0_10_4::doMigrationInternal() { + std::vector<std::string> groups; + ZLOption::listOptionGroups(groups); + for (std::vector<std::string>::const_iterator it = groups.begin(); it != groups.end(); ++it) { + static const std::string zipPostfix = ".zip"; + static const std::string sizeName = "Size"; + if (ZLStringUtil::stringEndsWith(ZLUnicodeUtil::toLower(*it), zipPostfix)) { + ZLIntegerOption option(FBCategoryKey::BOOKS, *it, sizeName, -1); + option.setValue(-1); + } + } +} diff --git a/reader/src/migration/Migration_0_11_0.cpp b/reader/src/migration/Migration_0_11_0.cpp new file mode 100644 index 0000000..0c2a509 --- /dev/null +++ b/reader/src/migration/Migration_0_11_0.cpp @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <iostream> +#include <iomanip> +#include <ZLTime.h> + +#include <vector> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "BookInfo.h" +#include "Migration.h" +#include "../options/FBCategoryKey.h" + +#include "../formats/FormatPlugin.h" + +#include "../database/booksdb/BooksDBUtil.h" +#include "../database/booksdb/BooksDB.h" +#include "../library/Book.h" +#include "../library/Tag.h" + +static const std::string BOOK_LIST_GROUP = "BookList"; +static const std::string BOOK_LIST_SIZE = "Size"; +static const std::string BOOK_LIST_PREFIX = "Book"; + +static const std::string CURRENT_STATE_GROUP = "State"; + +static const std::string RECENT_BOOKS_GROUP = "LastOpenedBooks"; +static const std::string BOOK = "Book"; +static const std::size_t MaxXmlListSize = 10; + +static const std::string PARAGRAPH_OPTION_NAME = "Paragraph"; +static const std::string WORD_OPTION_NAME = "Word"; +static const std::string CHAR_OPTION_NAME = "Char"; +static const std::string POSITION_IN_BUFFER = "PositionInBuffer"; +static const std::string BUFFER_SIZE = "UndoBufferSize"; +static const char * const BUFFER_PARAGRAPH_PREFIX = "Paragraph_"; +static const char * const BUFFER_WORD_PREFIX = "Word_"; +static const int MaxXmlStackSize = 20; + +static const std::string SIZE = "Size"; +static const std::string ENTRIES_NUMBER = "EntriesNumber"; +static const std::string PALM_TYPE = "PalmType"; + +static const std::string NET_FILES_GROUP = "Files"; + +class Migration_0_11_0_Runnable : public DBRunnable { + +public: + bool run(); + +private: + bool migrateBooks(); + bool migrateBookList(); + bool migrateState(); + bool migrateNetwork(); + + bool migrateBook(const ZLFile &file); + + std::string tags2string(const TagList &tags); + + bool stringEquals(const std::string &tags1, const std::string &tags2); + + bool migrateRecentBooks(); + + bool migrateBooksState(); + + bool migrateBookStateStack(const std::string &fileName, const Book &book); + bool migrateBookLastState(const std::string &fileName, const Book &book); + + bool shouldReadDisk(const std::string &fileName); + + bool clearBooksOptions(); + + static void moveOption(const ZLCategoryKey &category, const std::string &oldGroup, const std::string &newGroup, const std::string &name, const std::string &defaultValue); + static void moveOption(const ZLCategoryKey &category, const std::string &oldGroup, const std::string &newGroup, const std::string &name, int defaultValue); + static void movePercentGroups(std::vector<std::string> &optionGroups); + static void moveBookGroup(const std::string &oldgroup, const std::string &newgroup); + +private: + std::map<std::string, shared_ptr<Book> > myBooks; +}; + + +inline bool Migration_0_11_0_Runnable::shouldReadDisk(const std::string &fileName) { + const std::string ext = ZLFile(fileName).extension(); + return ext == "fb2" || ext == "epub" || ext == "mobi" || ext == "oebzip" || ext == "opf"; + //return ext == "fb2"; + //return true; +} + + +void Migration_0_11_0_Runnable::moveOption(const ZLCategoryKey &category, const std::string &oldGroup, const std::string &newGroup, const std::string &name, const std::string &defaultValue) { + ZLStringOption newOption(category, newGroup, name, defaultValue); + ZLStringOption oldOption(category, oldGroup, name, defaultValue); + newOption.setValue(oldOption.value()); + oldOption.setValue(defaultValue); +} + +void Migration_0_11_0_Runnable::moveOption(const ZLCategoryKey &category, const std::string &oldGroup, const std::string &newGroup, const std::string &name, int defaultValue) { + ZLIntegerOption newOption(category, newGroup, name, defaultValue); + ZLIntegerOption oldOption(category, oldGroup, name, defaultValue); + newOption.setValue(oldOption.value()); + oldOption.setValue(defaultValue); +} + +static bool percentPathPredicate(const std::string &path) { + static const std::string _start = "%APPLICATION_PATH%"; + return ZLStringUtil::stringStartsWith(path, _start); +} + +void Migration_0_11_0_Runnable::movePercentGroups(std::vector<std::string> &optionGroups) { + std::vector<std::string>::iterator it = optionGroups.begin(); + while ((it = std::find_if(it, optionGroups.end(), percentPathPredicate)) != optionGroups.end()) { + const std::string oldgroup = *it; + const std::string newgroup = ZLFile(oldgroup).resolvedPath(); + if (std::find(optionGroups.begin(), optionGroups.end(), newgroup) == optionGroups.end()) { + moveBookGroup(oldgroup, newgroup); + *it++ = newgroup; + } else { + if (BookInfo(newgroup).TitleOption.value().empty()) { + moveBookGroup(oldgroup, newgroup); + } + it = optionGroups.erase(it); + } + ZLOption::clearGroup(oldgroup); + } +} + +void Migration_0_11_0_Runnable::moveBookGroup(const std::string &oldgroup, const std::string &newgroup) { + BookInfo oldbi(oldgroup); + BookInfo newbi(newgroup); + newbi = oldbi; + oldbi.reset(); + + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, PARAGRAPH_OPTION_NAME, 0); + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, WORD_OPTION_NAME, 0); + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, CHAR_OPTION_NAME, 0); + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, POSITION_IN_BUFFER, 0); + + int stackSize = ZLIntegerOption(ZLCategoryKey::STATE, oldgroup, BUFFER_SIZE, 0).value(); + for (int i = 0; i < stackSize; ++i) { + std::string bufferParagraph = BUFFER_PARAGRAPH_PREFIX; + std::string bufferWord = BUFFER_WORD_PREFIX; + ZLStringUtil::appendNumber(bufferParagraph, i); + ZLStringUtil::appendNumber(bufferWord, i); + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, bufferParagraph, -1); + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, bufferWord, -1); + } + moveOption(ZLCategoryKey::STATE, oldgroup, newgroup, BUFFER_SIZE, 0); +} + + + +Migration_0_11_0::Migration_0_11_0() : Migration("0.11.0") { +} + +void Migration_0_11_0::doMigrationInternal() { + Migration_0_11_0_Runnable r; + BooksDB::Instance().executeAsTransaction(r); + //r.run(); +} + +bool Migration_0_11_0_Runnable::run() { +const ZLTime start; + if (!migrateBooks()) { + std::cerr << std::endl << "VERDICT: migrateBooks failed" << std::endl << std::endl; + } +std::cerr << "migration total 0: " << ZLTime().millisecondsFrom(start) << "ms" << std::endl; + if (!migrateBookList()) { + std::cerr << std::endl << "VERDICT: migrateBookList failed" << std::endl << std::endl; + } +std::cerr << "migration total 1: " << ZLTime().millisecondsFrom(start) << "ms" << std::endl; + if (!migrateState()) { + std::cerr << std::endl << "VERDICT: migrateState failed" << std::endl << std::endl; + } +std::cerr << "migration total 2: " << ZLTime().millisecondsFrom(start) << "ms" << std::endl; + if (!migrateNetwork()) { + std::cerr << std::endl << "VERDICT: migrateNetwork failed" << std::endl << std::endl; + } +std::cerr << "migration total 3: " << ZLTime().millisecondsFrom(start) << "ms" << std::endl; + if (!clearBooksOptions()) { + std::cerr << std::endl << "VERDICT: clearBooksOptions failed" << std::endl << std::endl; + } +std::cerr << "migration total 4: " << ZLTime().millisecondsFrom(start) << "ms" << std::endl; + return true; +} + + + +bool Migration_0_11_0_Runnable::migrateBooks() { + /*std::map<std::string, unsigned long> ext2time; + std::map<std::string, unsigned long> ext2num; + unsigned long totalTime = 0, totalNum = 0;*/ + + PluginCollection &collection = PluginCollection::Instance(); + std::vector<std::string> optionGroups; + ZLOption::listOptionGroups(optionGroups); + + movePercentGroups(optionGroups); + + bool res = true; + for (std::vector<std::string>::const_iterator it = optionGroups.begin(); it != optionGroups.end(); ++it) { + const std::string &name = *it; + if (Migration::isLikeToFileName(name)) { + /* TODO: check correctness of migration order: + * 1) palmType + * 2) size + * 3) book (depends on palmType and size) + */ + const std::string palmType = ZLStringOption(FBCategoryKey::BOOKS, name, PALM_TYPE, "").value(); + if (!palmType.empty()) { + BooksDB::Instance().setPalmType(name, palmType); + } + ZLStringOption(FBCategoryKey::BOOKS, name, PALM_TYPE, "").setValue(""); // clean books.xml + ZLFile file(name); + if (file.physicalFilePath() == name) { + int size = ZLIntegerOption(FBCategoryKey::BOOKS, name, SIZE, -1).value(); + if (size != -1) { + BooksDB::Instance().setFileSize(name, size); + } + } + if (collection.plugin(file, false) != 0) { + if (!BookInfo(name).TitleOption.value().empty()) { + //ZLTime start; + if (!migrateBook(ZLFile(name))) { + std::cerr << "ERROR(2): migrateBook failed" << std::endl; + res = false; + } + /*ZLTime end; + { + unsigned time = end.millisecondsFrom(start); + std::string ext = ZLFile(name).extension(); + totalTime += time; + totalNum += 1; + ext2time[ext] += time; + ext2num[ext] += 1; + }*/ + } + BookInfo(name).reset(); // clean books.xml + } else { + ZLOption::clearGroup(name); // clean books.xml + } + ZLIntegerOption(FBCategoryKey::BOOKS, name, SIZE, -1).setValue(-1); // clean books.xml + if (!ZLStringOption(FBCategoryKey::BOOKS, name, ENTRIES_NUMBER, "").value().empty()) { + ZLOption::clearGroup(name); // clean books.xml + } + } + } + + /*std::cerr << " ext" << " time,ms" << " time/total,%" << " number of books" << " time for 1 book,ms" << std::endl; + std::cerr << "---------------------------------------------------------------------------" << std::endl; + for (std::map<std::string, unsigned long>::const_iterator it = ext2time.begin(); it != ext2time.end(); ++it) { + const std::string &ext = it->first; + unsigned long time = it->second; + unsigned long num = ext2num[ext]; + std::cerr << std::setw(8) << ext << std::setw(10) << time << std::setw(15) << ((float) time) / totalTime * 100.0 + << std::setw(18) << num << std::setw(22) << ((float) time) / num << std::endl; + } + std::cerr << "---------------------------------------------------------------------------" << std::endl; + std::cerr << "total:" << std::endl; + std::cerr << std::setw(8) << "" << std::setw(10) << totalTime << std::setw(15) << "" + << std::setw(20) << totalNum << std::setw(20) << "" << std::endl;*/ + + return res; +} + + +bool Migration_0_11_0_Runnable::migrateBook(const ZLFile &file) { + shared_ptr<Book> infoBook = Book::loadFromBookInfo(file); + if (infoBook.isNull()) { + std::cerr << "ERROR: loading book from BookInfo failed: " << file.path() << std::endl; + return false; + } + if (shouldReadDisk(file.path()) && BooksDBUtil::isBookFull(*infoBook)) { + shared_ptr<Book> fileBook = Book::loadFromFile(file); + //shared_ptr<Book> fileBook = infoBook; + //shared_ptr<Book> fileBook; + if (!fileBook.isNull()) { + std::string tagList1 = tags2string(infoBook->tags()); + std::string tagList2 = tags2string(fileBook->tags()); + if (stringEquals(tagList1, tagList2)) { + infoBook->removeAllTags(); + const TagList &tList = fileBook->tags(); + for (TagList::const_iterator it = tList.begin(); it != tList.end(); ++it) { + infoBook->addTag(*it); + } + } + } + } + myBooks.insert(std::make_pair(file.path(), infoBook)); + const bool code = BooksDB::Instance().saveBook(infoBook); + if (!code) { + std::cerr << "ERROR: saving book to database failed: " << file.path() << std::endl; + } + return code; +} + +std::string Migration_0_11_0_Runnable::tags2string(const TagList &tags) { + std::string tagList; + TagList::const_iterator it = tags.begin(); + if (it != tags.end()) { + tagList += (*it++)->fullName(); + while (it != tags.end()) { + tagList += ','; + tagList += (*it++)->fullName(); + } + } + return tagList; +} + +bool Migration_0_11_0_Runnable::stringEquals(const std::string &tags1, const std::string &tags2) { + std::size_t i1 = 0; + std::size_t i2 = 0; + while (i1 < tags1.size() && i2 < tags2.size()) { + if (std::isspace(tags1[i1])) { + ++i1; + continue; + } + if (std::isspace(tags2[i2])) { + ++i2; + continue; + } + if (tags1[i1++] != tags2[i2++]) { + return false; + } + } + if (i1 == tags1.size() && i2 < tags2.size()) { + while (i2 < tags2.size()) { + if (!std::isspace(tags2[i2++])) { + return false; + } + } + return true; + } + if (i1 < tags1.size() && i2 == tags2.size()) { + while (i1 < tags1.size()) { + if (!std::isspace(tags1[i1++])) { + return false; + } + } + return true; + } + return true; +} + +bool Migration_0_11_0_Runnable::migrateBookList() { + bool res = true; + int size = ZLIntegerOption(ZLCategoryKey::STATE, BOOK_LIST_GROUP, BOOK_LIST_SIZE, 0).value(); + for (int i = 0; i < size; ++i) { + std::string optionName = BOOK_LIST_PREFIX; + ZLStringUtil::appendNumber(optionName, i); + const std::string &fileName = ZLStringOption(ZLCategoryKey::STATE, BOOK_LIST_GROUP, optionName, "").value(); + if (!fileName.empty()) { + std::map<std::string, shared_ptr<Book> >::iterator it = myBooks.find(fileName); + if (it != myBooks.end()) { + shared_ptr<Book> book = it->second; + if (!book.isNull() && book->bookId() != 0) { + if (!BooksDB::Instance().insertIntoBookList(*book)) { + std::cerr << "ERROR: insert into BookList failed: " << fileName << std::endl; + res = false; + } + } + } + } + } + ZLOption::clearGroup(BOOK_LIST_GROUP); // clean state.xml + return res; +} + +bool Migration_0_11_0_Runnable::migrateState() { + bool res = true; + if (!migrateRecentBooks()) { + std::cerr << "ERROR(2): migrateRecentBooks failed" << std::endl; + res = false; + } + if (!migrateBooksState()) { + std::cerr << "ERROR(2): migrateBooksState failed" << std::endl; + res = false; + } + ZLOption::clearGroup(RECENT_BOOKS_GROUP); // clean state.xml + ZLOption::clearGroup(CURRENT_STATE_GROUP); // clean state.xml + return res; +} + +bool Migration_0_11_0_Runnable::migrateRecentBooks() { + BookList books; + for (std::size_t i = 0; i < MaxXmlListSize; ++i) { + std::string num = BOOK; + ZLStringUtil::appendNumber(num, i); + std::string name = ZLStringOption(ZLCategoryKey::STATE, RECENT_BOOKS_GROUP, num, "").value(); + if (!name.empty()) { + //shared_ptr<Book> book = BooksDBUtil::getBook(name, false); + std::map<std::string, shared_ptr<Book> >::const_iterator it = myBooks.find(name); + if (it == myBooks.end()) { + if ((it = myBooks.find(ZLFile(name).resolvedPath())) == myBooks.end()) { + continue; + } + } + shared_ptr<Book> book = it->second; + if (!book.isNull() && book->bookId() != 0 && std::find(books.begin(), books.end(), book) == books.end()) { + books.push_back(book); + } + } + } + bool res = BooksDB::Instance().saveRecentBooks(books); + if (!res) { + std::cerr << "ERROR: saving recent books list failed (" << books.size() << " item[s])" << std::endl; + } + return res; +} + +bool Migration_0_11_0_Runnable::migrateBooksState() { + bool res = true; + + for (std::map<std::string, shared_ptr<Book> >::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + const std::string &fileName = it->first; + if (it->second.isNull()) { + std::cerr << "ERROR: book in map is null: " << fileName << std::endl; + res = false; + continue; + } + const Book &book = *it->second; + if (!migrateBookStateStack(fileName, book)) { + res = false; + } + if (!migrateBookLastState(fileName, book)) { + res = false; + } + } + return res; +} + + +bool Migration_0_11_0_Runnable::migrateBookStateStack(const std::string &fileName, const Book &book) { + std::deque<ReadingState> stack; + bool res = true; + int stackSize = ZLIntegerOption(ZLCategoryKey::STATE, fileName, BUFFER_SIZE, 0).value(); + if (stackSize > 0) { + if (stackSize > MaxXmlStackSize) { + stackSize = MaxXmlStackSize; + } + for (int i = 0; i < stackSize; ++i) { + std::string bufferParagraph = BUFFER_PARAGRAPH_PREFIX; + std::string bufferWord = BUFFER_WORD_PREFIX; + ZLStringUtil::appendNumber(bufferParagraph, i); + ZLStringUtil::appendNumber(bufferWord, i); + ReadingState pos( + ZLIntegerOption(ZLCategoryKey::STATE, fileName, bufferParagraph, -1).value(), + ZLIntegerOption(ZLCategoryKey::STATE, fileName, bufferWord, -1).value(), + 0 + ); + stack.push_back(pos); + ZLIntegerOption(ZLCategoryKey::STATE, fileName, bufferParagraph, -1).setValue(-1); // clean state.xml + ZLIntegerOption(ZLCategoryKey::STATE, fileName, bufferWord, -1).setValue(-1); // clean state.xml + } + if (!BooksDB::Instance().saveBookStateStack(book, stack)) { + std::cerr << "ERROR: saving book state stack failed: " << fileName << std::endl; + res = false; + } + stack.clear(); + } + ZLIntegerOption(ZLCategoryKey::STATE, fileName, BUFFER_SIZE, 0).setValue(0); // clean state.xml + return res; +} + +bool Migration_0_11_0_Runnable::migrateBookLastState(const std::string &fileName, const Book &book) { + const ReadingState state( + ZLIntegerOption(ZLCategoryKey::STATE, fileName, PARAGRAPH_OPTION_NAME, 0).value(), + ZLIntegerOption(ZLCategoryKey::STATE, fileName, WORD_OPTION_NAME, 0).value(), + ZLIntegerOption(ZLCategoryKey::STATE, fileName, CHAR_OPTION_NAME, 0).value() + ); + const int stackPos = ZLIntegerOption(ZLCategoryKey::STATE, fileName, POSITION_IN_BUFFER, 0).value(); + if (state.Paragraph == 0 && state.Word == 0 && state.Character == 0 && stackPos == 0) { + return true; + } + ZLIntegerOption(ZLCategoryKey::STATE, fileName, PARAGRAPH_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, fileName, WORD_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, fileName, CHAR_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, fileName, POSITION_IN_BUFFER, 0).setValue(0); + bool res1 = BooksDB::Instance().setBookState(book, state); + bool res2 = BooksDB::Instance().setStackPos(book, stackPos); + if (!res1) { + std::cerr << "ERROR: saving book last state failed: " << fileName << std::endl; + } + if (!res2) { + std::cerr << "ERROR: saving book state stack position failed: " << fileName << std::endl; + } + return res1 && res2; +} + +bool Migration_0_11_0_Runnable::migrateNetwork() { + bool res = true; +// TDE-Ebook-Reader desktop 0.99.1 deprecates NetFiles table, so don't fill it +// std::vector<std::string> urls; +// ZLOption::listOptionNames(NET_FILES_GROUP, urls); +// for (std::vector<std::string>::const_iterator it = urls.begin(); it != urls.end(); ++it) { +// const std::string &url = *it; +// const std::string fileName = ZLStringOption(ZLCategoryKey::NETWORK, NET_FILES_GROUP, url, "").value(); +// if (!BooksDB::Instance().setNetFile(url, fileName)) { +// std::cerr << "ERROR: saving file's URL failed: " << std::endl +// << "\tURL = " << url << std::endl +// << "\tfileName = " << fileName << std::endl; +// res = false; +// } +// } + ZLOption::clearGroup(NET_FILES_GROUP); // clean state.xml + return res; +} + +bool Migration_0_11_0_Runnable::clearBooksOptions() { + bool res = true; + for (std::map<std::string, shared_ptr<Book> >::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + const std::string &fileName = it->first; + if (it->second.isNull()) { + std::cerr << "ERROR: book in map is null in clearBooksOptions: " << fileName << std::endl; + res = false; + continue; + } + ZLOption::clearGroup(fileName); // clear books.xml & state.xml + } + return res; +} + diff --git a/reader/src/migration/Migration_0_8_11.cpp b/reader/src/migration/Migration_0_8_11.cpp new file mode 100644 index 0000000..bf21004 --- /dev/null +++ b/reader/src/migration/Migration_0_8_11.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <map> + +#include <ZLStringUtil.h> + +#include "Migration.h" +#include "../reader/ReaderActions.h" + +static void changeActionNames(const std::map<std::string,std::string> map, const std::string &group) { + const int length = ZLIntegerOption(ZLCategoryKey::CONFIG, group, "Number", 0).value(); + for (int i = 0; i < length; ++i) { + std::string optionName = "Action"; + ZLStringUtil::appendNumber(optionName, i); + ZLStringOption option(ZLCategoryKey::CONFIG, group, optionName, ""); + std::string value = option.value(); + std::map<std::string,std::string>::const_iterator it = map.find(value); + if (it != map.end()) { + option.setValue(it->second); + } + } +} + +static void changeActionNames() { + std::map<std::string,std::string> oldToNewNames; + oldToNewNames["0"] = "none"; + oldToNewNames["1"] = ActionCode::SHOW_LIBRARY; + oldToNewNames["30"] = ActionCode::OPEN_PREVIOUS_BOOK; + oldToNewNames["5"] = ActionCode::SHOW_TOC; + oldToNewNames["15"] = ActionCode::SCROLL_TO_HOME; + oldToNewNames["16"] = ActionCode::SCROLL_TO_START_OF_TEXT; + oldToNewNames["17"] = ActionCode::SCROLL_TO_END_OF_TEXT; + oldToNewNames["33"] = ActionCode::GOTO_NEXT_TOC_SECTION; + oldToNewNames["34"] = ActionCode::GOTO_PREVIOUS_TOC_SECTION; + oldToNewNames["9"] = ActionCode::PAGE_SCROLL_FORWARD; + oldToNewNames["10"] = ActionCode::PAGE_SCROLL_BACKWARD; + oldToNewNames["11"] = ActionCode::LINE_SCROLL_FORWARD; + oldToNewNames["12"] = ActionCode::LINE_SCROLL_BACKWARD; + oldToNewNames["3"] = ActionCode::UNDO; + oldToNewNames["4"] = ActionCode::REDO; + oldToNewNames["35"] = ActionCode::COPY_SELECTED_TEXT_TO_CLIPBOARD; + oldToNewNames["37"] = ActionCode::OPEN_SELECTED_TEXT_IN_DICTIONARY; + oldToNewNames["36"] = ActionCode::CLEAR_SELECTION; + oldToNewNames["6"] = ActionCode::SEARCH; + oldToNewNames["7"] = ActionCode::FIND_PREVIOUS; + oldToNewNames["8"] = ActionCode::FIND_NEXT; + oldToNewNames["19"] = ActionCode::INCREASE_FONT; + oldToNewNames["20"] = ActionCode::DECREASE_FONT; + oldToNewNames["21"] = ActionCode::SHOW_HIDE_POSITION_INDICATOR; + oldToNewNames["22"] = ActionCode::TOGGLE_FULLSCREEN; + oldToNewNames["23"] = ActionCode::FULLSCREEN_ON; + oldToNewNames["27"] = ActionCode::ROTATE_SCREEN; + oldToNewNames["2"] = ActionCode::SHOW_OPTIONS_DIALOG; + oldToNewNames["25"] = ActionCode::SHOW_BOOK_INFO_DIALOG; + oldToNewNames["24"] = ActionCode::ADD_BOOK; + oldToNewNames["18"] = ActionCode::CANCEL; + oldToNewNames["29"] = ActionCode::QUIT; + + changeActionNames(oldToNewNames, "Keys"); + changeActionNames(oldToNewNames, "Keys90"); + changeActionNames(oldToNewNames, "Keys180"); + changeActionNames(oldToNewNames, "Keys270"); +} + +Migration_0_8_11::Migration_0_8_11() : Migration("0.8.11") { +} + +void Migration_0_8_11::doMigrationInternal() { + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "ScrollingDelay", + ZLCategoryKey::CONFIG, "TapScrolling", "ScrollingDelay", + "0" + ); + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "Mode", + ZLCategoryKey::CONFIG, "TapScrolling", "Mode", + "0" + ); + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "LinesToKeep", + ZLCategoryKey::CONFIG, "TapScrolling", "LinesToKeep", + "1" + ); + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "LinesToScroll", + ZLCategoryKey::CONFIG, "TapScrolling", "LinesToScroll", + "1" + ); + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "PercentToScroll", + ZLCategoryKey::CONFIG, "TapScrolling", "PercentToScroll", + "50" + ); + moveOption( + ZLCategoryKey::CONFIG, "FingerTapScrolling", "Enabled", + ZLCategoryKey::CONFIG, "TapScrolling", "Enabled", + "true" + ); + moveOption( + ZLCategoryKey::CONFIG, "Options", "ScrollingDelay", + ZLCategoryKey::CONFIG, "LargeScrolling", "ScrollingDelay", + "250" + ); + changeActionNames(); +} diff --git a/reader/src/migration/Migration_0_8_13.cpp b/reader/src/migration/Migration_0_8_13.cpp new file mode 100644 index 0000000..ff86fed --- /dev/null +++ b/reader/src/migration/Migration_0_8_13.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <vector> + +#include <ZLStringUtil.h> + +#include "Migration.h" + +Migration_0_8_13::Migration_0_8_13() : Migration("0.8.13") { +} + +void Migration_0_8_13::doMigrationInternal() { + std::vector<std::string> optionNames; + ZLOption::listOptionNames("Style", optionNames); + for (std::vector<std::string>::const_iterator it = optionNames.begin(); it != optionNames.end(); ++it) { + if (ZLStringUtil::stringEndsWith(*it, ":lineSpacing") || + ZLStringUtil::stringEndsWith(*it, ":lineSpace")) { + ZLDoubleOption doubleOption(ZLCategoryKey::LOOK_AND_FEEL, "Style", *it, 0.0); + ZLIntegerOption intOption(ZLCategoryKey::LOOK_AND_FEEL, "Style", *it + "Percent", -1); + const double doubleValue = doubleOption.value(); + const int intValue = intOption.value(); + doubleOption.setValue((intValue == -1) ? 0.0 : (intValue / 100.0)); + intOption.setValue((int)(doubleValue * 100)); + } + } +} diff --git a/reader/src/migration/Migration_0_8_16.cpp b/reader/src/migration/Migration_0_8_16.cpp new file mode 100644 index 0000000..d08fc49 --- /dev/null +++ b/reader/src/migration/Migration_0_8_16.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> +#include <ZLLanguageUtil.h> + +#include "Migration.h" +#include "FB2MigrationReader.h" +#include "OEBMigrationReader.h" +#include "HtmlDCTagsReader.h" +#include "BookInfo.h" + +#include "../options/FBCategoryKey.h" +#include "../formats/oeb/OEBPlugin.h" +#include "../formats/pdb/PdbPlugin.h" +#include "../formats/pdb/PalmDocStream.h" + +Migration_0_8_16::Migration_0_8_16() : Migration("0.8.16") { +} + +void Migration_0_8_16::doMigrationInternal() { + PluginCollection &collection = PluginCollection::Instance(); + + std::vector<std::string> optionGroups; + ZLOption::listOptionGroups(optionGroups); + + for (std::vector<std::string>::const_iterator it = optionGroups.begin(); it != optionGroups.end(); ++it) { + if (isLikeToFileName(*it)) { + ZLFile file(*it); + if (collection.plugin(file, false) != 0) { + BookInfo info(*it); + ZLStringOption &languageOption = info.LanguageOption; + const std::string &language = languageOption.value(); + if (language == "") { + languageOption.setValue(collection.DefaultLanguageOption.value()); + } else if (language == "cz") { + languageOption.setValue("cs"); + } else if (language == "none") { + languageOption.setValue(ZLLanguageUtil::OtherLanguageCode); + } else if ((language == "chinese") || (language == "anycharacter")) { + languageOption.setValue("zh"); + } + + const std::string extension = file.extension(); + if (extension == "fb2") { + ZLBooleanOption seriesOption(FBCategoryKey::BOOKS, *it, "SequenceDefined", false); + if (!seriesOption.value() || info.TagsOption.value().empty()) { + FB2MigrationReader(info, !seriesOption.value()).doRead(ZLFile(*it)); + } + seriesOption.setValue(true); + } else if ((extension == "opf") || (extension == "oebzip") || (extension == "epub")) { + if (info.TagsOption.value().empty()) { + OEBMigrationReader(info).doRead(OEBPlugin::opfFile(ZLFile(*it))); + } + } else if ((extension == "prc") || (extension == "pdb") || (extension == "mobi")) { + const std::string fileType = PdbPlugin::fileType(file); + if (info.TagsOption.value().empty() && ((fileType == "BOOKMOBI") || (fileType == "TEXtREAd"))) { + shared_ptr<ZLInputStream> stream = new PalmDocStream(file); + if (!stream.isNull()) { + HtmlDCTagsReader(info).readDocument(*stream); + } + } + } + } + } + } +} diff --git a/reader/src/migration/Migration_0_99_0.cpp b/reader/src/migration/Migration_0_99_0.cpp new file mode 100644 index 0000000..6a1d253 --- /dev/null +++ b/reader/src/migration/Migration_0_99_0.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <string> + +#include <ZLLogger.h> + +#include "../database/booksdb/BooksDB.h" +#include "../library/Number.h" + +#include "Migration.h" + +static const std::string RENAME_TABLE_TO_OBSOLETE = "ALTER TABLE BookSeries RENAME TO BookSeries_Obsolete"; +static const std::string CREATE_NEW_TABLE = \ + "CREATE TABLE IF NOT EXISTS BookSeries ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id), " \ + " series_id INTEGER NOT NULL REFERENCES Series (series_id), " \ + " book_index TEXT " \ + "); "; +static const std::string DROP_OBSOLETE_TABLE = "DROP TABLE BookSeries_Obsolete"; +static const std::string LOAD_OBSOLETE_SERIES_QUERY = + "SELECT book_id, series_id, book_index" \ + " FROM BookSeries_Obsolete;"; + +class Migration_0_99_0_Runnable : public DBRunnable { +public: + bool run(); + +}; + +bool Migration_0_99_0_Runnable::run() { + DBConnection &connection = BooksDB::Instance().connection(); + + shared_ptr<DBCommand> renameTable = SQLiteFactory::createCommand(RENAME_TABLE_TO_OBSOLETE, connection); + shared_ptr<DBCommand> createNewTable = SQLiteFactory::createCommand(CREATE_NEW_TABLE, connection); + shared_ptr<DBCommand> dropObsoleteTable = SQLiteFactory::createCommand(DROP_OBSOLETE_TABLE, connection); + shared_ptr<DBCommand> loadObsoleteSeries = SQLiteFactory::createCommand(LOAD_OBSOLETE_SERIES_QUERY, connection); + shared_ptr<DBCommand> insertBookSeries = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOKSERIES, connection, "@book_id", DBValue::DBINT, "@series_id", DBValue::DBINT, "@book_index", DBValue::DBTEXT); + + if (!renameTable->execute()) { + return false; + } + if (!createNewTable->execute()) { + return false; + } + + shared_ptr<DBDataReader> reader = loadObsoleteSeries->executeReader(); + while (reader->next()) { + ((DBIntValue &) *insertBookSeries->parameter("@book_id").value()) = reader->intValue(0); + ((DBIntValue &) *insertBookSeries->parameter("@series_id").value()) = reader->intValue(1); + Number seriesIndex; + if (reader->type(2) == DBValue::DBREAL){ + seriesIndex = Number((int)reader->realValue(2)); + } else { + seriesIndex = Number(reader->intValue(2)); + } + ((DBTextValue &) *insertBookSeries->parameter("@book_index").value()) = seriesIndex.value(); + if (!insertBookSeries->execute()) { + ZLLogger::Instance().println("Migration", "problems with inserting series & book index"); + } + } + dropObsoleteTable->execute(); + return true; +} + + +Migration_0_99_0::Migration_0_99_0() : Migration("0.99.0") { + +} + +void Migration_0_99_0::doMigrationInternal() { + Migration_0_99_0_Runnable r; + BooksDB::Instance().executeAsTransaction(r); +} + diff --git a/reader/src/migration/Migration_0_99_1.cpp b/reader/src/migration/Migration_0_99_1.cpp new file mode 100644 index 0000000..985d743 --- /dev/null +++ b/reader/src/migration/Migration_0_99_1.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <map> + +#include <ZLStringUtil.h> + +#include "Migration.h" +#include "../reader/ReaderActions.h" +#include "../database/networkdb/NetworkDB.h" + +Migration_0_99_1::Migration_0_99_1() : Migration("0.99.1") { +} + +void Migration_0_99_1::doMigrationInternal() { + shared_ptr<DBCommand> cmd = SQLiteFactory::createCommand("DROP TABLE IF EXISTS NetFiles", NetworkDB::Instance().connection()); + cmd->execute(); +} diff --git a/reader/src/migration/OEBMigrationReader.cpp b/reader/src/migration/OEBMigrationReader.cpp new file mode 100644 index 0000000..735e0df --- /dev/null +++ b/reader/src/migration/OEBMigrationReader.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLUnicodeUtil.h> +#include <ZLXMLNamespace.h> + +#include "OEBMigrationReader.h" + +OEBMigrationReader::OEBMigrationReader(BookInfo &info) : myInfo(info) { +} + +static const std::string METADATA = "metadata"; +static const std::string DC_METADATA = "dc-metadata"; + +void OEBMigrationReader::characterDataHandler(const char *text, std::size_t len) { + if (myReadSubject) { + myBuffer.append(text, len); + } +} + +bool OEBMigrationReader::testDCTag(const std::string &name, const std::string &tag) const { + return + testTag(ZLXMLNamespace::DublinCore, name, tag) || + testTag(ZLXMLNamespace::DublinCoreLegacy, name, tag); +} + +void OEBMigrationReader::startElementHandler(const char *tag, const char**) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if ((METADATA == tagString) || (DC_METADATA == tagString)) { + myDCMetadataTag = tagString; + myReadMetaData = true; + } else if (myReadMetaData) { + if (testDCTag("subject", tagString)) { + myReadSubject = true; + } + } +} + +void OEBMigrationReader::endElementHandler(const char *tag) { + const std::string tagString = ZLUnicodeUtil::toLower(tag); + if (myDCMetadataTag == tagString) { + interrupt(); + } else if (myReadSubject) { + ZLUnicodeUtil::utf8Trim(myBuffer); + if (!myBuffer.empty()) { + if (!myTagList.empty()) { + myTagList += ','; + } + myTagList += myBuffer; + myBuffer.erase(); + } + myReadSubject = false; + } +} + +bool OEBMigrationReader::processNamespaces() const { + return true; +} + +void OEBMigrationReader::doRead(const ZLFile &file) { + myReadMetaData = false; + myReadSubject = false; + readDocument(file); + myInfo.TagsOption.setValue(myTagList); +} diff --git a/reader/src/migration/OEBMigrationReader.h b/reader/src/migration/OEBMigrationReader.h new file mode 100644 index 0000000..2ce6690 --- /dev/null +++ b/reader/src/migration/OEBMigrationReader.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OEBMIGRATIONREADER_H__ +#define __OEBMIGRATIONREADER_H__ + +#include <vector> + +#include <ZLXMLReader.h> + +#include "BookInfo.h" + +class OEBMigrationReader : public ZLXMLReader { + +public: + OEBMigrationReader(BookInfo &info); + void doRead(const ZLFile &file); + + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + bool processNamespaces() const; + +private: + bool testDCTag(const std::string &name, const std::string &tag) const; + +private: + BookInfo &myInfo; + + bool myReadMetaData; + bool myReadSubject; + + std::string myDCMetadataTag; + std::string myBuffer; + std::string myTagList; +}; + +#endif /* __OEBMIGRATIONREADER_H__ */ diff --git a/reader/src/migration/migrate.cpp b/reader/src/migration/migrate.cpp new file mode 100644 index 0000000..af411f0 --- /dev/null +++ b/reader/src/migration/migrate.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "../options/FBCategoryKey.h" + +#include "Migration.h" +#include "migrate.h" + +MigrationRunnable::MigrationRunnable() : + myVersionOption(FBCategoryKey::SYSTEM, "Version", "ReaderVersion", "0") { +} + +bool MigrationRunnable::shouldMigrate() const { + return + Migration::extractVersionInformation(myVersionOption.value()) < + Migration::extractVersionInformation(VERSION); +} + +void MigrationRunnable::run() { + Migration_0_8_11().doMigration(); + Migration_0_8_13().doMigration(); + Migration_0_8_16().doMigration(); + Migration_0_10_4().doMigration(); + Migration_0_11_0().doMigration(); + Migration_0_99_0().doMigration(); + Migration_0_99_1().doMigration(); + + myVersionOption.setValue(VERSION); +} diff --git a/reader/src/migration/migrate.h b/reader/src/migration/migrate.h new file mode 100644 index 0000000..e833d28 --- /dev/null +++ b/reader/src/migration/migrate.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __MIGRATE_H__ +#define __MIGRATE_H__ + +#include <ZLOptions.h> +#include <ZLRunnable.h> + +class MigrationRunnable : public ZLRunnable { + +public: + MigrationRunnable(); + bool shouldMigrate() const; + void run(); + +private: + ZLStringOption myVersionOption; +}; + +#endif /* __MIGRATE_H__ */ diff --git a/reader/src/network/BookReference.cpp b/reader/src/network/BookReference.cpp new file mode 100644 index 0000000..9740a65 --- /dev/null +++ b/reader/src/network/BookReference.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLFile.h> + +#include "BookReference.h" +#include "NetworkLinkCollection.h" + +BookReference::BookReference(const std::string &url, Format format, Type type) : URL(url), BookFormat(format), ReferenceType(type) { +} + +const std::string &BookReference::cleanURL() const { + return URL; +} + +std::string BuyBookReference::price(const std::string &price, const std::string ¤cy) { + if (currency.empty()) { + return price; + } else if (currency == "RUB") { + return price + " Ñ€."; + } else if (currency == "USD") { + return "$" + price; + } + return currency + " " + price; +} + +BuyBookReference::BuyBookReference(const std::string &url, Format format, Type type, const std::string &price) : BookReference(url, format, type), Price(price) { +} + +DecoratedBookReference::DecoratedBookReference(const BookReference &base, const std::string &url) : BookReference(url, base.BookFormat, base.ReferenceType), myCleanURL(base.cleanURL()) { +} + +const std::string &DecoratedBookReference::cleanURL() const { + return myCleanURL; +} + +std::string BookReference::localCopyFileName() const { + std::string fileName = NetworkLinkCollection::Instance().bookFileName(*this); + if (!fileName.empty() && ZLFile(fileName).exists()) { + return fileName; + } + + return std::string(); +} diff --git a/reader/src/network/BookReference.h b/reader/src/network/BookReference.h new file mode 100644 index 0000000..7b7ef74 --- /dev/null +++ b/reader/src/network/BookReference.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKREFERENCE_H__ +#define __BOOKREFERENCE_H__ + +#include <string> + +class BookReference { + +public: + enum Type { + DOWNLOAD_FULL, + DOWNLOAD_FULL_CONDITIONAL, + DOWNLOAD_DEMO, + DOWNLOAD_FULL_OR_DEMO, + BUY, + BUY_IN_BROWSER, + UNKNOWN + }; + + enum Format { + NONE = 0, + MOBIPOCKET = 1, + FB2_ZIP = 2, + EPUB = 3, + }; + +public: + BookReference(const std::string &url, Format format, Type type); + +public: + const std::string URL; + const Format BookFormat; + const Type ReferenceType; + +public: + virtual const std::string &cleanURL() const; + + std::string localCopyFileName() const; + +private: + BookReference(const BookReference&); + const BookReference &operator = (const BookReference&); +}; + +class BuyBookReference : public BookReference { + +public: + BuyBookReference(const std::string &url, Format format, Type type, const std::string &price); + +public: + static std::string price(const std::string &price, const std::string ¤cy); + +public: + const std::string Price; +}; + +class DecoratedBookReference : public BookReference { + +public: + DecoratedBookReference(const BookReference &base, const std::string &url); + +private: + const std::string &cleanURL() const; + +private: + const std::string myCleanURL; +}; + +#endif /* __BOOKREFERENCE_H__ */ diff --git a/reader/src/network/NetworkBookCollection.cpp b/reader/src/network/NetworkBookCollection.cpp new file mode 100644 index 0000000..155d702 --- /dev/null +++ b/reader/src/network/NetworkBookCollection.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLResource.h> + +#include "NetworkBookCollection.h" + + +NetworkBookCollection::NetworkBookCollection() { + myAuthorComparator = new NetworkAuthorComparator(myAuthorRates); +} + +void NetworkBookCollection::clear() { + myBookList.clear(); + myAuthorRates.clear(); + myAuthorBooksMap.reset(); +} + +void NetworkBookCollection::addBook(shared_ptr<NetworkItem> bookPtr) { + if (bookPtr.isNull() || bookPtr->typeId() != NetworkBookItem::TYPE_ID) { + return; + } + myAuthorBooksMap.reset(); + + NetworkItem::List::iterator it = std::upper_bound(myBookList.begin(), myBookList.end(), bookPtr, NetworkBookItemComparator()); + myBookList.insert(it, bookPtr); + + NetworkBookItem &book = (NetworkBookItem &) *bookPtr; + + for (std::vector<NetworkBookItem::AuthorData>::const_iterator jt = book.Authors.begin(); jt != book.Authors.end(); ++jt) { + const NetworkBookItem::AuthorData &author = *jt; + std::map<NetworkBookItem::AuthorData, unsigned int>::iterator kt = myAuthorRates.find(author); + if (kt == myAuthorRates.end()) { + myAuthorRates[author] = book.Index; + } else if (kt->second > book.Index) { + kt->second = book.Index; + } + } +} + +const NetworkAuthorBooksMap &NetworkBookCollection::authorBooksMap() { + if (myAuthorBooksMap.isNull()) { + myAuthorBooksMap = new NetworkAuthorBooksMap(*myAuthorComparator); + NetworkAuthorBooksMap &bookMap = *myAuthorBooksMap; + for (NetworkItem::List::const_iterator it = myBookList.begin(); it != myBookList.end(); ++it) { + NetworkBookItem &book = (NetworkBookItem &) **it; + for (std::vector<NetworkBookItem::AuthorData>::const_iterator jt = book.Authors.begin(); jt != book.Authors.end(); ++jt) { + bookMap[*jt].push_back(*it); + } + } + } + return *myAuthorBooksMap; +} diff --git a/reader/src/network/NetworkBookCollection.h b/reader/src/network/NetworkBookCollection.h new file mode 100644 index 0000000..730416e --- /dev/null +++ b/reader/src/network/NetworkBookCollection.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKBOOKCOLLECTION_H__ +#define __NETWORKBOOKCOLLECTION_H__ + +#include "NetworkItems.h" + +#include "NetworkComparators.h" + + +typedef std::map<NetworkBookItem::AuthorData, NetworkItem::List, NetworkAuthorComparator> NetworkAuthorBooksMap; + + +class NetworkBookCollection { + +public: + NetworkBookCollection(); + +public: + void addBook(shared_ptr<NetworkItem> bookPtr); + + const NetworkItem::List &books() const; + bool empty() const; + + void clear(); + + const NetworkAuthorBooksMap &authorBooksMap(); + +private: + NetworkItem::List myBookList; + std::map<NetworkBookItem::AuthorData, unsigned int> myAuthorRates; + shared_ptr<NetworkAuthorComparator> myAuthorComparator; + shared_ptr<NetworkAuthorBooksMap> myAuthorBooksMap; + +private: // disable copying + NetworkBookCollection(const NetworkBookCollection &); + const NetworkBookCollection &operator = (const NetworkBookCollection &); +}; + +inline const NetworkItem::List &NetworkBookCollection::books() const { return myBookList; } +inline bool NetworkBookCollection::empty() const { return myBookList.empty(); } + +#endif /* __NETWORKBOOKCOLLECTION_H__ */ diff --git a/reader/src/network/NetworkBookItem.cpp b/reader/src/network/NetworkBookItem.cpp new file mode 100644 index 0000000..5eeb101 --- /dev/null +++ b/reader/src/network/NetworkBookItem.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkItems.h" +#include "NetworkLink.h" +#include "authentication/NetworkAuthenticationManager.h" + +const ZLTypeId NetworkBookItem::TYPE_ID(NetworkItem::TYPE_ID); + +bool NetworkBookItem::AuthorData::operator < (const AuthorData &data) const { + const int sComp = SortKey.compare(data.SortKey); + return (sComp < 0) || (sComp == 0 && DisplayName < data.DisplayName); +} + +bool NetworkBookItem::AuthorData::operator != (const NetworkBookItem::AuthorData &data) const { + return DisplayName != data.DisplayName || SortKey != data.SortKey; +} + +bool NetworkBookItem::AuthorData::operator == (const NetworkBookItem::AuthorData &data) const { + return DisplayName == data.DisplayName && SortKey == data.SortKey; +} + +NetworkBookItem::NetworkBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references +) : + NetworkItem(link, title, summary, urlByType), + Index(index), + Id(id), + Language(language), + Date(date), + Authors(authors), + Tags(tags), + SeriesTitle(seriesTitle), + IndexInSeries(indexInSeries), + myReferences(references) { +} + +NetworkBookItem::NetworkBookItem(const NetworkBookItem &book, unsigned int index) : + NetworkItem(book.Link, book.Title, book.Summary, book.URLByType), + Index(index), + Id(book.Id), + Language(book.Language), + Date(book.Date), + Authors(book.Authors), + Tags(book.Tags), + SeriesTitle(book.SeriesTitle), + IndexInSeries(book.IndexInSeries) { +} + +const ZLTypeId &NetworkBookItem::typeId() const { + return TYPE_ID; +} + +shared_ptr<BookReference> NetworkBookItem::reference(BookReference::Type type) const { + shared_ptr<BookReference> reference; + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + if ((*it)->ReferenceType == type && + (reference.isNull() || (*it)->BookFormat > reference->BookFormat)) { + reference = *it; + } + } + + if (reference.isNull() && type == BookReference::DOWNLOAD_FULL) { + reference = this->reference(BookReference::DOWNLOAD_FULL_CONDITIONAL); + if (!reference.isNull()) { + shared_ptr<NetworkAuthenticationManager> authManager = + Link.authenticationManager(); + if (authManager.isNull() || authManager->needPurchase(*this)) { + return 0; + } + reference = authManager->downloadReference(*this); + } + } + + if (reference.isNull() && + type == BookReference::DOWNLOAD_FULL && + this->reference(BookReference::BUY).isNull() && + this->reference(BookReference::BUY_IN_BROWSER).isNull()) { + reference = this->reference(BookReference::DOWNLOAD_FULL_OR_DEMO); + } + + if (reference.isNull() && + type == BookReference::DOWNLOAD_DEMO && + (!this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull())) { + reference = this->reference(BookReference::DOWNLOAD_FULL_OR_DEMO); + } + + return reference; +} + +std::string NetworkBookItem::localCopyFileName() const { + const bool hasBuyReference = + !this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull(); + shared_ptr<BookReference> reference; + std::string fileName; + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + const BookReference::Type type = (*it)->ReferenceType; + if ((type == BookReference::DOWNLOAD_FULL || + type == BookReference::DOWNLOAD_FULL_CONDITIONAL || + (!hasBuyReference && type == BookReference::DOWNLOAD_FULL_OR_DEMO)) && + (reference.isNull() || (*it)->BookFormat > reference->BookFormat)) { + std::string name = (*it)->localCopyFileName(); + if (!name.empty()) { + reference = *it; + fileName = name; + } + } + } + return fileName; +} + +void NetworkBookItem::removeLocalFiles() const { + const bool hasBuyReference = + !this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull(); + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + const BookReference::Type type = (*it)->ReferenceType; + if (type == BookReference::DOWNLOAD_FULL || + type == BookReference::DOWNLOAD_FULL_CONDITIONAL || + (!hasBuyReference && type == BookReference::DOWNLOAD_FULL_OR_DEMO)) { + std::string fileName = (*it)->localCopyFileName(); + if (!fileName.empty()) { + // TODO: remove a book from the library + // TODO: remove a record from the database + ZLFile(fileName).remove(); + } + } + } +} + +bool NetworkBookItem::isFullyLoaded() const { + return true; +} + +void NetworkBookItem::loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); +} + +std::vector<shared_ptr<NetworkItem> > NetworkBookItem::getRelatedCatalogsItems() const { + return std::vector<shared_ptr<NetworkItem> >(); +} + +void NetworkBookItem::updateReferences(const std::vector<shared_ptr<BookReference> > &references) { + //TODO implement using one UrlInfoCollection instead of vector of references and urlByType + for (std::size_t i = 0; i < references.size(); ++i) { + bool found = false; + const shared_ptr<BookReference> newRef = references.at(i); + for (std::size_t j = 0; j < myReferences.size(); ++j) { + shared_ptr<BookReference> ref = myReferences.at(j); + if (ref->ReferenceType == newRef->ReferenceType && ref->BookFormat == ref->BookFormat) { + //TODO maybe implement a supporting of new urls with same book format & reference type: + //ref->URL = newRef->URL; + found = true; + break; + } + } + if (!found) { + myReferences.push_back(newRef); + } + } +} diff --git a/reader/src/network/NetworkCatalogItem.cpp b/reader/src/network/NetworkCatalogItem.cpp new file mode 100644 index 0000000..58c739c --- /dev/null +++ b/reader/src/network/NetworkCatalogItem.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "authentication/NetworkAuthenticationManager.h" +#include "NetworkLink.h" + +#include "NetworkItems.h" + +const ZLTypeId NetworkCatalogItem::TYPE_ID(NetworkItem::TYPE_ID); + +NetworkCatalogItem::NetworkCatalogItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : + NetworkItem(link, title, summary, urlByType), + myAccessibility(accessibility), + myFlags(flags) + { +} + +const ZLTypeId &NetworkCatalogItem::typeId() const { + return TYPE_ID; +} + +void NetworkCatalogItem::onDisplayItem() { +} + +bool NetworkCatalogItem::supportsResumeLoading() { + return false; +} + +std::string NetworkCatalogItem::resumeLoading(NetworkItem::List &/*children*/, shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); + return std::string(); +} + +std::string NetworkCatalogItem::getCatalogUrl() { + return URLByType[URL_CATALOG]; +} + +int NetworkCatalogItem::getFlags() const { + return myFlags; +} + +NetworkCatalogItem::AccessibilityType NetworkCatalogItem::getAccessibility() const { + return myAccessibility; +} + +ZLBoolean3 NetworkCatalogItem::getVisibility() const { + shared_ptr<NetworkAuthenticationManager> mgr = Link.authenticationManager(); + switch (myAccessibility) { + case ALWAYS: + return B3_TRUE; + case SIGNED_IN: + if (mgr.isNull()) { + return B3_FALSE; + } + return mgr->isAuthorised().Status == B3_TRUE ? B3_TRUE : B3_UNDEFINED; + case HAS_BOOKS: + if (mgr.isNull()) { + return B3_FALSE; + } else { + if (mgr->purchasedBooks().size() > 0) { + return B3_TRUE; + } else { + return B3_FALSE; + } + } + } + return B3_FALSE; +} diff --git a/reader/src/network/NetworkComparators.cpp b/reader/src/network/NetworkComparators.cpp new file mode 100644 index 0000000..66a0de3 --- /dev/null +++ b/reader/src/network/NetworkComparators.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkComparators.h" + +bool NetworkBookItemComparator::operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + const bool book0isABook = + bookPtr0->isInstanceOf(NetworkBookItem::TYPE_ID); + const bool book1isABook = + bookPtr1->isInstanceOf(NetworkBookItem::TYPE_ID); + + if (!book0isABook && !book1isABook) { + return bookPtr0->Title < bookPtr1->Title; + } + if (!book0isABook || !book1isABook) { + return !book0isABook; + } + + const NetworkBookItem &book0 = (NetworkBookItem &) *bookPtr0; + const NetworkBookItem &book1 = (NetworkBookItem &) *bookPtr1; + + const std::vector<NetworkBookItem::AuthorData> &authors0 = book0.Authors; + const std::vector<NetworkBookItem::AuthorData> &authors1 = book1.Authors; + if (authors0.empty() && !authors1.empty()) { + return true; + } + if (authors1.empty() && !authors0.empty()) { + return false; + } + if (!authors0.empty() && !authors1.empty()) { + if (authors0.front().SortKey != authors1.front().SortKey) { + return authors0.front().SortKey < authors1.front().SortKey; + } + } + + /*if (book0.Index != book1.Index) { + return book0.Index < book1.Index; + }*/ + + const bool book0HasSeriesTitle = !book0.SeriesTitle.empty(); + const bool book1HasSeriesTitle = !book1.SeriesTitle.empty(); + if (book0HasSeriesTitle && book1HasSeriesTitle) { + const int comp = book0.SeriesTitle.compare(book1.SeriesTitle); + if (comp != 0) { + return comp < 0; + } else { + int diff = book0.IndexInSeries - book1.IndexInSeries; + if (diff != 0) { + return diff < 0; + } + } + return book0.Title < book1.Title; + } + + const std::string &book0Key = book0HasSeriesTitle ? book0.SeriesTitle : book0.Title; + const std::string &book1Key = book1HasSeriesTitle ? book1.SeriesTitle : book1.Title; + const int comp = book0Key.compare(book1Key); + if (comp != 0) { + return comp < 0; + } + return book1HasSeriesTitle; +} + + +NetworkAuthorComparator::NetworkAuthorComparator(const std::map<NetworkBookItem::AuthorData, unsigned int> &rates) : myRates(rates) { +} + +bool NetworkAuthorComparator::operator () (const NetworkBookItem::AuthorData &author0, const NetworkBookItem::AuthorData &author1) const { + std::map<NetworkBookItem::AuthorData, unsigned int>::const_iterator it1 = myRates.find(author0); + std::map<NetworkBookItem::AuthorData, unsigned int>::const_iterator it2 = myRates.find(author1); + if (it1 == myRates.end() && it2 == myRates.end()) { + return author0 < author1; + } + if (it1 == myRates.end()) { + return false; + } + if (it2 == myRates.end()) { + return true; + } + if (it1->second != it2->second) { + return it1->second < it2->second; + } + return author0 < author1; +} + +bool NetworkBookItemByTitleComparator::operator ()(const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + return bookPtr0->Title < bookPtr1->Title; +} + +bool NetworkBookItemBySeriesComparator::operator ()(const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + const NetworkBookItem &book0 = static_cast<const NetworkBookItem&>(*bookPtr0); + const NetworkBookItem &book1 = static_cast<const NetworkBookItem&>(*bookPtr1); + if (book0.SeriesTitle != book1.SeriesTitle) { + return book0.SeriesTitle < book1.SeriesTitle; + } + const int diff = book0.IndexInSeries - book1.IndexInSeries; + if (diff != 0) { + return diff < 0 ? true : false; + } + return book0.Title < book1.Title; +} + + + diff --git a/reader/src/network/NetworkComparators.h b/reader/src/network/NetworkComparators.h new file mode 100644 index 0000000..a872a3f --- /dev/null +++ b/reader/src/network/NetworkComparators.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKCOMPARATORS_H__ +#define __NETWORKCOMPARATORS_H__ + + +#include <map> + +#include "NetworkItems.h" + +class NetworkBookItemComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkBookItemByTitleComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkBookItemBySeriesComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkAuthorComparator { + +public: + NetworkAuthorComparator(const std::map<NetworkBookItem::AuthorData, unsigned int> &rates); + + bool operator () (const NetworkBookItem::AuthorData &author0, const NetworkBookItem::AuthorData &author1) const; + +private: + const std::map<NetworkBookItem::AuthorData, unsigned int> &myRates; +}; + +#endif /* __NETWORKCOMPARATORS_H__ */ diff --git a/reader/src/network/NetworkErrors.cpp b/reader/src/network/NetworkErrors.cpp new file mode 100644 index 0000000..d20546f --- /dev/null +++ b/reader/src/network/NetworkErrors.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLStringUtil.h> +#include <ZLDialogManager.h> + +#include "NetworkErrors.h" + +const std::string NetworkErrors::ERROR_AUTHENTICATION_FAILED = "authenticationFailed"; +const std::string NetworkErrors::ERROR_INTERNAL = "internalError"; +const std::string NetworkErrors::ERROR_PURCHASE_NOT_ENOUGH_MONEY = "purchaseNotEnoughMoney"; +const std::string NetworkErrors::ERROR_PURCHASE_MISSING_BOOK = "purchaseMissingBook"; +const std::string NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED = "purchaseAlreadyPurchased"; +const std::string NetworkErrors::ERROR_BOOK_NOT_PURCHASED = "bookNotPurchased"; +const std::string NetworkErrors::ERROR_DOWNLOAD_LIMIT_EXCEEDED = "downloadLimitExceeded"; + +const std::string NetworkErrors::ERROR_LOGIN_ALREADY_TAKEN = "loginAlreadyTaken"; +const std::string NetworkErrors::ERROR_LOGIN_WAS_NOT_SPECIFIED = "loginNotSpecified"; +const std::string NetworkErrors::ERROR_PASSWORD_WAS_NOT_SPECIFIED = "passwordNotSpecified"; +const std::string NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED = "emailNotSpecified"; +const std::string NetworkErrors::ERROR_INVALID_EMAIL = "invalidEMail"; +const std::string NetworkErrors::ERROR_TOO_MANY_REGISTRATIONS = "tooManyRegistrations"; + +const std::string NetworkErrors::ERROR_NO_USER_EMAIL = "noUserEmail"; + +const std::string NetworkErrors::ERROR_SOMETHING_WRONG = "somethingWrongMessage"; +const std::string NetworkErrors::ERROR_UNSUPPORTED_OPERATION = "unsupportedOperation"; + +const std::string NetworkErrors::ERROR_CANT_DOWNLOAD_LIBRARIES_LIST = "librariesListDownloadingFailed"; +const std::string NetworkErrors::ERROR_TIMEOUT_EXPIRED = "operationTimedOutMessage"; + + +std::string NetworkErrors::errorMessage(const std::string &error) { + if (error.empty()) { + return ""; + } + + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + return errorResource[error].value(); +} + +std::string NetworkErrors::errorMessage(const std::string &error, const std::string &arg0) { + if (error.empty()) { + return ""; + } + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + return ZLStringUtil::printf(errorResource[error].value(), arg0); +} + +void NetworkErrors::showErrorMessage(const std::string &error) { + ZLDialogManager::Instance().errorBox(ZLResourceKey("networkError"), error); +} + diff --git a/reader/src/network/NetworkErrors.h b/reader/src/network/NetworkErrors.h new file mode 100644 index 0000000..d18d2f0 --- /dev/null +++ b/reader/src/network/NetworkErrors.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKERRORS_H__ +#define __NETWORKERRORS_H__ + +#include <string> + +class NetworkErrors { + +private: // disable instantiation + NetworkErrors(); + +public: + static const std::string ERROR_AUTHENTICATION_FAILED; + static const std::string ERROR_INTERNAL; + static const std::string ERROR_PURCHASE_NOT_ENOUGH_MONEY; + static const std::string ERROR_PURCHASE_MISSING_BOOK; + static const std::string ERROR_PURCHASE_ALREADY_PURCHASED; + static const std::string ERROR_BOOK_NOT_PURCHASED; + static const std::string ERROR_DOWNLOAD_LIMIT_EXCEEDED; + + static const std::string ERROR_LOGIN_ALREADY_TAKEN; + static const std::string ERROR_LOGIN_WAS_NOT_SPECIFIED; + static const std::string ERROR_PASSWORD_WAS_NOT_SPECIFIED; + static const std::string ERROR_EMAIL_WAS_NOT_SPECIFIED; + static const std::string ERROR_INVALID_EMAIL; + static const std::string ERROR_TOO_MANY_REGISTRATIONS; + + static const std::string ERROR_NO_USER_EMAIL; + + static const std::string ERROR_SOMETHING_WRONG; + static const std::string ERROR_UNSUPPORTED_OPERATION; + static const std::string ERROR_CANT_DOWNLOAD_LIBRARIES_LIST; + + static const std::string ERROR_TIMEOUT_EXPIRED; + +public: + static std::string errorMessage(const std::string &error); + static std::string errorMessage(const std::string &error, const std::string &arg0); + static void showErrorMessage(const std::string &error); +}; + +#endif /* __NETWORKERRORS_H__ */ diff --git a/reader/src/network/NetworkItem.cpp b/reader/src/network/NetworkItem.cpp new file mode 100644 index 0000000..33e22c4 --- /dev/null +++ b/reader/src/network/NetworkItem.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkItems.h" + +const ZLTypeId NetworkItem::TYPE_ID(ZLObjectWithRTTI::TYPE_ID); + +NetworkItem::NetworkItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType +) : + Link(link), + Title(title), + Summary(summary), + URLByType(urlByType) { +} + +NetworkItem::~NetworkItem() { +} diff --git a/reader/src/network/NetworkItems.h b/reader/src/network/NetworkItems.h new file mode 100644 index 0000000..169e5b7 --- /dev/null +++ b/reader/src/network/NetworkItems.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKITEMS_H__ +#define __NETWORKITEMS_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> + +#include <ZLFile.h> +#include <ZLTypeId.h> +#include <ZLBoolean3.h> +#include <ZLNetworkRequest.h> + +#include <ZLTreeNode.h> + +#include "BookReference.h" + +class NetworkAuthenticationManager; +class NetworkLink; + +class NetworkItem : public ZLObjectWithRTTI { + +public: + typedef std::vector<shared_ptr<NetworkItem> > List; + + enum URLType { + URL_NONE, + URL_CATALOG, + URL_HTML_PAGE, + URL_COVER, + URL_FULL_COVER, + URL_SINGLE_ENTRY + }; + + typedef std::map<URLType,std::string> UrlInfoCollection; + +protected: + static const ZLTypeId TYPE_ID; + +protected: + NetworkItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType + ); + +public: + virtual ~NetworkItem(); + + virtual const ZLTypeId &typeId() const = 0; + +public: + const NetworkLink &Link; + const std::string Title; + /*const*/ std::string Summary; + /*const*/ UrlInfoCollection URLByType; + +private: // disable copying + NetworkItem(const NetworkItem &item); + const NetworkItem &operator = (const NetworkItem &); +}; + +class NetworkCatalogItem : public NetworkItem { + +public: + static const ZLTypeId TYPE_ID; + + enum AccessibilityType { + ALWAYS, + SIGNED_IN, + HAS_BOOKS + }; + + enum CatalogFlags { + FLAG_NONE = 0, + FLAG_SHOW_AUTHOR = 1 << 0, + FLAG_GROUP_BY_AUTHOR = 1 << 1, + FLAG_GROUP_BY_SERIES = 1 << 2, + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES = 1 << 3, + FLAGS_DEFAULT = + FLAG_SHOW_AUTHOR | + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES, + FLAGS_GROUP = + FLAG_GROUP_BY_AUTHOR | + FLAG_GROUP_BY_SERIES | + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES, + }; + +public: + NetworkCatalogItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + + const ZLTypeId &typeId() const; + + // method is called each time the View Node is created for the Item. + virtual void onDisplayItem(); + // returns error message + virtual std::string loadChildren(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0) = 0; + virtual bool supportsResumeLoading(); + virtual std::string resumeLoading(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + + int getFlags() const; + AccessibilityType getAccessibility() const; + ZLBoolean3 getVisibility() const; + +protected: + virtual std::string getCatalogUrl(); + +private: + const AccessibilityType myAccessibility; + const int myFlags; +}; + +class NetworkBookItem : public NetworkItem { + +public: + struct AuthorData { + std::string DisplayName; + std::string SortKey; + + bool operator < (const AuthorData &data) const; + bool operator != (const AuthorData &data) const; + bool operator == (const AuthorData &data) const; + }; + +public: + static const ZLTypeId TYPE_ID; + +public: + NetworkBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references + ); + NetworkBookItem(const NetworkBookItem &book, unsigned int index); + + const ZLTypeId &typeId() const; + +public: + shared_ptr<BookReference> reference(BookReference::Type type) const; + + std::string localCopyFileName() const; + void removeLocalFiles() const; + + virtual bool isFullyLoaded() const; + virtual void loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener); + virtual std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + + void updateReferences(const std::vector<shared_ptr<BookReference> > &references); + +public: + /*const*/ unsigned int Index; + const std::string Id; + const std::string Language; + const std::string Date; + const std::vector<AuthorData> Authors; + const std::vector<std::string> Tags; + const std::string SeriesTitle; + const int IndexInSeries; + +private: + std::vector<shared_ptr<BookReference> > myReferences; +}; + +#endif /* __NETWORKITEMS_H__ */ diff --git a/reader/src/network/NetworkLink.cpp b/reader/src/network/NetworkLink.cpp new file mode 100644 index 0000000..218de23 --- /dev/null +++ b/reader/src/network/NetworkLink.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkRequest.h> + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> + +#include "NetworkLink.h" +#include "NetworkOperationData.h" + +const std::string NetworkLink::URL_MAIN = "main"; +const std::string NetworkLink::URL_SEARCH = "search"; +const std::string NetworkLink::URL_SIGN_IN = "signIn"; +const std::string NetworkLink::URL_SIGN_OUT = "signOut"; +const std::string NetworkLink::URL_SIGN_UP = "signUp"; +const std::string NetworkLink::URL_TOPUP = "topup"; +const std::string NetworkLink::URL_RECOVER_PASSWORD = "recoverPassword"; + +NetworkLink::NetworkLink( + const std::string &siteName +) : + mySiteName(ZLStringUtil::stringStartsWith(siteName, "www.") ? siteName.substr(std::string("www.").length()) : siteName), + myEnabled(true), + myUpdated(0) { +} + +NetworkLink::~NetworkLink() { +} + +std::string NetworkLink::url(const std::string &urlId) const { + std::map<std::string,std::string>::const_iterator it = myLinks.find(urlId); + return (it != myLinks.end()) ? it->second : std::string(); +} + +shared_ptr<ZLNetworkRequest> NetworkLink::resume(NetworkOperationData &result) const { + result.clear(); + return 0; +} + +void NetworkLink::setTitle(const std::string& title) { + myTitle = title; +} +void NetworkLink::setSummary(const std::string& summary) { + mySummary = summary; +} + +void NetworkLink::setLanguage(const std::string &language) { + myLanguage = language; +} + +void NetworkLink::setIcon(const std::string& icon) { + myIcon = icon; +} + +void NetworkLink::setPredefinedId(const std::string& id) { + myPredefinedId = id; +} + +void NetworkLink::setLinks(const std::map<std::string,std::string>& links) { + myLinks = links; +} + +void NetworkLink::setUpdated(shared_ptr<ATOMUpdated> u) { + myUpdated = u; +} + +std::string NetworkLink::getSiteName() const { + return mySiteName; +} + +void NetworkLink::setEnabled(bool enabled) { + myEnabled = enabled; +} + +std::string NetworkLink::getTitle() const { + return myTitle; +} +std::string NetworkLink::getSummary() const { + return mySummary; +} + +std::string NetworkLink::getLanguage() const { + return myLanguage; +} + +std::string NetworkLink::getPredefinedId() const { + return myPredefinedId; +} + +const std::map<std::string,std::string>& NetworkLink::getLinks() const { + return myLinks; +} + +shared_ptr<ATOMUpdated> NetworkLink::getUpdated() const { + return myUpdated; +} + +bool NetworkLink::isPredefined() const { + return !myPredefinedId.empty(); +} + +std::string NetworkLink::getIcon() const { + return myIcon; +} +bool NetworkLink::isEnabled() const { + return myEnabled; +} + +void NetworkLink::loadFrom(const NetworkLink & link) { + myTitle = link.myTitle; + myIcon = link.myIcon; + mySummary = link.mySummary; + myLanguage = link.myLanguage; + myLinks = link.myLinks; + myPredefinedId = link.myPredefinedId; + myUpdated = link.myUpdated; +} + +void NetworkLink::loadLinksFrom(const NetworkLink & link) { + myIcon = link.myIcon; + myLinks = link.myLinks; + myUpdated = link.myUpdated; +} + +void NetworkLink::loadSummaryFrom(const NetworkLink & link) { + myTitle = link.myTitle; + mySummary = link.mySummary; +} diff --git a/reader/src/network/NetworkLink.h b/reader/src/network/NetworkLink.h new file mode 100644 index 0000000..e0260b0 --- /dev/null +++ b/reader/src/network/NetworkLink.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKLINK_H__ +#define __NETWORKLINK_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> +#include <ZLOptions.h> + +#include "NetworkItems.h" +#include "atom/ATOMMetadata.h" + +class ZLNetworkRequest; + +class NetworkOperationData; +class NetworkAuthenticationManager; + +class NetworkLink { + +public: + static const std::string URL_MAIN; + static const std::string URL_SEARCH; + static const std::string URL_SIGN_IN; + static const std::string URL_SIGN_OUT; + static const std::string URL_SIGN_UP; + static const std::string URL_TOPUP; + static const std::string URL_RECOVER_PASSWORD; + +protected: + NetworkLink( + const std::string &siteName + ); + +public: + virtual ~NetworkLink(); + std::string url(const std::string &urlId) const; + + void setTitle(const std::string& title); + void setSummary(const std::string& summary); + void setLanguage(const std::string& language); + void setIcon(const std::string& icon); + void setLinks(const std::map<std::string,std::string>& links); + void setPredefinedId(const std::string& id); + void setEnabled(bool enabled); + void setUpdated(shared_ptr<ATOMUpdated> u); + + std::string getSiteName() const; + std::string getTitle() const; + std::string getSummary() const; + std::string getLanguage() const; + std::string getIcon() const; + const std::map<std::string,std::string>& getLinks() const; + std::string getPredefinedId() const; + bool isEnabled() const; + shared_ptr<ATOMUpdated> getUpdated() const; + + bool isPredefined() const; + + void loadFrom(const NetworkLink & link); + void loadLinksFrom(const NetworkLink & link); + void loadSummaryFrom(const NetworkLink & link); + +public: + virtual shared_ptr<ZLNetworkRequest> simpleSearchData(NetworkOperationData &data, const std::string &pattern) const = 0; + virtual shared_ptr<ZLNetworkRequest> advancedSearchData(NetworkOperationData &data, const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) const = 0; + virtual shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &data) const; + + virtual shared_ptr<NetworkAuthenticationManager> authenticationManager() const = 0; + virtual shared_ptr<NetworkItem> libraryItem() const = 0; + + virtual void rewriteUrl(std::string &url, bool isUrlExternal = false) const = 0; + +private: + const std::string mySiteName; + std::string myTitle; + std::string myIcon; + std::string mySummary; + std::string myLanguage; + std::map<std::string,std::string> myLinks; + std::string myPredefinedId; + bool myEnabled; + shared_ptr<ATOMUpdated> myUpdated; + +private: // disable copying + NetworkLink(const NetworkLink &); + const NetworkLink &operator = (const NetworkLink &); +}; + +#endif /* __NETWORKLINK_H__ */ diff --git a/reader/src/network/NetworkLinkCollection.cpp b/reader/src/network/NetworkLinkCollection.cpp new file mode 100644 index 0000000..323605e --- /dev/null +++ b/reader/src/network/NetworkLinkCollection.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cctype> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLResource.h> +#include <ZLNetworkManager.h> +#include <ZLTimeManager.h> +#include <ZLNetworkUtil.h> +#include <ZLibrary.h> +#include <ZLDialogManager.h> +#include <ZLInputStream.h> +#include <ZLOutputStream.h> +#include "../reader/Reader.h" +#include "../networkActions/NetworkOperationRunnable.h" + +#include "NetworkLinkCollection.h" + +#include "../options/FBCategoryKey.h" + +#include "../database/networkdb/NetworkDB.h" + +#include "NetworkOperationData.h" +#include "NetworkBookCollection.h" +#include "BookReference.h" +#include "NetworkErrors.h" + +#include "opds/OPDSLink.h" +#include "opds/OPDSLink_GenericXMLParser.h" +#include "opds/OPDSLink_GenericFeedReader.h" +#include "opds/OPDSXMLParser.h" + +#include "opds/URLRewritingRule.h" + +NetworkLinkCollection *NetworkLinkCollection::ourInstance = 0; + +NetworkLinkCollection &NetworkLinkCollection::Instance() { + if (ourInstance == 0) { + ourInstance = new NetworkLinkCollection(); + } + return *ourInstance; +} + +class NetworkLinkCollection::Comparator { + +public: + bool operator() ( + const shared_ptr<NetworkLink> &first, + const shared_ptr<NetworkLink> &second + ) const; + +private: + std::string removeLeadingNonAscii(const std::string &title) const; +}; + +std::string NetworkLinkCollection::Comparator::removeLeadingNonAscii(const std::string &title) const { + std::string str = title; + std::string::iterator it = str.begin(); + for (; it != str.end(); ++it) { + if ((*it & 0x80) == 0 && std::isalnum(*it)) { + break; + } + } + if (it != str.end()) { + str.erase(str.begin(), it); + } + return str; +} + +bool NetworkLinkCollection::Comparator::operator() ( + const shared_ptr<NetworkLink> &first, + const shared_ptr<NetworkLink> &second +) const { + return + removeLeadingNonAscii(first->getSiteName()) < + removeLeadingNonAscii(second->getSiteName()); +} + +//void NetworkLinkCollection::deleteLink(NetworkLink& link) { +// BooksDB::Instance().deleteNetworkLink(link.SiteName); +// for (std::vector<shared_ptr<NetworkLink> >::iterator it = myLinks.begin(); it != myLinks.end(); ++it) { +// if (&(**it) == &link) { +// myLinks.erase(it); +// break; +// } +// } +// Reader::Instance().refreshWindow(); +//} + +//void NetworkLinkCollection::saveLink(NetworkLink& link, bool isAuto) { +// saveLinkWithoutRefreshing(link, isAuto); +// Reader::Instance().refreshWindow(); +//} + +void NetworkLinkCollection::addOrUpdateLink(shared_ptr<NetworkLink> link) { + bool found = false; + bool updated = false; + + for (std::size_t i = 0; i < myLinks.size(); ++i) { + shared_ptr<NetworkLink> curLink = myLinks.at(i); + if (curLink->getPredefinedId() == link->getPredefinedId()) { + //if (*(link->getUpdated()) > *(curLink->getUpdated())) { + myLinks.at(i) = link; + updated = true; + //TODO implement custom links saving + found = true; + break; + } + } + + if (!found) { + myLinks.push_back(link); + std::sort(myLinks.begin(), myLinks.end(), Comparator()); + updated = true; + } + if (updated) { + NetworkDB::Instance().saveNetworkLink(link); + //Reader::Instance().sendRefresh(); + } +} + + + +static const std::string LOADING_NETWORK_LIBRARY_LIST = "loadingNetworkLibraryList"; + +class NetworkDownloadListRunnable : public NetworkOperationRunnable { +public: + NetworkDownloadListRunnable(ZLFile &tmpFile, const std::string &genericUrl) : + NetworkOperationRunnable(LOADING_NETWORK_LIBRARY_LIST), + myTmpFile(tmpFile), + myGenericUrl(genericUrl) { + } + +private: + void run() { + shared_ptr<ZLNetworkRequest> loadingRequest = ZLNetworkManager::Instance().createDownloadRequest(myGenericUrl, myTmpFile.physicalFilePath()); + myErrorMessage = ZLNetworkManager::Instance().perform(loadingRequest); + } + +private: + ZLFile &myTmpFile; + std::string myGenericUrl; +}; + + +class NetworkLinksUpdater : public ZLRunnable { + +public: + NetworkLinksUpdater(NetworkLinkCollection &networkLinkCollection, shared_ptr<ZLFile> genericFile) : + myNetworkLinkCollection(networkLinkCollection), myGenericFile(genericFile) { } + +private: + void run() { + std::vector<shared_ptr<NetworkLink> > links; + shared_ptr<OPDSFeedReader> feedReader = new OPDSLink::GenericFeedReader(links); + shared_ptr<ZLXMLReader> parser = new OPDSLink::GenericXMLParser(feedReader); + parser->readDocument(*myGenericFile); + + for (std::vector<shared_ptr<NetworkLink> >::iterator it = links.begin(); it != links.end(); ++it) { + myNetworkLinkCollection.addOrUpdateLink(*it); + } + } + +private: + NetworkLinkCollection &myNetworkLinkCollection; + shared_ptr<ZLFile> myGenericFile; +}; + + +NetworkLinkCollection::NetworkLinkCollection() : + DirectoryOption(ZLCategoryKey::NETWORK, "Options", "DownloadDirectory", ""), + LastUpdateTimeOption(ZLCategoryKey::NETWORK, "Update", "LastUpdateTime", -1), + myIsInitialized(false) { +} + +class NetworkLinkCollectionSynchronizer : public DBRunnable { +public: + NetworkLinkCollectionSynchronizer(NetworkLinkCollection &collection) : myCollection(collection) {} + bool run() { + myCollection.synchronize(); + return true; + } +private: + NetworkLinkCollection &myCollection; +}; + +void NetworkLinkCollection::initialize() { + if (myIsInitialized) { + return; + } + NetworkLinkCollectionSynchronizer runnable(*this); + NetworkDB::Instance().executeAsTransaction(runnable); +} + +void NetworkLinkCollection::synchronize() { + NetworkDB::Instance().loadNetworkLinks(myLinks); + std::sort(myLinks.begin(), myLinks.end(), Comparator()); + updateLinks("http://data.fbreader.org/catalogs/generic-1.9.xml"); +} + +void NetworkLinkCollection::updateLinks(std::string genericUrl) { + shared_ptr<ZLFile> genericFile = getGenericFile(genericUrl); + if (genericFile.isNull()) { + NetworkErrors::showErrorMessage(NetworkErrors::errorMessage(NetworkErrors::ERROR_CANT_DOWNLOAD_LIBRARIES_LIST)); + return; + } + + NetworkLinksUpdater updater(*this, genericFile); + ZLDialogManager::Instance().wait(ZLResourceKey(LOADING_NETWORK_LIBRARY_LIST), updater); + myIsInitialized = true; +} + +shared_ptr<ZLFile> NetworkLinkCollection::getGenericFile(std::string genericUrl) { + const std::string FILE_NAME = "fbreader_catalogs-" + genericUrl.substr(genericUrl.find_last_of('/') + 1); + ZLFile genericFileDir(ZLNetworkManager::CacheDirectory()); + genericFileDir.directory(true); + shared_ptr<ZLFile> genericFile = new ZLFile(ZLNetworkManager::CacheDirectory() + ZLibrary::FileNameDelimiter + FILE_NAME); + + long diff = LastUpdateTimeOption.value() == -1 ? -1 : ZLTime().millisecondsFrom(ZLTime(LastUpdateTimeOption.value(), 0)); + + if (genericFile->exists() && diff != -1 && diff < 7 * 24 * 60 * 60 * 1000) { //1 week + return genericFile; + } + + ZLFile tmpFile(ZLNetworkManager::CacheDirectory() + ZLibrary::FileNameDelimiter + "tmp" + FILE_NAME); + NetworkDownloadListRunnable runnable(tmpFile, genericUrl); + runnable.executeWithUI(); + if (runnable.hasErrors()) { + if (!genericFile->exists()) { //loading list from saved file even if obsolete + return 0; + } else { + return genericFile; + } + } + + shared_ptr<ZLOutputStream> outputStream = genericFile->outputStream(true); + shared_ptr<ZLInputStream> inputStream = tmpFile.inputStream(); + if (!outputStream->open() || !inputStream->open()) { + tmpFile.remove(); + return 0; + } + char buffer[2048]; + std::size_t readed = 0; + do { + readed = inputStream->read(buffer, 2048); + outputStream->write(buffer, readed); + } while (readed > 0); + + LastUpdateTimeOption.setValue(ZLTime().inSeconds()); + return genericFile; +} + +NetworkLinkCollection::~NetworkLinkCollection() { +} + +static std::string normalize(const std::string &url) { + static const std::string PREFIX0 = "http://feedbooks.com/"; + static const std::string PREFIX1 = "http://www.feedbooks.com/"; + static const std::string STANZA_PREFIX = "http://feedbooks.com/book/stanza/"; + + std::string nURL = url; + if (ZLStringUtil::stringStartsWith(nURL, PREFIX1)) { + nURL = PREFIX0 + nURL.substr(PREFIX1.length()); + } + if (ZLStringUtil::stringStartsWith(nURL, STANZA_PREFIX)) { + nURL = PREFIX0 + "book/" + nURL.substr(STANZA_PREFIX.length()) + ".epub"; + } + return nURL; +} + +std::string NetworkLinkCollection::bookFileName(const BookReference &reference) { + myErrorMessage.clear(); + return bookFileName(::normalize(reference.cleanURL()), reference.BookFormat, reference.ReferenceType); +} + +static bool parseUrl(const std::string &url, std::string &hostAndPath, std::string &query) { + std::size_t hostBegin = url.find("://"); + if (hostBegin == std::string::npos) { + return false; + } + hostBegin += 3; + if (!url.compare(hostBegin, 4, "www.")) { + hostBegin += 4; + } + std::size_t pathEnd = url.find('?', hostBegin); + hostAndPath = url.substr(hostBegin, pathEnd - hostBegin); + if (pathEnd != std::string::npos) { + query = url.substr(pathEnd + 1); + } + return true; +} + +std::string NetworkLinkCollection::bookFileName(const std::string &url, BookReference::Format format, BookReference::Type type) { + static const std::string escapeChars = "<>:\"|?*\\"; + + std::string path; + std::string query; + if (!::parseUrl(url, path, query)) { + return std::string(); + } + + std::string fileName = DirectoryOption.value(); + if (!ZLStringUtil::stringEndsWith(fileName, ZLibrary::FileNameDelimiter)) { + fileName += ZLibrary::FileNameDelimiter; + } + if (type == BookReference::DOWNLOAD_DEMO) { + fileName += "Demos" + ZLibrary::FileNameDelimiter; + } + + for (std::size_t i = 0; i < path.size(); ++i) { + char ch = path[i]; + if (escapeChars.find(ch) != std::string::npos) { + path[i] = '_'; + } + if (ch == '/') { + path[i] = ZLibrary::FileNameDelimiter[0]; + } + } + + const std::size_t nameIndex = path.find_last_of(ZLibrary::FileNameDelimiter); + if (nameIndex + 1 == path.length()) { + path.resize(path.length() - 1); //removing ending / if exists + } + + std::string ext; + switch (format) { + case BookReference::EPUB: + ext = ".epub"; + break; + case BookReference::MOBIPOCKET: + ext = ".mobi"; + break; + case BookReference::FB2_ZIP: + ext = ".fb2.zip"; + break; + case BookReference::NONE: + break; + } + if (ext.empty()) { + std::size_t tmp = path.find('.', nameIndex); // using not find_last_of to preserve extensions like `.fb2.zip` + if (tmp == std::string::npos) { + return std::string(); + } + ext = path.substr(tmp); + path.resize(tmp); + } else if (ZLStringUtil::stringEndsWith(path, ext)) { + path.resize(path.size() - ext.size()); + } + + if (!query.empty()) { + std::size_t index = 0; + while (index < query.size()) { + std::size_t j = query.find('&', index); + if (j == std::string::npos) { + j = query.size(); + } + std::string param = query.substr(index, j); + if (!ZLStringUtil::stringStartsWith(param, "username=") + && !ZLStringUtil::stringStartsWith(param, "password=") + && !ZLStringUtil::stringEndsWith(param, "=")) { + std::size_t k = path.size(); + path.append("_").append(param); + while (k < path.size()) { + char ch = path[k]; + if (escapeChars.find(ch) != std::string::npos || ch == '/') { + path[k] = '_'; + } + ++k; + } + } + index = j + 1; + } + } + fileName.append(path); + fileName.append(ext); + return fileName; +} + + +bool NetworkLinkCollection::downloadBook(const BookReference &reference, std::string &fileName, shared_ptr<ZLNetworkRequest::Listener> listener) { + std::string nURL = ::normalize(reference.URL); + rewriteUrl(nURL); + const std::string nNetworkBookId = ::normalize(reference.cleanURL()); + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + myErrorMessage.clear(); + + if (nURL.empty() || nNetworkBookId.empty()) { + myErrorMessage = errorResource["unknownErrorMessage"].value(); + return false; + } + fileName = bookFileName(nNetworkBookId, reference.BookFormat, reference.ReferenceType); + + //creating directory if not existed + const std::size_t directoryIndex = fileName.find_last_of(ZLibrary::FileNameDelimiter); + ZLFile(fileName.substr(0, directoryIndex)).directory(true); + + if (ZLFile(fileName).exists()) { + return true; + } + if (fileName.empty()) { + if (myErrorMessage.empty()) { + myErrorMessage = errorResource["unknownErrorMessage"].value(); + } + return false; + } + if (ZLFile(fileName).exists()) { + ZLFile(fileName).remove(); + } + ZLNetworkManager::Instance().downloadFile(nURL, fileName, listener); + return true; +} + +shared_ptr<NetworkBookCollection> NetworkLinkCollection::simpleSearch(const std::string &pattern) { + ZLNetworkRequest::Vector dataList; + std::vector<shared_ptr<NetworkOperationData> > opDataVector; + shared_ptr<NetworkBookCollection> result; + + myErrorMessage.clear(); + + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + NetworkLink &link = **it; + if (link.isEnabled()) { + shared_ptr<NetworkOperationData> opData = new NetworkOperationData(link); + opDataVector.push_back(opData); + shared_ptr<ZLNetworkRequest> data = link.simpleSearchData(*opData, pattern); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + while (myErrorMessage.empty() && !dataList.empty()) { + myErrorMessage = ZLNetworkManager::Instance().perform(dataList); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + NetworkOperationData &opData = **jt; + if (!opData.Items.empty() && result.isNull()) { + result = new NetworkBookCollection(); + } + for (NetworkItem::List::const_iterator kt = opData.Items.begin(); kt != opData.Items.end(); ++kt) { + result->addBook(*kt); + } + } + + dataList.clear(); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + shared_ptr<ZLNetworkRequest> data = (*jt)->resume(); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + return result; +} + +shared_ptr<NetworkBookCollection> NetworkLinkCollection::advancedSearch(const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) { + ZLNetworkRequest::Vector dataList; + std::vector<shared_ptr<NetworkOperationData> > opDataVector; + shared_ptr<NetworkBookCollection> result; + + myErrorMessage.clear(); + + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + NetworkLink &link = **it; + if (link.isEnabled()) { + shared_ptr<NetworkOperationData> opData = new NetworkOperationData(link); + opDataVector.push_back(opData); + shared_ptr<ZLNetworkRequest> data = link.advancedSearchData(*opData, titleAndSeries, author, tag, annotation); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + while (myErrorMessage.empty() && !dataList.empty()) { + myErrorMessage = ZLNetworkManager::Instance().perform(dataList); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + NetworkOperationData &opData = **jt; + if (!opData.Items.empty() && result.isNull()) { + result = new NetworkBookCollection(); + } + for (NetworkItem::List::const_iterator kt = opData.Items.begin(); kt != opData.Items.end(); ++kt) { + result->addBook(*kt); + } + } + + dataList.clear(); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + shared_ptr<ZLNetworkRequest> data = (*jt)->resume(); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + return result; +} + +NetworkLinkCollection::LinkVector NetworkLinkCollection::activeLinks() const { + LinkVector filteredList; + for (std::size_t i = 0; i < myLinks.size(); ++i) { + shared_ptr<NetworkLink> link = myLinks.at(i); + if (link->isEnabled()) { + filteredList.push_back(link); + } + } + return filteredList; +} + +std::size_t NetworkLinkCollection::size() const { + return myLinks.size(); +} + +NetworkLink &NetworkLinkCollection::link(std::size_t index) const { + return *myLinks[index]; +} + +std::size_t NetworkLinkCollection::numberOfEnabledLinks() const { + std::size_t count = 0; + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + if ((*it)->isEnabled()) { + ++count; + } + } + return count; +} + +void NetworkLinkCollection::rewriteUrl(std::string &url, bool externalUrl) const { + const std::string host = + ZLUnicodeUtil::toLower(ZLNetworkUtil::hostFromUrl(url)); + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + if (host.find((*it)->getSiteName()) != std::string::npos) { + (*it)->rewriteUrl(url, externalUrl); + } + } +} diff --git a/reader/src/network/NetworkLinkCollection.h b/reader/src/network/NetworkLinkCollection.h new file mode 100644 index 0000000..080959d --- /dev/null +++ b/reader/src/network/NetworkLinkCollection.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKLINKCOLLECTION_H__ +#define __NETWORKLINKCOLLECTION_H__ + +#include <string> +#include <vector> + +#include <shared_ptr.h> + +#include <ZLOptions.h> +#include <ZLNetworkRequest.h> + +#include "NetworkItems.h" + +class NetworkLink; +class NetworkBookCollection; +class BookReference; + +class NetworkLinkCollection { + +public: + typedef std::vector<shared_ptr<NetworkLink> > LinkVector; + +private: + class Comparator; + +public: + static NetworkLinkCollection &Instance(); + +private: + static NetworkLinkCollection *ourInstance; + +public: + ZLStringOption DirectoryOption; + ZLIntegerOption LastUpdateTimeOption; + +private: + NetworkLinkCollection(); + ~NetworkLinkCollection(); + +public: + void initialize(); + + std::string bookFileName(const BookReference &reference); + + bool downloadBook(const BookReference &reference, std::string &fileName, shared_ptr<ZLNetworkRequest::Listener> listener); + + shared_ptr<NetworkBookCollection> simpleSearch(const std::string &pattern); + shared_ptr<NetworkBookCollection> advancedSearch(const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation); + + LinkVector activeLinks() const; + std::size_t size() const; + std::size_t numberOfEnabledLinks() const; + NetworkLink &link(std::size_t index) const; + + const std::string &errorMessage() const; + + void rewriteUrl(std::string &url, bool externalUrl = false) const; + + //void deleteLink(NetworkLink& link); + //void saveLink(NetworkLink& link, bool isAuto = false); + +private: + void synchronize(); + + std::string bookFileName(const std::string &url, BookReference::Format format, BookReference::Type type); + + void updateLinks(std::string genericUrl); + shared_ptr<ZLFile> getGenericFile(std::string genericUrl); + void addOrUpdateLink(shared_ptr<NetworkLink> link); + +private: + LinkVector myLinks; + std::string myErrorMessage; + bool myIsInitialized; + +friend class NetworkLinksUpdater; +friend class NetworkLinkCollectionSynchronizer; +}; + +inline const std::string &NetworkLinkCollection::errorMessage() const { return myErrorMessage; } + +#endif /* __NETWORKLINKCOLLECTION_H__ */ diff --git a/reader/src/network/NetworkOperationData.cpp b/reader/src/network/NetworkOperationData.cpp new file mode 100644 index 0000000..6988071 --- /dev/null +++ b/reader/src/network/NetworkOperationData.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkRequest.h> + +#include "NetworkLink.h" +#include "NetworkOperationData.h" + +NetworkOperationData::NetworkOperationData(const NetworkLink &link) : Link(link) { +} + +void NetworkOperationData::clear() { + Items.clear(); + ResumeURI.clear(); +} + +shared_ptr<ZLNetworkRequest> NetworkOperationData::resume() { + shared_ptr<ZLNetworkRequest> request = Link.resume(*this); + clear(); + return request; +} diff --git a/reader/src/network/NetworkOperationData.h b/reader/src/network/NetworkOperationData.h new file mode 100644 index 0000000..4d4a46f --- /dev/null +++ b/reader/src/network/NetworkOperationData.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKOPERATIONDATA_H__ +#define __NETWORKOPERATIONDATA_H__ + +#include <shared_ptr.h> + +#include "NetworkItems.h" + +class ZLNetworkRequest; + +class NetworkLink; + +class NetworkOperationData { + +public: + NetworkOperationData(const NetworkLink &link); + + void clear(); + shared_ptr<ZLNetworkRequest> resume(); + +public: + const NetworkLink &Link; + NetworkItem::List Items; + std::string ResumeURI; +}; + +#endif /* __NETWORKOPERATIONDATA_H__ */ diff --git a/reader/src/network/SearchResult.cpp b/reader/src/network/SearchResult.cpp new file mode 100644 index 0000000..2b66326 --- /dev/null +++ b/reader/src/network/SearchResult.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "SearchResult.h" + +SearchResult SearchResult::ourLastSearchResult; + + +SearchResult::SearchResult() { +} + +const SearchResult &SearchResult::lastSearchResult() { + return ourLastSearchResult; +} + +void SearchResult::setLastSearchResult(const std::string &summary, shared_ptr<NetworkBookCollection> bookCollection) { + ourLastSearchResult.mySummary = summary; + ourLastSearchResult.myBookCollection = bookCollection; +} + diff --git a/reader/src/network/SearchResult.h b/reader/src/network/SearchResult.h new file mode 100644 index 0000000..bd18b71 --- /dev/null +++ b/reader/src/network/SearchResult.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __SEARCHRESULT_H__ +#define __SEARCHRESULT_H__ + +#include "NetworkBookCollection.h" + +class SearchResult { + +private: + static SearchResult ourLastSearchResult; + +private: + SearchResult(); + +public: + static const SearchResult &lastSearchResult(); + static void setLastSearchResult(const std::string &summary, shared_ptr<NetworkBookCollection> bookCollection); + +public: + const std::string &summary() const; + shared_ptr<NetworkBookCollection> collection() const; + +private: + std::string mySummary; + shared_ptr<NetworkBookCollection> myBookCollection; +}; + +inline const std::string &SearchResult::summary() const { return mySummary; } +inline shared_ptr<NetworkBookCollection> SearchResult::collection() const { return myBookCollection; } + +#endif /* __SEARCHRESULT_H__ */ diff --git a/reader/src/network/UserList.cpp b/reader/src/network/UserList.cpp new file mode 100644 index 0000000..1712788 --- /dev/null +++ b/reader/src/network/UserList.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLOptions.h> +#include <ZLStringUtil.h> + +#include "UserList.h" + + +static const unsigned int MAX_USER_NAMES = 10; + +static const std::string USER_LIST = "userList-"; +static const std::string USER = "user"; + +UserList::UserList(const std::string &siteName) : myGroupName(USER_LIST + siteName) { + for (unsigned int i = 0; i < MAX_USER_NAMES; ++i) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i); + std::string userName = ZLStringOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, "").value(); + if (!userName.empty()) { + myUserNames.push_back(userName); + mySavedNames.insert(userName); + } + } + if (myUserNames.empty()) { + myUserNames.push_back(std::string()); + } +} + +UserList::~UserList() { + unsigned int i = 0; + for (std::size_t k = 0; k < myUserNames.size() && i < MAX_USER_NAMES; ++k) { + const std::string &name = myUserNames[k]; + if (mySavedNames.find(name) != mySavedNames.end()) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i++); + ZLStringOption userOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, ""); + userOption.setValue(name); + } + } + while (i < MAX_USER_NAMES) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i++); + ZLStringOption userOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, ""); + userOption.setValue(""); + } +} + +const std::vector<std::string> &UserList::users() const { + return myUserNames; +} + +void UserList::addUser(const std::string &user) { + std::vector<std::string>::iterator it; + while ((it = std::find(myUserNames.begin(), myUserNames.end(), user)) != myUserNames.end()) { + myUserNames.erase(it); + } + myUserNames.insert(myUserNames.begin(), user); +} + +void UserList::saveUser(const std::string &user) { + std::vector<std::string>::iterator it = std::find(myUserNames.begin(), myUserNames.end(), user); + if (it == myUserNames.end()) { + myUserNames.insert(myUserNames.begin(), user); + } + mySavedNames.insert(user); +} diff --git a/reader/src/network/UserList.h b/reader/src/network/UserList.h new file mode 100644 index 0000000..d1f298f --- /dev/null +++ b/reader/src/network/UserList.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __USERLIST_H__ +#define __USERLIST_H__ + +#include <string> +#include <vector> +#include <set> + + +class UserList { + +public: + UserList(const std::string &siteName); + ~UserList(); + + const std::vector<std::string> &users() const; + void addUser(const std::string &user); + void saveUser(const std::string &user); + +private: + std::string myGroupName; + std::vector<std::string> myUserNames; + std::set<std::string> mySavedNames; +}; + +#endif /* __USERLIST_H__ */ diff --git a/reader/src/network/atom/ATOMConstructs.cpp b/reader/src/network/atom/ATOMConstructs.cpp new file mode 100644 index 0000000..9684825 --- /dev/null +++ b/reader/src/network/atom/ATOMConstructs.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "ATOMConstructs.h" + +#include <ZLStringUtil.h> + +#include <math.h> + + + +const std::string ATOMCommonAttributes::XML_BASE = "xml:base"; +const std::string ATOMCommonAttributes::XML_LANG = "xml:lang"; + + +ATOMCommonAttributes::ATOMCommonAttributes() { +} + +ATOMCommonAttributes::~ATOMCommonAttributes() { +} + +void ATOMCommonAttributes::readAttributes(const std::map<std::string, std::string> &attributes) { + readAttribute(XML_BASE, attributes); + readAttribute(XML_LANG, attributes); +} + +void ATOMCommonAttributes::readAttribute(const std::string &name, const std::map<std::string, std::string> &attributes) { + std::map<std::string, std::string>::const_iterator it = attributes.find(name); + if (it != attributes.end()) { + myAttributes[name] = it->second; + } +} + +void ATOMCommonAttributes::setUserData(const std::string &key, const std::string &value) { + myUserData[key] = value; +} + +const std::string ATOMCommonAttributes::userData(const std::string &key) const { + std::map<std::string,std::string>::const_iterator it = myUserData.find(key); + return (it != myUserData.end()) ? it->second : std::string(); +} + +ATOMPersonConstruct::ATOMPersonConstruct() { +} + +ATOMPersonConstruct::ATOMPersonConstruct(const std::string &name) : myName(name) { +} + + +ATOMDateConstruct::ATOMDateConstruct(int year) : + myYear(year), myMonth(0), myDay(0), + myHour(0), myMinutes(0), mySeconds(0), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day) : + myYear(year), myMonth(month), myDay(day), + myHour(0), myMinutes(0), mySeconds(0), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(sfract), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(sfract), myTZHour(tzhour), myTZMinutes(tzminutes) { +} + +bool ATOMDateConstruct::operator<(const ATOMDateConstruct &a) const { + if (myYear < a.myYear) return true; + if (myYear > a.myYear) return false; + + if (myMonth < a.myMonth) return true; + if (myMonth > a.myMonth) return false; + + if (myDay < a.myDay) return true; + if (myDay > a.myDay) return false; + + if (myHour < a.myHour) return true; + if (myHour > a.myHour) return false; + + if (myMinutes < a.myMinutes) return true; + if (myMinutes > a.myMinutes) return false; + + if (mySeconds < a.mySeconds) return true; + if (mySeconds > a.mySeconds) return false; + +// if (mySecondFraction < a.mySecondFraction) return true; +// if (mySecondFraction > a.mySecondFraction) return false; + return false; +} + +bool ATOMDateConstruct::operator>(const ATOMDateConstruct &a) const { + if (myYear > a.myYear) return true; + if (myYear < a.myYear) return false; + + if (myMonth > a.myMonth) return true; + if (myMonth < a.myMonth) return false; + + if (myDay > a.myDay) return true; + if (myDay < a.myDay) return false; + + if (myHour > a.myHour) return true; + if (myHour < a.myHour) return false; + + if (myMinutes > a.myMinutes) return true; + if (myMinutes < a.myMinutes) return false; + + if (mySeconds > a.mySeconds) return true; + if (mySeconds < a.mySeconds) return false; + +// if (mySecondFraction < a.mySecondFraction) return true; +// if (mySecondFraction > a.mySecondFraction) return false; + return false; +} + +void ATOMDateConstruct::makeStringLength(std::string &str, int len) { + const int lendiff = str.length() - len; + if (lendiff > 0) { + str = str.substr(lendiff); + } else { + str = std::string(-lendiff, '0') + str; + } +} + + +std::string ATOMDateConstruct::getDateTime(bool brief) const { + std::string timezone = "Z"; + if (myTZMinutes != 0 || myTZHour != 0) { + int tzminnum = myTZMinutes; + int tzhournum = myTZHour; + char sign; + if (tzhournum == 0) { + sign = (tzminnum >= 0) ? '+' : '-'; + } else { + sign = (tzhournum > 0) ? '+' : '-'; + if (tzhournum > 0 && tzminnum < 0) { + --tzhournum; + tzminnum = 60 + tzminnum; + } else if (tzhournum < 0 && tzminnum > 0) { + ++tzhournum; + tzminnum = 60 - tzminnum; + } + } + std::string tzmin, tzhour; + ZLStringUtil::appendNumber(tzmin, tzminnum < 0 ? -tzminnum : tzminnum); + ZLStringUtil::appendNumber(tzhour, tzhournum < 0 ? -tzhournum : tzhournum); + makeStringLength(tzmin, 2); + makeStringLength(tzhour, 2); + timezone = sign + tzhour + ":" + tzmin; + } + + std::string time; + if (mySecondFraction >= 0.01) { + std::string sfr; + unsigned int sfrnum = (unsigned int) floor(100 * mySecondFraction + 0.5); + ZLStringUtil::appendNumber(sfr, sfrnum); + makeStringLength(sfr, 2); + time = "." + sfr; + } + if (!brief || !time.empty() || mySeconds != 0) { + std::string sec; + ZLStringUtil::appendNumber(sec, mySeconds); + makeStringLength(sec, 2); + time = ":" + sec + time; + } + if (!brief || !time.empty() || myHour != 0 || myMinutes != 0 || timezone != "Z") { + std::string hour, min; + ZLStringUtil::appendNumber(hour, myHour); + ZLStringUtil::appendNumber(min, myMinutes); + makeStringLength(hour, 2); + makeStringLength(min, 2); + time = hour + ":" + min + time; + } + + std::string date; + if (!brief || !time.empty() || myDay != 0) { + std::string day; + ZLStringUtil::appendNumber(day, myDay); + makeStringLength(day, 2); + date = "-" + day; + } + if (!brief || !date.empty() || myMonth != 0) { + std::string month; + ZLStringUtil::appendNumber(month, myMonth); + makeStringLength(month, 2); + date = "-" + month + date; + } + + std::string year; + ZLStringUtil::appendNumber(year, myYear); + makeStringLength(year, 4); + date = year + date; + + if (!brief || !time.empty()) { + date = date + "T" + time + timezone; + } + return date; +} + +bool ATOMDateConstruct::parse(const std::string &str, ATOMDateConstruct &dateTime) { + dateTime.setYear(0); + dateTime.setMonth(0); + dateTime.setDay(0); + dateTime.setHour(0); + dateTime.setMinutes(0); + dateTime.setSeconds(0); + dateTime.setSecondFraction(0); + dateTime.setTZHour(0); + dateTime.setTZMinutes(0); + const int len = str.length(); + if (len != 4 && len != 7 && len != 10 && len != 17 && len != 20 && len < 22) { + return false; + } + int num = 0, sign = 1; + float fnum = 0.0, fmult = 0.1; + int start, end, log; + char ch; + end = 4; start = 0; log = 0; + while (start < len) { + ch = str[start++]; + if (!std::isdigit(ch)) { + return false; + } + num = 10 * num + ((int) (ch - '0')); + fnum += fmult * ((int) (ch - '0')); + fmult *= 0.1; + if (start == end) { + switch (log) { + case 0: dateTime.setYear(num); break; + case 1: dateTime.setMonth(num); break; + case 2: dateTime.setDay(num); break; + case 3: dateTime.setHour(num); break; + case 4: dateTime.setMinutes(num); break; + case 5: dateTime.setSeconds(num); break; + case 6: dateTime.setSecondFraction(fnum); break; + case 7: dateTime.setTZHour(sign * num); break; + case 8: dateTime.setTZMinutes(sign * num); break; + default: return false; + } + num = 0; fnum = 0.0; fmult = 0.1; + if (start == len) return true; + switch (log) { + case 0: + case 1: + if (str[start++] != '-') return false; + end = start + 2; + break; + case 2: + if (str[start++] != 'T') return false; + end = start + 2; + break; + case 3: + case 7: + if (str[start++] != ':') return false; + end = start + 2; + break; + case 4: + ch = str[start++]; + if (ch == ':') { + end = start + 2; + } else if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + log += 2; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + case 5: + ch = str[start++]; + if (ch == '.') { + end = start; + while (std::isdigit(str[++end])) /* NOP */; + } else if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + log += 1; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + case 6: + ch = str[start++]; + if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + //case 8: + default: return false; + } + ++log; + } + } + return false; +} + +long ATOMDateConstruct::getLongSeconds_stupid() { + return ((((((myYear - 2000) * 12 + myMonth) * 31 + myDay) * 24 + myHour) * 60 + myMinutes) * 60 + mySeconds); +} + +void ATOMDateConstruct::setLongSeconds_stupid(long t) { + myYear = t / (12*31*24*60*60) + 2000; + t = t % (12*31*24*60*60); + myMonth = t / (31*24*60*60); + t = t % (31*24*60*60); + myDay = t / (24*60*60); + t = t % (24*60*60); + myHour = t / (60*60); + t = t % (60*60); + myMinutes = t / (60); + t = t % (60); + mySeconds = t; +} diff --git a/reader/src/network/atom/ATOMConstructs.h b/reader/src/network/atom/ATOMConstructs.h new file mode 100644 index 0000000..2497bd4 --- /dev/null +++ b/reader/src/network/atom/ATOMConstructs.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ATOMCONSTRUCTS_H__ +#define __ATOMCONSTRUCTS_H__ + +#include <map> +#include <string> + + +class ATOMCommonAttributes { + +public: + static const std::string XML_BASE; + static const std::string XML_LANG; + +public: + ATOMCommonAttributes(); + virtual ~ATOMCommonAttributes(); + +public: + std::map<std::string, std::string> &attributes() { return myAttributes; } + const std::map<std::string, std::string> &attributes() const { return myAttributes; } + + std::string &base() { return myAttributes[XML_BASE]; } + std::string &lang() { return myAttributes[XML_LANG]; } + + virtual void readAttributes(const std::map<std::string, std::string> &attributes); + + void setUserData(const std::string &key, const std::string &value); + const std::string userData(const std::string &key) const; + +protected: + void readAttribute(const std::string &name, const std::map<std::string, std::string> &attributes); + +private: + std::map<std::string, std::string> myAttributes; + std::map<std::string,std::string> myUserData; +}; + + +class ATOMPersonConstruct : public ATOMCommonAttributes { + +public: + ATOMPersonConstruct(); + ATOMPersonConstruct(const std::string &name); + + const std::string &name() const { return myName; } + const std::string &uri() const { return myUri; } + const std::string &email() const { return myEmail; } + + void setName(const std::string &name) { myName = name; } + void setUri(const std::string &uri) { myUri = uri; } + void setEmail(const std::string &email) { myEmail = email; } + +private: + std::string myName; + std::string myUri; + std::string myEmail; +}; + + +class ATOMDateConstruct : public ATOMCommonAttributes { + +public: + static bool parse(const std::string &str, ATOMDateConstruct &dateTime); + +public: + ATOMDateConstruct(int year); + ATOMDateConstruct(int year, int month, int day); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); + + bool operator <(const ATOMDateConstruct& a) const; + bool operator >(const ATOMDateConstruct& a) const; + + std::string getDateTime(bool brief = false) const; + + int year() const { return myYear; } + int month() const { return myMonth; } + int day() const { return myDay; } + int hour() const { return myHour; } + int minutes() const { return myMinutes; } + int seconds() const { return mySeconds; } + float secondFraction() const { return mySecondFraction; } + int timeZoneHour() const { return myTZHour; } + int timeZoneMinutes() const { return myTZMinutes; } + + void setYear(int year) { myYear = year; } + void setMonth(int month) { myMonth = month; } + void setDay(int day) { myDay = day; } + void setHour(int hour) { myHour = hour; } + void setMinutes(int minutes) { myMinutes = minutes; } + void setSeconds(int seconds) { mySeconds = seconds; } + void setSecondFraction(float sfract) { mySecondFraction = sfract; } + void setTZHour(int tzhour) { myTZHour = tzhour; } + void setTZMinutes(int tzminutes) { myTZMinutes = tzminutes; } + + long getLongSeconds_stupid(); + void setLongSeconds_stupid(long t); + +private: + static void makeStringLength(std::string &str, int len); + +private: + int myYear; + int myMonth; + int myDay; + int myHour; + int myMinutes; + int mySeconds; + float mySecondFraction; + int myTZHour; + int myTZMinutes; +}; + + +#endif /* __ATOMCONSTRUCTS_H__ */ diff --git a/reader/src/network/atom/ATOMContainers.cpp b/reader/src/network/atom/ATOMContainers.cpp new file mode 100644 index 0000000..fb05c10 --- /dev/null +++ b/reader/src/network/atom/ATOMContainers.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "ATOMContainers.h" + +ATOMEntry::ATOMEntry() { +} + +ATOMEntry::ATOMEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + myId(id), myTitle(title), myUpdated(updated) { +} + + + +ATOMFeedMetadata::ATOMFeedMetadata() { +} + +ATOMFeedMetadata::ATOMFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + myId(id), myTitle(title), myUpdated(updated) { +} + + + +/* +ATOMFeed::ATOMFeed() { +} + +ATOMFeed::ATOMFeed(const ATOMId &id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMFeedMatadata(id, title, updated) { +} +*/ + + diff --git a/reader/src/network/atom/ATOMContainers.h b/reader/src/network/atom/ATOMContainers.h new file mode 100644 index 0000000..1fb3f92 --- /dev/null +++ b/reader/src/network/atom/ATOMContainers.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ATOMCONTAINTERS_H__ +#define __ATOMCONTAINTERS_H__ + +#include <vector> + +#include <shared_ptr.h> + +#include "ATOMMetadata.h" + + + +class ATOMEntry : public ATOMCommonAttributes { + +public: + ATOMEntry(); + ATOMEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMAuthor> > &authors() { return myAuthors; } + std::vector<shared_ptr<ATOMCategory> > &categories() { return myCategories; } + std::vector<shared_ptr<ATOMContributor> > &contributors() { return myContributors; } + std::vector<shared_ptr<ATOMLink> > &links() { return myLinks; } + + shared_ptr<ATOMPublished> published() { return myPublished; } + shared_ptr<ATOMIcon> icon() { return myIcon; } + const std::string &rights() { return myRights; } + const std::string &summary() { return mySummary; } + const std::string &title() { return myTitle; } + shared_ptr<ATOMUpdated> updated() { return myUpdated; } + + void setPublished(shared_ptr<ATOMPublished> published) { myPublished = published; } + void setIcon(shared_ptr<ATOMIcon> icon) { myIcon = icon; } + void setRights(const std::string &rights) { myRights = rights; } + void setSummary(const std::string &summary) { mySummary = summary; } + void setTitle(const std::string &title) { myTitle = title; } + void setUpdated(shared_ptr<ATOMUpdated> updated) { myUpdated = updated; } + + shared_ptr<ATOMId> id() { return myId; } + void setId(shared_ptr<ATOMId> id) { myId = id; } + +private: + shared_ptr<ATOMId> myId; + + std::vector<shared_ptr<ATOMAuthor> > myAuthors; + std::vector<shared_ptr<ATOMCategory> > myCategories; + //shared_ptr<ATOMContent> myContent; TODO: implement ATOMContent + std::vector<shared_ptr<ATOMContributor> > myContributors; + std::vector<shared_ptr<ATOMLink> > myLinks; + shared_ptr<ATOMIcon> myIcon; + shared_ptr<ATOMPublished> myPublished; + std::string myRights; // TODO: implement ATOMTextConstruct + //shared_ptr<ATOMSource> mySource; // TODO: implement ATOMSource + std::string mySummary; // TODO: implement ATOMTextConstruct + std::string myTitle; // TODO: implement ATOMTextConstruct + shared_ptr<ATOMUpdated> myUpdated; +}; + + +class ATOMFeedMetadata : public ATOMCommonAttributes { + +public: + ATOMFeedMetadata(); + ATOMFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMAuthor> > &authors() { return myAuthors; } + std::vector<shared_ptr<ATOMCategory> > &categories() { return myCategories; } + std::vector<shared_ptr<ATOMContributor> > &contributors() { return myContributors; } + std::vector<shared_ptr<ATOMLink> > &links() { return myLinks; } + + shared_ptr<ATOMGenerator> generator() { return myGenerator; } + shared_ptr<ATOMIcon> icon() { return myIcon; } + shared_ptr<ATOMLogo> logo() { return myLogo; } + const std::string &rights() { return myRights; } + const std::string &subtitle() { return mySubtitle; } + const std::string &summary() { return mySummary; } + const std::string &title() { return myTitle; } + shared_ptr<ATOMUpdated> updated() { return myUpdated; } + + void setGenerator(shared_ptr<ATOMGenerator> generator) { myGenerator = generator; } + void setIcon(shared_ptr<ATOMIcon> icon) { myIcon = icon; } + void setLogo(shared_ptr<ATOMLogo> logo) { myLogo = logo; } + void setRights(const std::string &rights) { myRights = rights; } + void setSubtitle(const std::string &subtitle) { mySubtitle = subtitle; } + void setSummary(const std::string &summary) { mySummary = summary; } + void setTitle(const std::string &title) { myTitle = title; } + void setUpdated(shared_ptr<ATOMUpdated> updated) { myUpdated = updated; } + + shared_ptr<ATOMId> id() { return myId; } + void setId(shared_ptr<ATOMId> id) { myId = id; } + +private: + shared_ptr<ATOMId> myId; + + std::vector<shared_ptr<ATOMAuthor> > myAuthors; + std::vector<shared_ptr<ATOMCategory> > myCategories; + std::vector<shared_ptr<ATOMContributor> > myContributors; + shared_ptr<ATOMGenerator> myGenerator; + shared_ptr<ATOMIcon> myIcon; + std::vector<shared_ptr<ATOMLink> > myLinks; + shared_ptr<ATOMLogo> myLogo; + std::string myRights; // TODO: implement ATOMTextConstruct + std::string mySubtitle; // TODO: implement ATOMTextConstruct + std::string mySummary; // TODO: implement ATOMTextConstruct + std::string myTitle; // TODO: implement ATOMTextConstruct + shared_ptr<ATOMUpdated> myUpdated; +}; + + +/* +class ATOMFeed : public ATOMFeedMetadata { + +public: + ATOMFeed(); + ATOMFeed(const ATOMId &id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMEntry> > entries() { return myEntries; } + +private: + std::vector<shared_ptr<ATOMEntry> > myEntries; +}; +*/ + + +#endif /* __ATOMCONTAINTERS_H__ */ diff --git a/reader/src/network/atom/ATOMMetadata.cpp b/reader/src/network/atom/ATOMMetadata.cpp new file mode 100644 index 0000000..cb81e0e --- /dev/null +++ b/reader/src/network/atom/ATOMMetadata.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "ATOMMetadata.h" + + +const std::string ATOMConstants::TYPE_TEXT = "text"; +const std::string ATOMConstants::TYPE_HTML = "html"; +const std::string ATOMConstants::TYPE_XHTML = "xhtml"; + +const std::string ATOMConstants::TYPE_DEFAULT = TYPE_TEXT; + +const std::string ATOMConstants::REL_ALTERNATE = "alternate"; +const std::string ATOMConstants::REL_RELATED = "related"; +const std::string ATOMConstants::REL_SELF = "self"; +const std::string ATOMConstants::REL_ENCLOSURE = "enclosure"; +const std::string ATOMConstants::REL_VIA = "via"; + + + +const std::string ATOMCategory::TERM = "term"; +const std::string ATOMCategory::SCHEME = "scheme"; +const std::string ATOMCategory::LABEL = "label"; + +const std::string ATOMGenerator::URI = "uri"; +const std::string ATOMGenerator::VERSION_ATT = "version"; + +const std::string ATOMLink::HREF = "href"; +const std::string ATOMLink::REL = "rel"; +const std::string ATOMLink::TYPE = "type"; +const std::string ATOMLink::HREFLANG = "hreflang"; +const std::string ATOMLink::TITLE = "title"; +const std::string ATOMLink::LENGTH = "length"; + + + +ATOMAuthor::ATOMAuthor() { +} + +ATOMAuthor::ATOMAuthor(const std::string &name) : ATOMPersonConstruct(name) { +} + + + +ATOMCategory::ATOMCategory() { +} + +ATOMCategory::ATOMCategory(const std::string &termStr) { + term() = termStr; +} + +void ATOMCategory::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(TERM, attributes); + readAttribute(SCHEME, attributes); + readAttribute(LABEL, attributes); +} + + + +ATOMContributor::ATOMContributor() { +} + +ATOMContributor::ATOMContributor(const std::string &name) : ATOMPersonConstruct(name) { +} + + + +ATOMGenerator::ATOMGenerator() { +} + +ATOMGenerator::ATOMGenerator(const std::string &text) : myText(text) { +} + +void ATOMGenerator::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(URI, attributes); + readAttribute(VERSION_ATT, attributes); +} + + + +ATOMIcon::ATOMIcon() { +} + +ATOMIcon::ATOMIcon(const std::string &uri) : myUri(uri) { +} + + + +ATOMId::ATOMId() { +} + +ATOMId::ATOMId(const std::string &uri) : myUri(uri) { +} + + + +ATOMLink::ATOMLink() { +} + +ATOMLink::ATOMLink(const std::string &hrefStr) { + href() = hrefStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr) { + href() = hrefStr; + rel() = relStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr){ + href() = hrefStr; + rel() = relStr; + type() = typeStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr, const std::string &titleStr) { + href() = hrefStr; + rel() = relStr; + type() = typeStr; + title() = titleStr; +} + +void ATOMLink::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(HREF, attributes); + readAttribute(REL, attributes); + readAttribute(TYPE, attributes); + readAttribute(HREFLANG, attributes); + readAttribute(TITLE, attributes); + readAttribute(LENGTH, attributes); +} + +ATOMLogo::ATOMLogo() { +} + +ATOMLogo::ATOMLogo(const std::string &uri) : myUri(uri) { +} + + + +ATOMPublished::ATOMPublished() : ATOMDateConstruct(0) { +} + +ATOMPublished::ATOMPublished(int year) : ATOMDateConstruct(year) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day) : ATOMDateConstruct(year, month, day) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + + + +ATOMUpdated::ATOMUpdated() : ATOMDateConstruct(0) { +} + +ATOMUpdated::ATOMUpdated(int year) : ATOMDateConstruct(year) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day) : ATOMDateConstruct(year, month, day) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + + diff --git a/reader/src/network/atom/ATOMMetadata.h b/reader/src/network/atom/ATOMMetadata.h new file mode 100644 index 0000000..3fb7619 --- /dev/null +++ b/reader/src/network/atom/ATOMMetadata.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ATOMMETADATA_H__ +#define __ATOMMETADATA_H__ + +#include "ATOMConstructs.h" + + +class ATOMConstants { + +private: + ATOMConstants(); + +public: + static const std::string TYPE_TEXT; + static const std::string TYPE_HTML; + static const std::string TYPE_XHTML; + static const std::string TYPE_DEFAULT; + + static const std::string REL_ALTERNATE; + static const std::string REL_RELATED; + static const std::string REL_SELF; + static const std::string REL_ENCLOSURE; + static const std::string REL_VIA; +}; + + + + + +class ATOMAuthor : public ATOMPersonConstruct { + +public: + ATOMAuthor(); + ATOMAuthor(const std::string &name); +}; + + + +class ATOMCategory : public ATOMCommonAttributes { + +public: + static const std::string TERM; + static const std::string SCHEME; + static const std::string LABEL; + +public: + ATOMCategory(); + ATOMCategory(const std::string &termStr); + +public: + std::string &term() { return attributes()[TERM]; } + std::string &scheme() { return attributes()[SCHEME]; } + std::string &label() { return attributes()[LABEL]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); +}; + + + +class ATOMContributor : public ATOMPersonConstruct { + +public: + ATOMContributor(); + ATOMContributor(const std::string &name); +}; + + + +class ATOMGenerator : public ATOMCommonAttributes { + +public: + static const std::string URI; + static const std::string VERSION_ATT; + +public: + ATOMGenerator(); + ATOMGenerator(const std::string &text); + +public: + const std::string &text() const { return myText; } + void setText(const std::string &text) { myText = text; } + + std::string &uri() { return attributes()[URI]; } + std::string &version() { return attributes()[VERSION_ATT]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); + +private: + std::string myText; +}; + + + +class ATOMIcon : public ATOMCommonAttributes { + +public: + ATOMIcon(); + ATOMIcon(const std::string &uri); + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + + + +class ATOMId : public ATOMCommonAttributes { + +public: + ATOMId(); + ATOMId(const std::string &uri); + + const ATOMId &operator = (const ATOMId &id); + + bool operator == (const ATOMId &id) const; + bool operator != (const ATOMId &id) const; + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + +inline const ATOMId &ATOMId::operator = (const ATOMId &id) { myUri = id.myUri; return *this; } +inline bool ATOMId::operator == (const ATOMId &id) const { return myUri == id.myUri; } +inline bool ATOMId::operator != (const ATOMId &id) const { return myUri != id.myUri; } + + + +class ATOMLink : public ATOMCommonAttributes { + +public: + static const std::string HREF; + static const std::string REL; + static const std::string TYPE; + static const std::string HREFLANG; + static const std::string TITLE; + static const std::string LENGTH; + +public: + ATOMLink(); + ATOMLink(const std::string &hrefStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr, const std::string &titleStr); + +public: + std::string &href() { return attributes()[HREF]; } + std::string &rel() { return attributes()[REL]; } + std::string &type() { return attributes()[TYPE]; } + std::string &hreflang() { return attributes()[HREFLANG]; } + std::string &title() { return attributes()[TITLE]; } + std::string &length() { return attributes()[LENGTH]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); +}; + + + +class ATOMLogo : public ATOMCommonAttributes { + +public: + ATOMLogo(); + ATOMLogo(const std::string &uri); + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + + +class ATOMPublished : public ATOMDateConstruct { + +public: + ATOMPublished(); + ATOMPublished(int year); + ATOMPublished(int year, int month, int day); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + +class ATOMUpdated : public ATOMDateConstruct { + +public: + ATOMUpdated(); + ATOMUpdated(int year); + ATOMUpdated(int year, int month, int day); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + + +#endif /* ATOMMETADATA */ diff --git a/reader/src/network/authentication/NetworkAuthenticationManager.cpp b/reader/src/network/authentication/NetworkAuthenticationManager.cpp new file mode 100644 index 0000000..137388f --- /dev/null +++ b/reader/src/network/authentication/NetworkAuthenticationManager.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkAuthenticationManager.h" + +#include "../NetworkLink.h" +#include "../NetworkErrors.h" + +NetworkAuthenticationManager::NetworkAuthenticationManager(const NetworkLink &link) : + Link(link), + UserNameOption(ZLCategoryKey::NETWORK, link.getSiteName(), "userName", ""), + SkipIPOption(ZLCategoryKey::NETWORK, link.getSiteName(), "skipIP", true) { +} + +NetworkAuthenticationManager::~NetworkAuthenticationManager() { +} + +bool NetworkAuthenticationManager::needsInitialization() { + return false; +} + +std::string NetworkAuthenticationManager::initialize(shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} + +bool NetworkAuthenticationManager::needPurchase(const NetworkBookItem &) { + return true; +} + +std::string NetworkAuthenticationManager::purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener) { + std::string error = NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); + listener->finished(error); + return error; +} + + +std::string NetworkAuthenticationManager::topupAccountLink() { + return ""; +} + +std::string NetworkAuthenticationManager::currentAccount() { + return ""; +} + +bool NetworkAuthenticationManager::skipIPSupported() { + return false; +} + +bool NetworkAuthenticationManager::registrationSupported() { + return false; +} + +std::string NetworkAuthenticationManager::registerUser(const std::string &, const std::string &, const std::string &) { + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} + +bool NetworkAuthenticationManager::passwordRecoverySupported() { + return false; +} + +std::string NetworkAuthenticationManager::recoverPassword(const std::string &) { + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} diff --git a/reader/src/network/authentication/NetworkAuthenticationManager.h b/reader/src/network/authentication/NetworkAuthenticationManager.h new file mode 100644 index 0000000..75ae9dd --- /dev/null +++ b/reader/src/network/authentication/NetworkAuthenticationManager.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKAUTHENTICATIONMANAGER_H__ +#define __NETWORKAUTHENTICATIONMANAGER_H__ + +#include <shared_ptr.h> +#include <ZLOptions.h> +#include <ZLBoolean3.h> + +#include "../NetworkItems.h" +#include "../BookReference.h" + +class NetworkLink; + +class NetworkAuthenticationManager { + +public: + NetworkAuthenticationManager(const NetworkLink &link); + virtual ~NetworkAuthenticationManager(); + +public: + const NetworkLink &Link; + ZLStringOption UserNameOption; + ZLBooleanOption SkipIPOption; + +public: + struct AuthenticationStatus { + const ZLBoolean3 Status; + const std::string Message; + + AuthenticationStatus(bool status); + AuthenticationStatus(const std::string &msg); + }; + + virtual AuthenticationStatus isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener = 0) = 0; + virtual std::string authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener) = 0; // returns error message + virtual void logOut() = 0; + + virtual bool skipIPSupported(); + + virtual shared_ptr<BookReference> downloadReference(const NetworkBookItem &book) = 0; + +public: // Account specific methods (can be called only if authorised!!!) + virtual const std::string ¤tUserName() = 0; + virtual bool needsInitialization(); + virtual std::string initialize(shared_ptr<ZLNetworkRequest::Listener> listener); // returns error message + virtual bool needPurchase(const NetworkBookItem &book); // returns true if link must be purchased before downloading + virtual std::string purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener); // returns error message + + virtual std::string topupAccountLink(); + virtual std::string currentAccount(); + + virtual const NetworkItem::List &purchasedBooks() const = 0; + +public: // new User Registration + virtual bool registrationSupported(); + virtual std::string registerUser(const std::string &login, const std::string &password, const std::string &email); + +public: // Password Recovery + virtual bool passwordRecoverySupported(); + virtual std::string recoverPassword(const std::string &email); + +private: // disable copying + NetworkAuthenticationManager(const NetworkAuthenticationManager &); + const NetworkAuthenticationManager &operator = (const NetworkAuthenticationManager &); +}; + +inline NetworkAuthenticationManager::AuthenticationStatus::AuthenticationStatus(bool status) : Status(status ? B3_TRUE : B3_FALSE) {} +inline NetworkAuthenticationManager::AuthenticationStatus::AuthenticationStatus(const std::string &msg) : Status(B3_UNDEFINED), Message(msg) {} + +#endif /* __NETWORKAUTHENTICATIONMANAGER_H__ */ diff --git a/reader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp b/reader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp new file mode 100644 index 0000000..b1b6c69 --- /dev/null +++ b/reader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LitResAuthenticationDataParser.h" + + +static const std::string TAG_AUTHORIZATION_OK = "catalit-authorization-ok"; +static const std::string TAG_AUTHORIZATION_FAILED = "catalit-authorization-failed"; + +static const std::string TAG_PURCHASE_OK = "catalit-purchase-ok"; +static const std::string TAG_PURCHASE_FAILED = "catalit-purchase-failed"; + +static const std::string TAG_DOWNLOAD_FAILED = "catalit-download-failed"; + +static const std::string TAG_REGISTRATION_FAILED = "catalit-registration-failed"; + +static const std::string TAG_PASSWORD_RECOVERY_OK = "catalit-pass-recover-ok"; +static const std::string TAG_PASSWORD_RECOVERY_FAILED = "catalit-pass-recover-failed"; + +LitResAuthenticationDataParser::LitResAuthenticationDataParser() { +} + +void LitResAuthenticationDataParser::startElementHandler(const char *tag, const char **attributes) { + myAttributes.clear(); + while (*attributes != 0) { + std::string name(*attributes++); + if (*attributes == 0) { + break; + } + std::string value(*attributes++); + myAttributes.insert(std::make_pair(name, value)); + } + processTag(tag); +} + + + + + +LitResLoginDataParser::LitResLoginDataParser(std::string &firstName, std::string &lastName, std::string &sid) : + myFirstName(firstName), myLastName(lastName), mySid(sid) { +} + +void LitResLoginDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else if (TAG_AUTHORIZATION_OK == tag) { + myFirstName = attributes()["first-name"]; + myLastName = attributes()["first-name"]; + mySid = attributes()["sid"]; + } +} + + +LitResPurchaseDataParser::LitResPurchaseDataParser(std::string &account, std::string &bookId) : + myAccount(account), myBookId(bookId) { +} + +void LitResPurchaseDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else { + myAccount = attributes()["account"]; + myBookId = attributes()["art"]; + if (TAG_PURCHASE_OK == tag) { + // nop + } else if (TAG_PURCHASE_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_NOT_ENOUGH_MONEY); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_MISSING_BOOK); + } else if ("3" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } + } +} + + +/*LitResDownloadErrorDataParser::LitResDownloadErrorDataParser() { +} + +void LitResDownloadErrorDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else { + if (TAG_DOWNLOAD_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_BOOK_NOT_PURCHASED); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_DOWNLOAD_LIMIT_EXCEEDED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } + } +}*/ + + +LitResRegisterUserDataParser::LitResRegisterUserDataParser(std::string &sid) : mySid(sid) { +} + +void LitResRegisterUserDataParser::processTag(const std::string &tag) { + if (TAG_REGISTRATION_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_LOGIN_ALREADY_TAKEN); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_LOGIN_WAS_NOT_SPECIFIED); + } else if ("3" == error) { + setErrorCode(NetworkErrors::ERROR_PASSWORD_WAS_NOT_SPECIFIED); + } else if ("4" == error) { + setErrorCode(NetworkErrors::ERROR_INVALID_EMAIL); + } else if ("5" == error) { + setErrorCode(NetworkErrors::ERROR_TOO_MANY_REGISTRATIONS); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } else if (TAG_AUTHORIZATION_OK == tag) { + mySid = attributes()["sid"]; + } +} + + +void LitResPasswordRecoveryDataParser::processTag(const std::string &tag) { + if (TAG_PASSWORD_RECOVERY_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_NO_USER_EMAIL); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } else if (TAG_PASSWORD_RECOVERY_OK == tag) { + // NOP + } +} diff --git a/reader/src/network/authentication/litres/LitResAuthenticationDataParser.h b/reader/src/network/authentication/litres/LitResAuthenticationDataParser.h new file mode 100644 index 0000000..60baa02 --- /dev/null +++ b/reader/src/network/authentication/litres/LitResAuthenticationDataParser.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESAUTHENTICATIONDATAPARSER_H__ +#define __LITRESAUTHENTICATIONDATAPARSER_H__ + +#include <ZLXMLReader.h> + +#include "../../NetworkErrors.h" + + +class LitResAuthenticationDataParser : public ZLXMLReader { + +public: + LitResAuthenticationDataParser(); + +private: + void startElementHandler(const char *tag, const char **attributes); + +protected: + void setErrorCode(const std::string &msg); + std::map<std::string, std::string> &attributes(); + + virtual void processTag(const std::string &tag) = 0; + +private: + std::map<std::string, std::string> myAttributes; +}; + +inline void LitResAuthenticationDataParser::setErrorCode(const std::string &msg) { setErrorMessage(NetworkErrors::errorMessage(msg)); } +inline std::map<std::string, std::string> &LitResAuthenticationDataParser::attributes() { return myAttributes; } + + +class LitResLoginDataParser : public LitResAuthenticationDataParser { + +public: + LitResLoginDataParser(std::string &firstName, std::string &lastName, std::string &sid); + +private: + void processTag(const std::string &tag); + +private: + std::string &myFirstName; + std::string &myLastName; + std::string &mySid; +}; + + +class LitResPurchaseDataParser : public LitResAuthenticationDataParser { + +public: + LitResPurchaseDataParser(std::string &account, std::string &bookId); + +private: + void processTag(const std::string &tag); + +private: + std::string &myAccount; + std::string &myBookId; +}; + + +/*class LitResDownloadErrorDataParser : public LitResAuthenticationDataParser { + +public: + LitResDownloadErrorDataParser(); + +private: + void processTag(const std::string &tag); + +};*/ + +class LitResRegisterUserDataParser : public LitResAuthenticationDataParser { + +public: + LitResRegisterUserDataParser(std::string &sid); + +private: + void processTag(const std::string &tag); + +private: + std::string &mySid; +}; + +class LitResPasswordRecoveryDataParser : public LitResAuthenticationDataParser { + +private: + void processTag(const std::string &tag); +}; + +#endif /* __LITRESAUTHENTICATIONDATAPARSER_H__ */ diff --git a/reader/src/network/authentication/litres/LitResAuthenticationManager.cpp b/reader/src/network/authentication/litres/LitResAuthenticationManager.cpp new file mode 100644 index 0000000..e552b5c --- /dev/null +++ b/reader/src/network/authentication/litres/LitResAuthenticationManager.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> +#include <ZLUserData.h> +#include <ZLExecutionUtil.h> + +#include "../../tree/NetworkLibrary.h" + +#include "../../litres/LitResBooksFeedParser.h" +#include "../../litres/LitResUtil.h" +#include "LitResAuthenticationManager.h" +#include "LitResAuthenticationDataParser.h" + +#include "../../NetworkErrors.h" +#include "../../NetworkLink.h" +#include "../../NetworkLinkCollection.h" + +LitResAuthenticationManager::LitResAuthenticationManager(const NetworkLink &link) : + NetworkAuthenticationManager(link), + mySidChecked(false), + mySidUserNameOption(ZLCategoryKey::NETWORK, link.getSiteName(), "sidUserName", ""), + mySidOption(ZLCategoryKey::NETWORK, link.getSiteName(), "sid", "") +{ +} + +class LitResAuthorisationScope : public ZLUserData { +public: + std::string firstName; + std::string lastName; + std::string newSid; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +NetworkAuthenticationManager::AuthenticationStatus LitResAuthenticationManager::isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener) { + const bool useNetwork = !listener.isNull(); + bool authState = !mySidUserNameOption.value().empty() && !mySidOption.value().empty(); + if (mySidChecked || !useNetwork) { + if (!listener.isNull()) + listener->finished(authState ? std::string() : "Not authorised"); + return AuthenticationStatus(authState); + } + + if (!authState) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + listener->finished("Not authorised"); + return AuthenticationStatus(false); + } + + LitResAuthorisationScope *scope = new LitResAuthorisationScope; + scope->listener = listener; + shared_ptr<ZLXMLReader> xmlReader = new LitResLoginDataParser(scope->firstName, scope->lastName, scope->newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_IN); + ZLNetworkUtil::appendParameter(url, "sid", mySidOption.value()); + + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest(url, xmlReader); + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onAuthorised)); + ZLNetworkManager::Instance().performAsync(networkData); + return AuthenticationStatus(std::string()); +} + +std::string LitResAuthenticationManager::authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener) { + LitResAuthorisationScope *scope = new LitResAuthorisationScope; + scope->listener = listener; + shared_ptr<ZLXMLReader> xmlReader = new LitResLoginDataParser(scope->firstName, scope->lastName, scope->newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_IN); + ZLNetworkUtil::appendParameter(url, "login", UserNameOption.value()); + ZLNetworkUtil::appendParameter(url, "pwd", pwd); + ZLNetworkUtil::appendParameter(url, "skip_ip", "1"); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, + xmlReader + ); + + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onAuthorised)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onAuthorised(ZLUserDataHolder &data, const std::string &error) { + LitResAuthorisationScope &scope = static_cast<LitResAuthorisationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + mySidChecked = true; + if (!error.empty()) { + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + } else { + mySidOption.setValue(scope.newSid); + mySidUserNameOption.setValue(UserNameOption.value()); + } + + scope.listener->finished(error); +} + + +void LitResAuthenticationManager::logOut() { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + + myInitializedDataSid.clear(); + myPurchasedBooksIds.clear(); + myPurchasedBooksList.clear(); + myAccount.clear(); +} + +const std::string &LitResAuthenticationManager::currentUserName() { + return mySidUserNameOption.value(); +} + +bool LitResAuthenticationManager::needPurchase(const NetworkBookItem &book) { + return myPurchasedBooksIds.count(book.Id) == 0; +} + +class LitResPurchaseBookScope : public ZLUserData { +public: + std::string account; + std::string bookId; + const NetworkBookItem *book; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +std::string LitResAuthenticationManager::purchaseBook(const NetworkBookItem &book, shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + std::string error; + if (sid.empty()) { + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + + shared_ptr<BookReference> reference = book.reference(BookReference::BUY); + if (reference.isNull()) { + // TODO: add correct error message + error = "Oh, that's impossible"; + listener->finished(error); + return error; + } + std::string query = reference->URL; + ZLNetworkUtil::appendParameter(query, "sid", sid); + + LitResPurchaseBookScope *scope = new LitResPurchaseBookScope; + scope->book = &book; + scope->listener = listener; + + shared_ptr<ZLXMLReader> xmlReader = new LitResPurchaseDataParser(scope->account, scope->bookId); + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest(query, xmlReader); + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBookPurchased)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onBookPurchased(ZLUserDataHolder &data, const std::string &error) { + LitResPurchaseBookScope &scope = static_cast<LitResPurchaseBookScope&>(*data.getUserData("scope")); + shared_ptr<ZLNetworkRequest::Listener> listener = scope.listener; + if (!scope.account.empty()) { + myAccount = BuyBookReference::price(scope.account, "RUB"); + } + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + } + const std::string alreadyPurchasedError = NetworkErrors::errorMessage(NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED); + if (error != alreadyPurchasedError) { + if (!error.empty()) { + listener->finished(error); + return; + } + if (scope.bookId != scope.book->Id) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_SOMETHING_WRONG, Link.getSiteName())); + return; + } + } + myPurchasedBooksIds.insert(scope.book->Id); + myPurchasedBooksList.push_back(new NetworkBookItem(*scope.book, 0)); + listener->finished(error); +} + +shared_ptr<BookReference> LitResAuthenticationManager::downloadReference(const NetworkBookItem &book) { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return 0; + } + shared_ptr<BookReference> reference = + book.reference(BookReference::DOWNLOAD_FULL_CONDITIONAL); + if (reference.isNull()) { + return 0; + } + std::string url = reference->URL; + ZLNetworkUtil::appendParameter(url, "sid", sid); + return new DecoratedBookReference(*reference, url); +} + +void LitResAuthenticationManager::collectPurchasedBooks(NetworkItem::List &list) { + list.assign(myPurchasedBooksList.begin(), myPurchasedBooksList.end()); +} + +const std::set<std::string> &LitResAuthenticationManager::getPurchasedIds() const { + return myPurchasedBooksIds; +} + +const NetworkItem::List &LitResAuthenticationManager::purchasedBooks() const { + return myPurchasedBooksList; +} + +std::string LitResAuthenticationManager::topupAccountLink() { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return std::string(); + } + std::string url = Link.url(NetworkLink::URL_TOPUP); + ZLNetworkUtil::appendParameter(url, "sid", sid); + return url; +} + +std::string LitResAuthenticationManager::currentAccount() { + return myAccount; +} + +bool LitResAuthenticationManager::needsInitialization() { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return false; + } + return sid != myInitializedDataSid; +} + +class LitResInitializationScope : public ZLUserData { +public: + std::string dummy; + std::string error; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +std::string LitResAuthenticationManager::initialize(shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } + if (sid == myInitializedDataSid) { + listener->finished(std::string()); + return std::string(); + } + + LitResInitializationScope *scope = new LitResInitializationScope; + scope->listener = listener; + + shared_ptr<ZLNetworkRequest> request = loadPurchasedBooks(myPurchasedBooksIds, myPurchasedBooksList); + request->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBooksLoaded)); + return ZLNetworkManager::Instance().performAsync(request); +} + +void LitResAuthenticationManager::onBooksLoaded(ZLUserDataHolder &data, const std::string &error) { + LitResInitializationScope &scope = static_cast<LitResInitializationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + scope.error = error; + shared_ptr<ZLNetworkRequest> request = loadAccount(scope.dummy); + request->setListener(ZLExecutionUtil::createListener(new ZLUserDataHolder(data), this, &LitResAuthenticationManager::onAccountReceived)); + ZLNetworkManager::Instance().performAsync(request); +} + +void LitResAuthenticationManager::onAccountReceived(ZLUserDataHolder &data, const std::string &error) { + LitResInitializationScope &scope = static_cast<LitResInitializationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + if (!error.empty() && !scope.error.empty()) { + scope.error.append("\n").append(error); + } else if (!error.empty()) { + scope.error = error; + } + if (!scope.error.empty()) { + myInitializedDataSid.clear(); + loadPurchasedBooksOnError(myPurchasedBooksIds, myPurchasedBooksList); + loadAccountOnError(); + scope.listener->finished(scope.error); + return; + } + myInitializedDataSid = mySidOption.value(); + loadPurchasedBooksOnSuccess(myPurchasedBooksIds, myPurchasedBooksList); + loadAccountOnSuccess(); + scope.listener->finished(); +} + +shared_ptr<ZLNetworkRequest> LitResAuthenticationManager::loadPurchasedBooks(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + const std::string &sid = mySidOption.value(); + purchasedBooksIds.clear(); + purchasedBooksList.clear(); + + std::string query; + ZLNetworkUtil::appendParameter(query, "my", "1"); + ZLNetworkUtil::appendParameter(query, "sid", sid); + + return ZLNetworkManager::Instance().createXMLParserRequest( + LitResUtil::url(Link, "pages/catalit_browser/" + query), + new LitResBooksFeedParser(Link, purchasedBooksList) + ); +} + +void LitResAuthenticationManager::loadPurchasedBooksOnError(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + purchasedBooksIds.clear(); + purchasedBooksList.clear(); +} + +void LitResAuthenticationManager::loadPurchasedBooksOnSuccess(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + for (NetworkItem::List::iterator it = purchasedBooksList.begin(); it != purchasedBooksList.end(); ++it) { + NetworkBookItem &book = (NetworkBookItem&)**it; + book.Index = 0; + purchasedBooksIds.insert(book.Id); + } + + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + +shared_ptr<ZLNetworkRequest> LitResAuthenticationManager::loadAccount(std::string &dummy1) { + const std::string &sid = mySidOption.value(); + + myAccount.clear(); + + std::string query; + ZLNetworkUtil::appendParameter(query, "sid", sid); + ZLNetworkUtil::appendParameter(query, "art", "0"); + + return ZLNetworkManager::Instance().createXMLParserRequest( + LitResUtil::url(Link, "pages/purchase_book/" + query), + new LitResPurchaseDataParser(myAccount, dummy1) + ); +} + +void LitResAuthenticationManager::loadAccountOnError() { + myAccount.clear(); +} + +void LitResAuthenticationManager::loadAccountOnSuccess() { + myAccount = BuyBookReference::price(myAccount, "RUB"); +} + +bool LitResAuthenticationManager::skipIPSupported() { + return true; +} + +bool LitResAuthenticationManager::registrationSupported() { + return true; +} + +std::string LitResAuthenticationManager::registerUser(const std::string &login, const std::string &password, const std::string &email) { + std::string newSid; + shared_ptr<ZLXMLReader> xmlReader = new LitResRegisterUserDataParser(newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_UP); + ZLNetworkUtil::appendParameter(url, "new_login", login); + ZLNetworkUtil::appendParameter(url, "new_pwd1", password); + ZLNetworkUtil::appendParameter(url, "mail", email); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, xmlReader + ); + std::string error = ZLNetworkManager::Instance().perform(networkData); + + mySidChecked = true; + if (!error.empty()) { + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + return error; + } + mySidOption.setValue(newSid); + mySidUserNameOption.setValue(login); + return ""; +} + +bool LitResAuthenticationManager::passwordRecoverySupported() { + return true; +} + +std::string LitResAuthenticationManager::recoverPassword(const std::string &email) { + std::string url = Link.url(NetworkLink::URL_RECOVER_PASSWORD); + ZLNetworkUtil::appendParameter(url, "mail", email); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, new LitResPasswordRecoveryDataParser() + ); + return ZLNetworkManager::Instance().perform(networkData); +} + +class LitResReloadPurchasedBooksScope : public ZLUserData { +public: + std::set<std::string> purchasedBooksIds; + NetworkItem::List purchasedBooksList; + shared_ptr<ZLNetworkRequest::Listener> Listener; +}; + +std::string LitResAuthenticationManager::reloadPurchasedBooks(shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + std::string error; + if (sid.empty()) { + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + if (sid != myInitializedDataSid) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + + LitResReloadPurchasedBooksScope *scope = new LitResReloadPurchasedBooksScope; + shared_ptr<ZLNetworkRequest> networkData = loadPurchasedBooks(scope->purchasedBooksIds, scope->purchasedBooksList); + scope->Listener = listener; + + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBooksReloaded)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onBooksReloaded(ZLUserDataHolder &data, const std::string &error) { + LitResReloadPurchasedBooksScope &scope = static_cast<LitResReloadPurchasedBooksScope&>(*data.getUserData("scope")); + shared_ptr<ZLNetworkRequest::Listener> listener = scope.Listener; + if (!error.empty()) { + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + logOut(); //should it logOut in this case? + } + listener->finished(error); + return; + } + loadPurchasedBooksOnSuccess(scope.purchasedBooksIds, scope.purchasedBooksList); + myPurchasedBooksIds = scope.purchasedBooksIds; + myPurchasedBooksList = scope.purchasedBooksList; + listener->finished(std::string()); +} + diff --git a/reader/src/network/authentication/litres/LitResAuthenticationManager.h b/reader/src/network/authentication/litres/LitResAuthenticationManager.h new file mode 100644 index 0000000..6aefa6d --- /dev/null +++ b/reader/src/network/authentication/litres/LitResAuthenticationManager.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESAUTHENTICATIONMANAGER_H__ +#define __LITRESAUTHENTICATIONMANAGER_H__ + +#include <set> + +#include <ZLNetworkRequest.h> +#include <ZLUserData.h> + +#include "../NetworkAuthenticationManager.h" +#include "../../NetworkItems.h" + +class LitResAuthenticationManager : public NetworkAuthenticationManager { + +public: + LitResAuthenticationManager(const NetworkLink &link); + +public: + AuthenticationStatus isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener = 0); + std::string authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener); + void logOut(); + bool skipIPSupported(); + + const std::string ¤tUserName(); + bool needsInitialization(); + std::string initialize(shared_ptr<ZLNetworkRequest::Listener> listener); + bool needPurchase(const NetworkBookItem &book); + std::string purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener); + shared_ptr<BookReference> downloadReference(const NetworkBookItem &book); + + std::string topupAccountLink(); + std::string currentAccount(); + + std::string reloadPurchasedBooks(shared_ptr<ZLNetworkRequest::Listener> listener); + void collectPurchasedBooks(NetworkItem::List &list); + const std::set<std::string> &getPurchasedIds() const; + const NetworkItem::List &purchasedBooks() const; + +private: + void onAuthorised(ZLUserDataHolder &data, const std::string &error); + void onBookPurchased(ZLUserDataHolder &data, const std::string &error); + void onBooksLoaded(ZLUserDataHolder &data, const std::string &error); + void onAccountReceived(ZLUserDataHolder &data, const std::string &error); + void onBooksReloaded(ZLUserDataHolder &data, const std::string &error); + +private: + shared_ptr<ZLNetworkRequest> loadPurchasedBooks(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + void loadPurchasedBooksOnError(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + void loadPurchasedBooksOnSuccess(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + + shared_ptr<ZLNetworkRequest> loadAccount(std::string &dummy1); + void loadAccountOnError(); + void loadAccountOnSuccess(); + +public: // new User Registration + bool registrationSupported(); + std::string registerUser(const std::string &login, const std::string &password, const std::string &email); + +public: // Password Recovery + bool passwordRecoverySupported(); + std::string recoverPassword(const std::string &email); + +private: + bool mySidChecked; + + ZLStringOption mySidUserNameOption; + ZLStringOption mySidOption; + + std::string myInitializedDataSid; + std::set<std::string> myPurchasedBooksIds; + NetworkItem::List myPurchasedBooksList; + std::string myAccount; +}; + +#endif /* __LITRESAUTHENTICATIONMANAGER_H__ */ diff --git a/reader/src/network/litres/LitResAuthorsItem.cpp b/reader/src/network/litres/LitResAuthorsItem.cpp new file mode 100644 index 0000000..ece7438 --- /dev/null +++ b/reader/src/network/litres/LitResAuthorsItem.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkManager.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResAuthorsParser.h" +#include "LitResBooksFeedItem.h" + +#include "LitResAuthorsItem.h" + +LitResAuthorsItem::LitResAuthorsItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +) { +} + +class LitResAuthorsItemRunnable : public ZLRunnable { +public: + LitResAuthorsItemRunnable(LitResAuthorsItem *item, NetworkItem::List &children) : myItem(item), myChildren(children) { } + void run() { + myItem->fillChildrenWithAuthors(myChildren, myItem->myAuthorsList); + } +private: + LitResAuthorsItem *myItem; + NetworkItem::List &myChildren; +}; + +std::string LitResAuthorsItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + //TODO maybe add sid parameter if possible + //(at LitRes API documentation it said that's adding sid _always_ is a good practice) + + myAuthorsList.clear(); + shared_ptr<ZLNetworkRequest> data = ZLNetworkManager::Instance().createXMLParserRequest( + getCatalogUrl(), + new LitResAuthorsParser(myAuthorsList), + new LitResAuthorsItemRunnable(this, children) + ); + data->setListener(listener); + return ZLNetworkManager::Instance().performAsync(data); +} + +void LitResAuthorsItem::fillChildrenWithAuthors(NetworkItem::List &children, const LitResAuthorsParser::AuthorsList &authors) { + for (std::size_t i = 0; i < authors.size(); ++i) { + const LitResAuthorsParser::LitresAuthorData &author = authors.at(i); + + UrlInfoCollection urlByType = URLByType; + urlByType[NetworkItem::URL_CATALOG] = LitResUtil::generateBooksByAuthorUrl(author.Id); + //TODO add icon change for one author here + //urlByType[NetworkItem::URL_COVER] = + children.push_back(new LitResBooksFeedItem( + true, + Link, + author.DisplayName, + getSubtitle(author), + urlByType, + NetworkCatalogItem::ALWAYS, + NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES + )); + } +} + +std::string LitResAuthorsItem::getSubtitle(const LitResAuthorsParser::LitresAuthorData &author) { + static const std::string SPACE = " "; + std::string subtitle = author.FirstName; + if (!author.MiddleName.empty()) { + if (!subtitle.empty()) { + subtitle += SPACE; + } + subtitle += author.MiddleName; + } + if (!author.LastName.empty()) { + if (!subtitle.empty()) { + subtitle += SPACE; + } + subtitle += author.LastName; + } + return subtitle; +} diff --git a/reader/src/network/litres/LitResAuthorsItem.h b/reader/src/network/litres/LitResAuthorsItem.h new file mode 100644 index 0000000..31847f4 --- /dev/null +++ b/reader/src/network/litres/LitResAuthorsItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESAUTHORSITEM_H__ +#define __LITRESAUTHORSITEM_H__ + +#include "../NetworkItems.h" + +#include "LitResAuthorsParser.h" + +class LitResAuthorsItem : public NetworkCatalogItem { + +public: + LitResAuthorsItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags = FLAGS_DEFAULT + ); + +protected: + void fillChildrenWithAuthors(NetworkItem::List &children, const LitResAuthorsParser::AuthorsList &authors); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + + static std::string getSubtitle(const LitResAuthorsParser::LitresAuthorData &author); + +private: + LitResAuthorsParser::AuthorsList myAuthorsList; + +friend class LitResAuthorsItemRunnable; +}; + +#endif /* __LITRESAUTHORSITEM_H__ */ diff --git a/reader/src/network/litres/LitResAuthorsParser.cpp b/reader/src/network/litres/LitResAuthorsParser.cpp new file mode 100644 index 0000000..453ffb5 --- /dev/null +++ b/reader/src/network/litres/LitResAuthorsParser.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLUnicodeUtil.h> + +#include "../NetworkLink.h" +#include "LitResGenre.h" +#include "LitResUtil.h" + +#include "LitResAuthorsParser.h" + +static const std::string TAG_CATALOG = "catalit-persons"; +static const std::string TAG_SUBJECT = "subject"; +static const std::string TAG_TITLE = "title"; +static const std::string TAG_MAIN = "main"; +static const std::string TAG_FIRST_NAME = "first-name"; +static const std::string TAG_MIDDLE_NAME = "middle-name"; +static const std::string TAG_LAST_NAME = "last-name"; + +std::string LitResAuthorsParser::stringAttributeValue(const char **attributes, const char *name) { + if (attributes == 0) { + return std::string(); + } + const char *value = attributeValue(attributes, name); + return value != 0 ? value : std::string(); +} + +LitResAuthorsParser::LitResAuthorsParser(AuthorsList &authors) : myAuthors(authors) { + myState = START; +} + + +void LitResAuthorsParser::startElementHandler(const char *tag, const char **attributes) { + processState(tag, false, attributes); + myState = getNextState(tag, false); + myBuffer.clear(); +} + +void LitResAuthorsParser::endElementHandler(const char *tag) { + processState(tag, true, 0); + myState = getNextState(tag, true); + myBuffer.clear(); +} + +void LitResAuthorsParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} + +void LitResAuthorsParser::processState(const std::string &tag, bool closed, const char **attributes) { + switch(myState) { + case START: + break; + case CATALOG: + if (!closed && TAG_SUBJECT == tag) { + myAuthorId = stringAttributeValue(attributes, "id"); + } + break; + case SUBJECT: + if (closed && TAG_SUBJECT == tag) { + LitresAuthorData litresAuthor; + litresAuthor.Id = myAuthorId; + litresAuthor.DisplayName = myAuthorDisplayName; + litresAuthor.FirstName = myAuthorFirstName; + litresAuthor.MiddleName = myAuthorMiddleName; + litresAuthor.LastName = myAuthorLastName; + litresAuthor.SortKey = ZLUnicodeUtil::toLower(myAuthorLastName); + + myAuthors.push_back(litresAuthor); + myAuthorId.clear(); + myAuthorDisplayName.clear(); + myAuthorFirstName.clear(); + myAuthorMiddleName.clear(); + myAuthorLastName.clear(); + } + break; + case TITLE: + break; + case MAIN: + if (closed && TAG_MAIN == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorDisplayName = myBuffer; + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorFirstName = myBuffer; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorMiddleName = myBuffer; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorLastName = myBuffer; + } + break; + } +} + +LitResAuthorsParser::State LitResAuthorsParser::getNextState(const std::string &tag, bool closed) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + return CATALOG; + } + break; + case CATALOG: + if (!closed) { + if (TAG_SUBJECT == tag) { + return SUBJECT; + } + } else { + if (TAG_CATALOG == tag) { + return START; + } + } + break; + case SUBJECT: + if (!closed) { + if (TAG_TITLE == tag) { + return TITLE; + } + } else { + if (TAG_SUBJECT == tag) { + return CATALOG; + } + } + break; + case TITLE: + if (!closed) { + if (TAG_MAIN == tag) { + return MAIN; + } + } else { + if (TAG_TITLE == tag) { + return FIRST_NAME; + } + } + break; + case MAIN: + if (closed && TAG_MAIN == tag) { + return TITLE; + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + return MIDDLE_NAME; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + return LAST_NAME; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + return SUBJECT; + } + break; + } + return myState; +} diff --git a/reader/src/network/litres/LitResAuthorsParser.h b/reader/src/network/litres/LitResAuthorsParser.h new file mode 100644 index 0000000..ead137d --- /dev/null +++ b/reader/src/network/litres/LitResAuthorsParser.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESAUTHORSPARSER_H__ +#define __LITRESAUTHORSPARSER_H__ + +#include <vector> +#include <map> + +#include <ZLXMLReader.h> + +#include "../NetworkItems.h" + +class NetworkLink; +struct LitResGenre; +class NetworkAuthenticationManager; + +class LitResAuthorsParser : public ZLXMLReader { + +public: + struct LitresAuthorData { + std::string Id; + std::string DisplayName; + std::string FirstName; + std::string MiddleName; + std::string LastName; + std::string SortKey; + + bool operator< (const LitresAuthorData &authorData) const; + }; + typedef std::vector<LitresAuthorData> AuthorsList; + +public: + LitResAuthorsParser(AuthorsList &authors); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + enum State { + START, CATALOG, SUBJECT, TITLE, MAIN, FIRST_NAME, MIDDLE_NAME, LAST_NAME + }; + + std::string stringAttributeValue(const char **attributes, const char *name); + void processState(const std::string &tag, bool closed, const char **attributes); + State getNextState(const std::string &tag, bool closed); + +private: + AuthorsList &myAuthors; + + std::string myBuffer; + State myState; + + std::string myAuthorId; + std::string myAuthorDisplayName; + std::string myAuthorFirstName; + std::string myAuthorMiddleName; + std::string myAuthorLastName; +}; + +inline bool LitResAuthorsParser::LitresAuthorData::operator< (const LitresAuthorData &authorData) const { + return SortKey.compare(authorData.SortKey) < 0; +} + +#endif /* __LITRESAUTHORSPARSER_H__ */ diff --git a/reader/src/network/litres/LitResBookItem.cpp b/reader/src/network/litres/LitResBookItem.cpp new file mode 100644 index 0000000..cdc9306 --- /dev/null +++ b/reader/src/network/litres/LitResBookItem.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLStringUtil.h> + +#include "LitResBooksFeedItem.h" +#include "LitResUtil.h" + +#include "LitResBookItem.h" + +LitResBookItem::LitResBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references, + const std::vector<std::string> authorIds +) : + NetworkBookItem(link, id, index, title, summary, language, date, authors, + tags, seriesTitle, indexInSeries, urlByType, references), + myAuthorIds(authorIds) +{ + +} + +std::vector<shared_ptr<NetworkItem> > LitResBookItem::getRelatedCatalogsItems() const { + std::vector<shared_ptr<NetworkItem> > items; + + UrlInfoCollection urlByType = URLByType; + + urlByType[URL_CATALOG] = LitResUtil::generateAlsoReadUrl(Id); + items.push_back(new LitResBooksFeedItem(false, Link, resource("alsoRead").value(), std::string(), urlByType)); + + for (std::size_t i = 0; i < myAuthorIds.size(); ++i) { + urlByType[URL_CATALOG] = LitResUtil::generateBooksByAuthorUrl(myAuthorIds.at(i)); + std::string title = ZLStringUtil::printf(resource("sameAuthor").value(), Authors.at(i).DisplayName); + items.push_back(new LitResBooksFeedItem(false, Link, title, std::string(), urlByType)); + } + + return items; +} + +const ZLResource &LitResBookItem::resource(const std::string &resourceKey) const { + return ZLResource::resource("networkView")["bookNode"][resourceKey]; +} diff --git a/reader/src/network/litres/LitResBookItem.h b/reader/src/network/litres/LitResBookItem.h new file mode 100644 index 0000000..129b6a6 --- /dev/null +++ b/reader/src/network/litres/LitResBookItem.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESBOOKITEM_H__ +#define __LITRESBOOKITEM_H__ + +#include "../NetworkItems.h" + +class LitResBookItem : public NetworkBookItem { +public: + LitResBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references, + const std::vector<std::string> authorIds + ); + + std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + +protected: + const ZLResource &resource(const std::string &resourceKey) const; + +private: + std::vector<std::string> myAuthorIds; +}; + +#endif /* __LITRESBOOKITEM_H__ */ diff --git a/reader/src/network/litres/LitResBooksFeedItem.cpp b/reader/src/network/litres/LitResBooksFeedItem.cpp new file mode 100644 index 0000000..b597255 --- /dev/null +++ b/reader/src/network/litres/LitResBooksFeedItem.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLNetworkManager.h> +#include <ZLNetworkUtil.h> +#include <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResBooksFeedParser.h" + +#include "LitResBooksFeedItem.h" + +LitResBooksFeedItem::LitResBooksFeedItem( + bool shouldSort, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +), myShouldSort(shouldSort) { + +} + +void LitResBooksFeedItem::onDisplayItem() { +} + +class LitResBooksFeedItemRunnable : public ZLNetworkRequest::Listener { +public: + LitResBooksFeedItemRunnable(LitResBooksFeedItem &item, shared_ptr<ZLNetworkRequest> request, NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) : + myItem(item), myChildren(children), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + + void finished(const std::string &error) { + if (error.empty()) { + ++myItem.myLoadingState.CurrentPage; + if (myItem.myShouldSort) { + std::sort(myChildren.begin(), myChildren.end(), NetworkBookItemComparator()); + } + } + myListener->finished(error); + } +private: + LitResBooksFeedItem &myItem; + NetworkItem::List &myChildren; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + + +std::string LitResBooksFeedItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { +// //TODO maybe add sid parameter if possible +// //(at LitRes API documentation it said that's adding sid _always_ is a good practice) + + myLoadingState.CurrentPage = 0; + myLoadingState.AllPagesCount = 1; + + shared_ptr<ZLNetworkRequest> request = getRequest(children); + new LitResBooksFeedItemRunnable(*this, request, children, listener); + return std::string(); +} + +bool LitResBooksFeedItem::supportsResumeLoading() { + return true; +} + +std::string LitResBooksFeedItem::resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + shared_ptr<ZLNetworkRequest> request = getRequest(children); + if (request.isNull()) { + listener->finished(); + return std::string(); + } + new LitResBooksFeedItemRunnable(*this, request, children, listener); + return std::string(); +} + +shared_ptr<ZLNetworkRequest> LitResBooksFeedItem::getRequest(NetworkItem::List &children) { + if (myLoadingState.CurrentPage >= myLoadingState.AllPagesCount) { + return 0; + } + return ZLNetworkManager::Instance().createXMLParserRequest( + withLimitParameters(getCatalogUrl(), myLoadingState), + new LitResBooksFeedParser(Link, children, &myLoadingState) + ); +} + +std::string LitResBooksFeedItem::withLimitParameters(std::string query, const LoadingState &state) { + static const unsigned int ITEMS_PER_PAGE = 40; + unsigned int startItemNumber = (unsigned int)state.CurrentPage * ITEMS_PER_PAGE; + std::string params; + ZLStringUtil::appendNumber(params, startItemNumber); + params += ","; + ZLStringUtil::appendNumber(params, ITEMS_PER_PAGE); + ZLNetworkUtil::appendParameter(query, "limit", params); + return query; +} + diff --git a/reader/src/network/litres/LitResBooksFeedItem.h b/reader/src/network/litres/LitResBooksFeedItem.h new file mode 100644 index 0000000..8af7df2 --- /dev/null +++ b/reader/src/network/litres/LitResBooksFeedItem.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESBOOKFEEDITEM_H__ +#define __LITRESBOOKFEEDITEM_H__ + +#include "../NetworkItems.h" + +class LitResBooksFeedItem : public NetworkCatalogItem { + +public: + struct LoadingState { + int CurrentPage; + int AllPagesCount; + } myLoadingState; + +public: + LitResBooksFeedItem( + bool shouldSort, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + +private: + void onDisplayItem(); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + bool supportsResumeLoading(); + std::string resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + shared_ptr<ZLNetworkRequest> getRequest(NetworkItem::List &children); + static std::string withLimitParameters(std::string url, const LoadingState &state); + +private: + bool myShouldSort; + +friend class LitResBooksFeedItemRunnable; +}; + +#endif /* __LITRESBOOKFEEDITEM_H__ */ diff --git a/reader/src/network/litres/LitResBooksFeedParser.cpp b/reader/src/network/litres/LitResBooksFeedParser.cpp new file mode 100644 index 0000000..4d2fe93 --- /dev/null +++ b/reader/src/network/litres/LitResBooksFeedParser.cpp @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "LitResBooksFeedParser.h" +#include "LitResBookItem.h" +#include "LitResGenre.h" +#include "LitResUtil.h" +#include "../NetworkLink.h" + +static const std::string TAG_CATALOG = "catalit-fb2-books"; +static const std::string TAG_BOOK = "fb2-book"; +static const std::string TAG_TEXT_DESCRIPTION = "text_description"; +static const std::string TAG_HIDDEN = "hidden"; +static const std::string TAG_TITLE_INFO = "title-info"; +static const std::string TAG_GENRE = "genre"; +static const std::string TAG_AUTHOR = "author"; +static const std::string TAG_FIRST_NAME = "first-name"; +static const std::string TAG_MIDDLE_NAME = "middle-name"; +static const std::string TAG_LAST_NAME = "last-name"; +static const std::string TAG_AUTHOR_ID = "id"; +static const std::string TAG_BOOK_TITLE = "book-title"; +static const std::string TAG_ANNOTATION = "annotation"; +static const std::string TAG_DATE = "date"; +static const std::string TAG_SEQUENCE = "sequence"; +static const std::string TAG_LANGUAGE = "lang"; + +std::string LitResBooksFeedParser::stringAttributeValue(const char **attributes, const char *name) { + if (attributes == 0) { + return std::string(); + } + const char *value = attributeValue(attributes, name); + return value != 0 ? value : std::string(); +} + +LitResBooksFeedParser::LitResBooksFeedParser(const NetworkLink &link, NetworkItem::List &books, LitResBooksFeedItem::LoadingState *loadingState) : + myLink(link), + myBooks(books), + myIndex(0), + myLoadingState(loadingState) { + myState = START; +} + + +void LitResBooksFeedParser::startElementHandler(const char *tag, const char **attributes) { + processState(tag, false, attributes); + myState = getNextState(tag, false); + myBuffer.clear(); +} + +void LitResBooksFeedParser::endElementHandler(const char *tag) { + processState(tag, true, 0); + myState = getNextState(tag, true); + myBuffer.clear(); +} + +void LitResBooksFeedParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} + +void LitResBooksFeedParser::processState(const std::string &tag, bool closed, const char **attributes) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + if (myLoadingState) { + myLoadingState->AllPagesCount = ZLStringUtil::stringToInteger(stringAttributeValue(attributes, "pages"), 1); + } + } + break; + case CATALOG: + if (!closed && TAG_BOOK == tag) { + myBookId = stringAttributeValue(attributes, "hub_id"); + myURLByType[NetworkItem::URL_COVER] = + stringAttributeValue(attributes, "cover_preview"); + myURLByType[NetworkItem::URL_FULL_COVER] = + stringAttributeValue(attributes, "cover"); + + std::string url = stringAttributeValue(attributes, "url"); + if (!url.empty()) { + myLink.rewriteUrl(url, true); // This code duplicates code in Reader::openInBrowser and is not required + myURLByType[NetworkItem::URL_HTML_PAGE] = url; + } + + //TODO check if buying book works right + std::string price = BuyBookReference::price(stringAttributeValue(attributes, "price"), "RUB"); + myReferences.push_back(new BuyBookReference( + LitResUtil::generatePurchaseUrl(myLink, myBookId), + BookReference::FB2_ZIP, + BookReference::BUY, + price + )); + + std::string hasTrial = stringAttributeValue(attributes, "has_trial"); + if (!hasTrial.empty() && hasTrial != "0") { + myReferences.push_back(new BookReference( + LitResUtil::generateTrialUrl(myBookId), + BookReference::FB2_ZIP, + BookReference::DOWNLOAD_DEMO + )); + } + + myReferences.push_back(new BookReference( + LitResUtil::generateDownloadUrl(myBookId), + BookReference::FB2_ZIP, + BookReference::DOWNLOAD_FULL_CONDITIONAL + )); + } + break; + case BOOK: + if (closed && TAG_BOOK == tag) { + myBooks.push_back(new LitResBookItem( + myLink, + myBookId, + myIndex++, + myTitle, + mySummary, + myLanguage, + myDate, + myAuthors, + myTags, + mySeriesTitle, + myIndexInSeries, + myURLByType, + myReferences, + myAuthorsIds + )); + + myTitle.erase(); + mySummary.erase(); + myLanguage.erase(); + myDate.erase(); + mySeriesTitle.erase(); + myIndexInSeries = 0; + myAuthors.clear(); + myAuthorsIds.clear(); + myTags.clear(); + myURLByType.clear(); + myReferences.clear(); + } + break; + case BOOK_DESCRIPTION: + break; + case HIDDEN: + break; + case TITLE_INFO: + if (!closed) { + if (TAG_AUTHOR == tag) { + myAuthorFirstName.clear(); + myAuthorMiddleName.clear(); + myAuthorLastName.clear(); + } else if (TAG_SEQUENCE == tag) { + mySeriesTitle = stringAttributeValue(attributes, "name"); + if (!mySeriesTitle.empty()) { + const char *indexInSeries = attributeValue(attributes, "number"); + myIndexInSeries = indexInSeries != 0 ? std::atoi(indexInSeries) : 0; + } + } + } + break; + case AUTHOR: + if (closed && TAG_AUTHOR == tag) { + NetworkBookItem::AuthorData data; + if (!myAuthorFirstName.empty()) { + data.DisplayName.append(myAuthorFirstName); + } + if (!myAuthorMiddleName.empty()) { + if (!data.DisplayName.empty()) { + data.DisplayName.append(" "); + } + data.DisplayName.append(myAuthorMiddleName); + } + if (!myAuthorLastName.empty()) { + if (!data.DisplayName.empty()) { + data.DisplayName.append(" "); + } + data.DisplayName.append(myAuthorLastName); + } + data.SortKey = myAuthorLastName; + myAuthors.push_back(data); + myAuthorsIds.push_back(myAuthorId); + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorFirstName = myBuffer; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorMiddleName = myBuffer; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorLastName = myBuffer; + } + break; + case AUTHOR_ID: + if (closed && TAG_AUTHOR_ID == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorId = myBuffer; + } + break; + case GENRE: + if (closed && TAG_GENRE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + + const std::map<std::string,shared_ptr<LitResGenre> > &genresMap = + LitResGenreMap::Instance().genresMap(); + const std::map<shared_ptr<LitResGenre>,std::string> &genresTitles = + LitResGenreMap::Instance().genresTitles(); + + std::map<std::string, shared_ptr<LitResGenre> >::const_iterator it = genresMap.find(myBuffer); + if (it != genresMap.end()) { + std::map<shared_ptr<LitResGenre>, std::string>::const_iterator jt = genresTitles.find(it->second); + if (jt != genresTitles.end()) { + myTags.push_back(jt->second); + } + } + } + break; + case BOOK_TITLE: + if (closed && TAG_BOOK_TITLE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myTitle = myBuffer; + } + break; + case ANNOTATION: + if (!closed) { + ZLUnicodeUtil::utf8Trim(myBuffer); + if (!myBuffer.empty()) { + mySummary.append(myBuffer); + mySummary.append(" "); + } + } else { + ZLUnicodeUtil::utf8Trim(myBuffer); + mySummary.append(myBuffer); + int size = mySummary.size(); + if (size > 0) { + if (TAG_ANNOTATION == tag) { + if (mySummary[size - 1] == '\n') { + mySummary.erase(size - 1); + } + } else if ("p" == tag) { + if (mySummary[size - 1] != '\n') { + mySummary.append("\n"); + } + } else { + if (!myBuffer.empty() && mySummary[size - 1] != '\n') { + mySummary.append(" "); + } + } + } + } + break; + case DATE: + if (closed && TAG_DATE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myDate = myBuffer; + } + break; + case LANGUAGE: + if (closed && TAG_LANGUAGE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myLanguage = myBuffer; + } + break; + } +} + +LitResBooksFeedParser::State LitResBooksFeedParser::getNextState(const std::string &tag, bool closed) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + return CATALOG; + } + break; + case CATALOG: + if (!closed) { + if (TAG_BOOK == tag) { + return BOOK; + } + } else { + if (TAG_CATALOG == tag) { + return START; + } + } + break; + case BOOK: + if (!closed) { + if (TAG_TEXT_DESCRIPTION == tag) { + return BOOK_DESCRIPTION; + } + } else { + if (TAG_BOOK == tag) { + return CATALOG; + } + } + break; + case BOOK_DESCRIPTION: + if (!closed) { + if (TAG_HIDDEN == tag) { + return HIDDEN; + } + } else { + if (TAG_TEXT_DESCRIPTION == tag) { + return BOOK; + } + } + break; + case HIDDEN: + if (!closed) { + if (TAG_TITLE_INFO == tag) { + return TITLE_INFO; + } + } else { + if (TAG_HIDDEN == tag) { + return BOOK_DESCRIPTION; + } + } + break; + case TITLE_INFO: + if (!closed) { + if (TAG_GENRE == tag) { + return GENRE; + } else if (TAG_AUTHOR == tag) { + return AUTHOR; + } else if (TAG_BOOK_TITLE == tag) { + return BOOK_TITLE; + } else if (TAG_ANNOTATION == tag) { + return ANNOTATION; + } else if (TAG_DATE == tag) { + return DATE; + } else if (TAG_LANGUAGE == tag) { + return LANGUAGE; + } /*else if (TAG_SEQUENCE == tag) { + return SEQUENCE; // handled without state through attributes + }*/ + } else { + if (TAG_TITLE_INFO == tag) { + return HIDDEN; + } + } + break; + case AUTHOR: + if (!closed) { + if (TAG_FIRST_NAME == tag) { + return FIRST_NAME; + } else if (TAG_MIDDLE_NAME == tag) { + return MIDDLE_NAME; + } else if (TAG_LAST_NAME == tag) { + return LAST_NAME; + } else if (TAG_AUTHOR_ID == tag) { + return AUTHOR_ID; + } + } else { + if (TAG_AUTHOR == tag) { + return TITLE_INFO; + } + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + return AUTHOR; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + return AUTHOR; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + return AUTHOR; + } + break; + case AUTHOR_ID: + if (closed && TAG_AUTHOR_ID == tag) { + return AUTHOR; + } + break; + case GENRE: + if (closed && TAG_GENRE == tag) { + return TITLE_INFO; + } + break; + case BOOK_TITLE: + if (closed && TAG_BOOK_TITLE == tag) { + return TITLE_INFO; + } + break; + case ANNOTATION: + if (closed && TAG_ANNOTATION == tag) { + return TITLE_INFO; + } + break; + case DATE: + if (closed && TAG_DATE == tag) { + return TITLE_INFO; + } + break; + case LANGUAGE: + if (closed && TAG_LANGUAGE == tag) { + return TITLE_INFO; + } + break; + } + return myState; +} + diff --git a/reader/src/network/litres/LitResBooksFeedParser.h b/reader/src/network/litres/LitResBooksFeedParser.h new file mode 100644 index 0000000..6f9a6dc --- /dev/null +++ b/reader/src/network/litres/LitResBooksFeedParser.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESBOOKSFEEDPARSER_H__ +#define __LITRESBOOKSFEEDPARSER_H__ + +#include <vector> +#include <map> + +#include <ZLXMLReader.h> + +#include "../NetworkItems.h" + +#include "LitResBooksFeedItem.h" + +class NetworkLink; +struct LitResGenre; +class NetworkAuthenticationManager; + +class LitResBooksFeedParser : public ZLXMLReader { + +public: + LitResBooksFeedParser(const NetworkLink &link, NetworkItem::List &books, LitResBooksFeedItem::LoadingState *state = 0); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + enum State { + START, CATALOG, BOOK, BOOK_DESCRIPTION, HIDDEN, TITLE_INFO, + GENRE, AUTHOR, FIRST_NAME, MIDDLE_NAME, LAST_NAME, AUTHOR_ID, BOOK_TITLE, + ANNOTATION, DATE, LANGUAGE, + }; + + std::string stringAttributeValue(const char **attributes, const char *name); + void processState(const std::string &tag, bool closed, const char **attributes); + State getNextState(const std::string &tag, bool closed); + +private: + const NetworkLink &myLink; + + NetworkItem::List &myBooks; + std::string myBuffer; + + unsigned int myIndex; + + State myState; + + std::string myBookId; + std::string myTitle; + std::string mySummary; + std::string myLanguage; + std::string myDate; + std::string mySeriesTitle; + int myIndexInSeries; + + std::string myAuthorFirstName; + std::string myAuthorMiddleName; + std::string myAuthorLastName; + std::string myAuthorId; + std::vector<NetworkBookItem::AuthorData> myAuthors; + std::vector<std::string> myAuthorsIds; + + std::vector<std::string> myTags; + NetworkItem::UrlInfoCollection myURLByType; + std::vector<shared_ptr<BookReference> > myReferences; + + LitResBooksFeedItem::LoadingState *myLoadingState; +}; + +#endif /* __LITRESBOOKSFEEDPARSER_H__ */ diff --git a/reader/src/network/litres/LitResBookshelfItem.cpp b/reader/src/network/litres/LitResBookshelfItem.cpp new file mode 100644 index 0000000..be931fe --- /dev/null +++ b/reader/src/network/litres/LitResBookshelfItem.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLNetworkRequest.h> +#include <ZLExecutionUtil.h> + +#include "LitResBookshelfItem.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" + +#include "SortedCatalogItem.h" + +LitResBookshelfItem::LitResBookshelfItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility +) { + myForceReload = false; +} + +void LitResBookshelfItem::onDisplayItem() { + myForceReload = false; +} + +class LitResBookshelfItemLoaderScope : public ZLUserData { +public: + LitResBookshelfItemLoaderScope(NetworkItem::List &children) : Children(children) {} + NetworkItem::List &Children; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + + +std::string LitResBookshelfItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + LitResAuthenticationManager &mgr = (LitResAuthenticationManager&)*Link.authenticationManager(); + if (mgr.isAuthorised().Status == B3_FALSE) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } + + LitResBookshelfItemLoaderScope *scope = new LitResBookshelfItemLoaderScope(children); + scope->listener = listener; + + shared_ptr<ZLUserDataHolder> scopeData = new ZLUserDataHolder; + scopeData->addUserData("scope", scope); + if (myForceReload) { + mgr.reloadPurchasedBooks(ZLExecutionUtil::createListener(scopeData, this, &LitResBookshelfItem::onReloaded)); + return std::string(); + } + onReloaded(*scopeData, std::string()); + return std::string(); +} + +void LitResBookshelfItem::onReloaded(ZLUserDataHolder &data, const std::string &error) { + LitResBookshelfItemLoaderScope &scope = static_cast<LitResBookshelfItemLoaderScope&>(*data.getUserData("scope")); + LitResAuthenticationManager &mgr = static_cast<LitResAuthenticationManager&>(*Link.authenticationManager()); + myForceReload = true; + NetworkItem::List tmpChildren; + mgr.collectPurchasedBooks(tmpChildren); + std::sort(tmpChildren.begin(), tmpChildren.end(), NetworkBookItemComparator()); + + + NetworkItem::List &children = scope.Children; + + if (tmpChildren.size() <= 5) { + children.assign(tmpChildren.begin(), tmpChildren.end()); + std::sort(children.begin(), children.end(), NetworkBookItemComparator()); + } else { + children.push_back(SortedCatalogItem::create(*this, "byDate", tmpChildren, FLAG_SHOW_AUTHOR)); + children.push_back(SortedCatalogItem::create(*this, "byAuthor", tmpChildren, FLAG_GROUP_BY_AUTHOR, NetworkBookItemComparator())); + children.push_back(SortedCatalogItem::create(*this, "byTitle", tmpChildren, FLAG_SHOW_AUTHOR, NetworkBookItemByTitleComparator())); + SortedCatalogItem* bySeries = SortedCatalogItem::create(*this, "bySeries", tmpChildren, FLAG_SHOW_AUTHOR | FLAG_GROUP_BY_SERIES, + NetworkBookItemBySeriesComparator(), SortedCatalogItem::BySeriesFilter()); + + if (!bySeries->isEmpty()) { + children.push_back(bySeries); + } else { + delete bySeries; + } + } + + scope.listener->finished(error); +} diff --git a/reader/src/network/litres/LitResBookshelfItem.h b/reader/src/network/litres/LitResBookshelfItem.h new file mode 100644 index 0000000..22ea8d9 --- /dev/null +++ b/reader/src/network/litres/LitResBookshelfItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESBOOKSHELFITEM_H__ +#define __LITRESBOOKSHELFITEM_H__ + +#include <ZLResource.h> +#include <ZLExecutionUtil.h> + +#include "../NetworkComparators.h" +#include "../NetworkItems.h" + +class NetworkLink; + +class LitResBookshelfItem : public NetworkCatalogItem { + +public: + LitResBookshelfItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS + ); + +private: + void onDisplayItem(); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + void onReloaded(ZLUserDataHolder &data, const std::string &error); + +private: + bool myForceReload; +}; + +#endif /* __LITRESBOOKSHELFITEM_H__ */ diff --git a/reader/src/network/litres/LitResByGenresItem.cpp b/reader/src/network/litres/LitResByGenresItem.cpp new file mode 100644 index 0000000..a9b6367 --- /dev/null +++ b/reader/src/network/litres/LitResByGenresItem.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLNetworkManager.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResBooksFeedParser.h" +#include "LitResBooksFeedItem.h" + +#include "LitResByGenresItem.h" + +static const std::string EMPTY_STRING = std::string(); + +LitResByGenresItem::LitResByGenresItem( + const std::vector<shared_ptr<LitResGenre> > &genreTree, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +), myGenreTree(genreTree) { +} + +std::string LitResByGenresItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + for (std::size_t i = 0; i < myGenreTree.size(); ++i) { + shared_ptr<LitResGenre> genre = myGenreTree.at(i); + if (genre->Children.empty()) { + UrlInfoCollection urlByType = URLByType; + urlByType[NetworkItem::URL_CATALOG] = LitResUtil::generateBooksByGenreUrl(genre->Id); + //TODO add icon change for one genre here + //urlByType[NetworkItem::URL_COVER] = + children.push_back(new LitResBooksFeedItem(true, Link, genre->Title, EMPTY_STRING, urlByType, ALWAYS)); + } else { + children.push_back(new LitResByGenresItem(genre->Children, Link, genre->Title, EMPTY_STRING, URLByType, ALWAYS, FLAG_NONE)); + } + } + listener->finished(); + return std::string(); +} + diff --git a/reader/src/network/litres/LitResByGenresItem.h b/reader/src/network/litres/LitResByGenresItem.h new file mode 100644 index 0000000..3af0e23 --- /dev/null +++ b/reader/src/network/litres/LitResByGenresItem.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESBYGENRESITEM_H__ +#define __LITRESBYGENRESITEM_H__ + +#include "../NetworkItems.h" + +#include "LitResGenre.h" + +class LitResByGenresItem : public NetworkCatalogItem { + +public: + LitResByGenresItem( + const std::vector<shared_ptr<LitResGenre> > &genreTree, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags + ); + +private: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + const std::vector<shared_ptr<LitResGenre> > &myGenreTree; +}; + +#endif /* __LITRESBYGENRESITEM_H__ */ diff --git a/reader/src/network/litres/LitResGenre.cpp b/reader/src/network/litres/LitResGenre.cpp new file mode 100644 index 0000000..a541948 --- /dev/null +++ b/reader/src/network/litres/LitResGenre.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkManager.h> + +#include <ZLibrary.h> +#include <ZLDir.h> +#include <ZLFile.h> +#include <ZLTime.h> + +#include "LitResGenresParser.h" +#include "LitResGenre.h" +#include "LitResUtil.h" + +static const std::string GENRES_CACHE_PREFIX = "litres_genres_"; +static const std::string GENRES_CACHE_SUFFIX = ".xml"; + +LitResGenre::LitResGenre() { +} + +LitResGenre::LitResGenre(const std::string &id, const std::string &title) : Id(id), Title(title) { +} + +LitResGenreMap *LitResGenreMap::ourInstance = 0; + +const LitResGenreMap &LitResGenreMap::Instance() { + if (ourInstance == 0) { + ourInstance = new LitResGenreMap(); + } + return *ourInstance; +} + +LitResGenreMap::LitResGenreMap() : myInitialized(false) { +} + +void LitResGenreMap::validateGenres() const { + if (!myInitialized) { + if (loadGenres()) { + buildGenresTitles(myGenresTree); + myInitialized = true; + } + } +} + +const std::map<std::string, shared_ptr<LitResGenre> > &LitResGenreMap::genresMap() const { + validateGenres(); + return myGenresMap; +} + +const std::vector<shared_ptr<LitResGenre> > &LitResGenreMap::genresTree() const { + validateGenres(); + return myGenresTree; +} + +const std::map<shared_ptr<LitResGenre>, std::string> &LitResGenreMap::genresTitles() const { + validateGenres(); + return myGenresTitles; +} + +void LitResGenreMap::fillGenreIds(const std::string &tag, std::vector<std::string> &ids) const { + std::vector<std::string> words; + int index = 0; + + const std::map<shared_ptr<LitResGenre>, std::string> map = genresTitles(); + + do { + int index2 = tag.find(' ', index); + std::string word = tag.substr(index, index2 - index); + ZLUnicodeUtil::utf8Trim(word); + if (!word.empty()) { + words.push_back(ZLUnicodeUtil::toLower(word)); + } + index = index2 + 1; + } while (index != 0); + + for (std::map<shared_ptr<LitResGenre>, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) { + const LitResGenre &genre = *it->first; + std::string title = ZLUnicodeUtil::toLower(it->second); + bool containsAll = true; + for (std::vector<std::string>::const_iterator jt = words.begin(); jt != words.end(); ++jt) { + if (title.find(*jt) == std::string::npos) { + containsAll = false; + break; + } + } + if (containsAll) { + ids.push_back(genre.Id); + } + } +} + +bool LitResGenreMap::loadGenres() const { + static const std::string directoryPath = ZLNetworkManager::CacheDirectory(); + static shared_ptr<ZLDir> dir = ZLFile(directoryPath).directory(true); + + const std::string url = LitResUtil::url("pages/catalit_genres/"); + + myGenresTree.clear(); + myGenresMap.clear(); + myGenresTitles.clear(); + + if (dir.isNull()) { + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest( + url, + new LitResGenresParser(myGenresTree, myGenresMap) + ); + const std::string error = ZLNetworkManager::Instance().perform(networkData); + if (!error.empty()) { + myGenresTree.clear(); + myGenresMap.clear(); + myGenresTitles.clear(); + return false; + } + return true; + } + + std::string cacheName; + bool cacheValid = false; + + std::vector<std::string> files; + dir->collectFiles(files, false); + for (std::vector<std::string>::const_iterator it = files.begin(); it != files.end(); ++it) { + const std::string &name = *it; + if (ZLStringUtil::stringStartsWith(name, GENRES_CACHE_PREFIX)) { + cacheName = name; + } + } + files.clear(); + + ZLTime now; + + if (!cacheName.empty()) { + std::string cacheDate = cacheName.substr(GENRES_CACHE_PREFIX.size(), 8); + int cacheYear = std::atoi(cacheDate.substr(0, 4).c_str()); + int cacheMonth = std::atoi(cacheDate.substr(4, 2).c_str()); + int cacheDay = std::atoi(cacheDate.substr(6, 2).c_str()); + int daysDiff = (now.year() - cacheYear) * 365 + (now.month() - cacheMonth) * 31 + (now.dayOfMonth() - cacheDay); + if (daysDiff < 30) { + cacheValid = true; + } + cacheName = dir->itemPath(cacheName); + } + + if (!cacheValid) { + std::string yearStr, monthStr, dayStr; + ZLStringUtil::appendNumber(yearStr, now.year()); + ZLStringUtil::appendNumber(monthStr, now.month()); + ZLStringUtil::appendNumber(dayStr, now.dayOfMonth()); + while (monthStr.size() < 2) { + monthStr = "0" + monthStr; + } + while (dayStr.size() < 2) { + dayStr = "0" + dayStr; + } + + const std::string fileName = dir->path() + ZLibrary::FileNameDelimiter + + GENRES_CACHE_PREFIX + yearStr + monthStr + dayStr + GENRES_CACHE_SUFFIX; + + const std::string error = ZLNetworkManager::Instance().downloadFile(url, fileName); + if (!error.empty()) { + ZLFile(fileName).remove(); + } else { + ZLFile(cacheName).remove(); + cacheName = fileName; + } + } + + if (cacheName.empty()) { + return false; + } + + shared_ptr<ZLXMLReader> parser = new LitResGenresParser(myGenresTree, myGenresMap); + return parser->readDocument(ZLFile(cacheName)); +} + +void LitResGenreMap::buildGenresTitles(const std::vector<shared_ptr<LitResGenre> > &genres, const std::string &titlePrefix) const { + for (std::vector<shared_ptr<LitResGenre> >::const_iterator it = genres.begin(); it != genres.end(); ++it) { + shared_ptr<LitResGenre> genre = *it; + std::string title = titlePrefix.empty() ? (genre->Title) : (titlePrefix + "/" + genre->Title); + if (genre->Id.empty()) { + buildGenresTitles(genre->Children, title); + } else { + myGenresTitles[genre] = title; + } + } +} diff --git a/reader/src/network/litres/LitResGenre.h b/reader/src/network/litres/LitResGenre.h new file mode 100644 index 0000000..4b2bd3b --- /dev/null +++ b/reader/src/network/litres/LitResGenre.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESGENRE_H__ +#define __LITRESGENRE_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> + +struct LitResGenre { + std::string Id; + std::string Title; + std::vector<shared_ptr<LitResGenre> > Children; + + LitResGenre(); + LitResGenre(const std::string &id, const std::string &title); +}; + +class LitResGenreMap { + +public: + static const LitResGenreMap &Instance(); + +private: + static LitResGenreMap *ourInstance; + +private: + LitResGenreMap(); + +public: + const std::map<std::string, shared_ptr<LitResGenre> > &genresMap() const; + const std::vector<shared_ptr<LitResGenre> > &genresTree() const; + const std::map<shared_ptr<LitResGenre>, std::string> &genresTitles() const; + void fillGenreIds(const std::string &tag, std::vector<std::string> &ids) const; + +private: + void validateGenres() const; + bool loadGenres() const; + void buildGenresTitles(const std::vector<shared_ptr<LitResGenre> > &genres, const std::string &titlePrefix = "") const; + + mutable std::vector<shared_ptr<LitResGenre> > myGenresTree; + mutable std::map<std::string, shared_ptr<LitResGenre> > myGenresMap; + mutable std::map<shared_ptr<LitResGenre>, std::string> myGenresTitles; + mutable bool myInitialized; +}; + +#endif /* __LITRESGENRE_H__ */ diff --git a/reader/src/network/litres/LitResGenresParser.cpp b/reader/src/network/litres/LitResGenresParser.cpp new file mode 100644 index 0000000..9ed3f2d --- /dev/null +++ b/reader/src/network/litres/LitResGenresParser.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> + +#include "LitResGenresParser.h" + +#include "LitResGenre.h" + +static const std::string TAG_GENRE = "genre"; + + +LitResGenresParser::LitResGenresParser(std::vector<shared_ptr<LitResGenre> > &genresTree, std::map<std::string, shared_ptr<LitResGenre> > &genresMap) : + myGenresTree(genresTree), + myGenresMap(genresMap), + myDontPopStack(false) { +} + +void LitResGenresParser::saveGenre(shared_ptr<LitResGenre> genre, const std::string &token) { + if (myStack.empty()) { + myGenresTree.push_back(genre); + } else { + myStack.back()->Children.push_back(genre); + } + if (genre->Id.empty()) { + myStack.push_back(genre); + } else { + myDontPopStack = true; + if (!token.empty()) { + myGenresMap[token] = genre; + } + } +} + +void LitResGenresParser::startElementHandler(const char *tag, const char **attributes) { + if (TAG_GENRE == tag) { + const char *id = attributeValue(attributes, "id"); + const char *title = attributeValue(attributes, "title"); + const char *token = attributeValue(attributes, "token"); + std::string strId, strTitle, strToken; + if (id != 0) { + strId = id; + } + if (title != 0) { + strTitle = title; + } + if (token != 0) { + strToken = token; + } + saveGenre(new LitResGenre(strId, strTitle), strToken); + } +} + +void LitResGenresParser::endElementHandler(const char *tag) { + if (TAG_GENRE == tag) { + if (!myDontPopStack) { + myStack.pop_back(); + } + myDontPopStack = false; + } +} + +void LitResGenresParser::characterDataHandler(const char *, std::size_t) { +} + diff --git a/reader/src/network/litres/LitResGenresParser.h b/reader/src/network/litres/LitResGenresParser.h new file mode 100644 index 0000000..424d37b --- /dev/null +++ b/reader/src/network/litres/LitResGenresParser.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESGENRESPARSER_H__ +#define __LITRESGENRESPARSER_H__ + + +#include <map> +#include <vector> +#include <string> + +#include <ZLXMLReader.h> + +struct LitResGenre; + +class LitResGenresParser : public ZLXMLReader { + +public: + LitResGenresParser(std::vector<shared_ptr<LitResGenre> > &genresTree, std::map<std::string, shared_ptr<LitResGenre> > &genresMap); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + + void saveGenre(shared_ptr<LitResGenre> genre, const std::string &token); + + const std::string &titlePrefix(); + +private: + std::vector<shared_ptr<LitResGenre> > &myGenresTree; + std::map<std::string, shared_ptr<LitResGenre> > &myGenresMap; + std::vector<shared_ptr<LitResGenre> > myStack; + bool myDontPopStack; + + std::vector<std::string> myTitleStack; + std::string myTitlePrefix; +}; + +#endif /* __LITRESGENRESPARSER_H__ */ diff --git a/reader/src/network/litres/LitResRecommendationsItem.cpp b/reader/src/network/litres/LitResRecommendationsItem.cpp new file mode 100644 index 0000000..54d7cd7 --- /dev/null +++ b/reader/src/network/litres/LitResRecommendationsItem.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLNetworkUtil.h> + +#include "../NetworkLink.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "LitResRecommendationsItem.h" + +LitResRecommendationsItem::LitResRecommendationsItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility +) : OPDSCatalogItem( + link, + title, + summary, + urlByType, + accessibility +) { } + +std::string LitResRecommendationsItem::getCatalogUrl() { + LitResAuthenticationManager &mgr = (LitResAuthenticationManager&)*Link.authenticationManager(); + std::string catalogUrl = OPDSCatalogItem::getCatalogUrl(); + if (mgr.isAuthorised().Status == B3_FALSE) { + return catalogUrl; + } + std::string query = ZLStringUtil::join(mgr.getPurchasedIds(), ","); + ZLNetworkUtil::appendParameter(catalogUrl, "ids", query); + return catalogUrl; +} diff --git a/reader/src/network/litres/LitResRecommendationsItem.h b/reader/src/network/litres/LitResRecommendationsItem.h new file mode 100644 index 0000000..ba27623 --- /dev/null +++ b/reader/src/network/litres/LitResRecommendationsItem.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESRECOMMENDATIONSITEM_H__ +#define __LITRESRECOMMENDATIONSITEM_H__ + +#include "../opds/OPDSCatalogItem.h" + +class LitResRecommendationsItem : public OPDSCatalogItem { + +public: + LitResRecommendationsItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS + ); + +private: + std::string getCatalogUrl(); +}; + +#endif /* __LITRESRECOMMENDATIONSITEM_H__ */ diff --git a/reader/src/network/litres/LitResUtil.cpp b/reader/src/network/litres/LitResUtil.cpp new file mode 100644 index 0000000..992b7d9 --- /dev/null +++ b/reader/src/network/litres/LitResUtil.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkUtil.h> +#include <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "../opds/OPDSMetadata.h" + +#include "LitResBookshelfItem.h" +#include "LitResBooksFeedItem.h" +#include "LitResRecommendationsItem.h" +#include "LitResByGenresItem.h" +#include "LitResAuthorsItem.h" + +#include "LitResUtil.h" + + +static std::string LITRES_API_URL = "://robot.litres.ru/"; + +std::string LitResUtil::url(const std::string &path) { + std::string url = LITRES_API_URL + path; + if (ZLNetworkUtil::hasParameter(url, "sid") || + ZLNetworkUtil::hasParameter(url, "pwd")) { + url = "https" + url; + } else { + url = "http" + url; + } + return url; +} + +std::string LitResUtil::url(const NetworkLink &link, const std::string &path) { + std::string urlString = url(path); + link.rewriteUrl(urlString); + return urlString; +} + +std::string LitResUtil::url(bool secure, const std::string &path) { + std::string url = LITRES_API_URL + path; + if (secure) { + url = "https" + url; + } else { + url = "http" + url; + } + return url; +} + +std::string LitResUtil::url(const NetworkLink &link, bool secure, const std::string &path) { + std::string urlString = url(secure, path); + link.rewriteUrl(urlString, true); + return urlString; +} + +std::string LitResUtil::generateTrialUrl(std::string bookId) { + std::size_t len = bookId.length(); + if (len < 8) { + bookId = std::string(8 - len, '0') + bookId; + } + std::string query = "static/trials/%s/%s/%s/%s.fb2.zip"; + query = ZLStringUtil::printf(query, bookId.substr(0,2)); + query = ZLStringUtil::printf(query, bookId.substr(2,2)); + query = ZLStringUtil::printf(query, bookId.substr(4,2)); + query = ZLStringUtil::printf(query, bookId); + return url(false, query); +} + +std::string LitResUtil::generatePurchaseUrl(const NetworkLink &link, const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(link, true, "pages/purchase_book/" + query); +} + +std::string LitResUtil::generateDownloadUrl(const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(true, "pages/catalit_download_book/" + query); +} + +std::string LitResUtil::generateAlsoReadUrl(const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "rating", "with"); + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(false, "pages/catalit_browser/" + query); +} + +std::string LitResUtil::generateBooksByGenreUrl(const std::string &genreId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "checkpoint", "2000-01-01"); + ZLNetworkUtil::appendParameter(query, "genre", genreId); + return url(false, "pages/catalit_browser/" + query); +} + +std::string LitResUtil::generateBooksByAuthorUrl(const std::string &authorId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "checkpoint", "2000-01-01"); + ZLNetworkUtil::appendParameter(query, "person", authorId); + return url(false, "pages/catalit_browser/" + query); +} + +shared_ptr<NetworkItem> LitResUtil::createLitResNode(shared_ptr<ZLMimeType> type, std::string rel, const NetworkLink &link, std::string title, + std::string annotation, std::map<NetworkItem::URLType,std::string> urlMap, bool dependsOnAccount) { + static const std::string TYPE = "type"; + static const std::string NO = "no"; + + std::string litresType = type->getParameter(TYPE); + + if (rel == OPDSConstants::REL_BOOKSHELF) { + return new LitResBookshelfItem( + link, + title, + annotation, + urlMap, + NetworkCatalogItem::SIGNED_IN + ); + } else if (rel == OPDSConstants::REL_RECOMMENDATIONS) { + return new LitResRecommendationsItem( + (OPDSLink&)link, + title, + annotation, + urlMap, + NetworkCatalogItem::HAS_BOOKS + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_BOOKS->getParameter(TYPE)) { + int flags = NetworkCatalogItem::FLAGS_DEFAULT; + if (type->getParameter("groupSeries") == NO) { + flags &= ~NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES; + } + if (type->getParameter("showAuthor") == "false") { + flags &= ~NetworkCatalogItem::FLAG_SHOW_AUTHOR; + } + bool sort = type->getParameter("sort") != NO; + return new LitResBooksFeedItem( + sort, + link, + title, + annotation, + urlMap, + dependsOnAccount ? NetworkCatalogItem::SIGNED_IN : NetworkCatalogItem::ALWAYS, + flags + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_GENRES->getParameter(TYPE)) { + return new LitResByGenresItem( + LitResGenreMap::Instance().genresTree(), + link, + title, + annotation, + urlMap, + NetworkCatalogItem::ALWAYS, + NetworkCatalogItem::FLAG_SHOW_AUTHOR + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_AUTHORS->getParameter(TYPE)) { + return new LitResAuthorsItem( + link, + title, + annotation, + urlMap, + NetworkCatalogItem::ALWAYS + ); + } else { + return 0; + } +} diff --git a/reader/src/network/litres/LitResUtil.h b/reader/src/network/litres/LitResUtil.h new file mode 100644 index 0000000..fd23a08 --- /dev/null +++ b/reader/src/network/litres/LitResUtil.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LITRESUTIL_H__ +#define __LITRESUTIL_H__ + +#include <string> + +#include "../NetworkItems.h" + +class NetworkLink; + +class LitResUtil { + +public: + static std::string url(const std::string &path); + static std::string url(const NetworkLink &link, const std::string &path); + static std::string url(const NetworkLink &link, bool secure, const std::string &path); + static std::string url(bool secure, const std::string &path); + + static std::string generateTrialUrl(std::string bookId); + static std::string generatePurchaseUrl(const NetworkLink &link, const std::string &bookId); + static std::string generateDownloadUrl(const std::string &bookId); + static std::string generateAlsoReadUrl(const std::string &bookId); + static std::string generateBooksByGenreUrl(const std::string &genreId); + static std::string generateBooksByAuthorUrl(const std::string &authorId); + +public: + static shared_ptr<NetworkItem> createLitResNode(shared_ptr<ZLMimeType> type, std::string rel, + const NetworkLink &link, std::string title, + std::string annotation, std::map<NetworkItem::URLType,std::string> urlMap, + bool dependsOnAccount); + +private: + LitResUtil(); +}; + +#endif /* __LITRESUTIL_H__ */ diff --git a/reader/src/network/litres/SortedCatalogItem.cpp b/reader/src/network/litres/SortedCatalogItem.cpp new file mode 100644 index 0000000..79d7f49 --- /dev/null +++ b/reader/src/network/litres/SortedCatalogItem.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "SortedCatalogItem.h" + +bool SortedCatalogItem::BookItemFilter::accepts(NetworkItem* item) const { + return zlobject_cast<NetworkBookItem*>(item) != 0; +} + +bool SortedCatalogItem::BySeriesFilter::accepts(NetworkItem* item) const { + NetworkBookItem* bookItem = zlobject_cast<NetworkBookItem*>(item); + return bookItem != 0 && !bookItem->SeriesTitle.empty(); +} + +SortedCatalogItem::SortedCatalogItem(const NetworkCatalogItem &parent, const ZLResource &resource, + const NetworkItem::List &children, int flags) + : NetworkCatalogItem(parent.Link, resource.value(), resource["summary"].value(), parent.URLByType, ALWAYS, flags) { + myChildren = children; +} + +std::string SortedCatalogItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + children.assign(myChildren.begin(), myChildren.end()); + listener->finished(); + return std::string(); +} + +bool SortedCatalogItem::isEmpty() const { + return myChildren.empty(); +} + +const ZLResource &SortedCatalogItem::resource(const std::string &resourceKey) { + return ZLResource::resource("networkView")[resourceKey]; +} diff --git a/reader/src/network/litres/SortedCatalogItem.h b/reader/src/network/litres/SortedCatalogItem.h new file mode 100644 index 0000000..e4f2744 --- /dev/null +++ b/reader/src/network/litres/SortedCatalogItem.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __SORTEDCATALOGITEM_H__ +#define __SORTEDCATALOGITEM_H__ + +#include <algorithm> + +#include <ZLResource.h> + +#include "../NetworkComparators.h" +#include "../NetworkItems.h" + +class SortedCatalogItem : public NetworkCatalogItem { + +public: + class BookItemFilter { + public: + bool accepts(NetworkItem* item) const; + }; + + class BySeriesFilter { + public: + bool accepts(NetworkItem* item) const; + }; + + //TODO maybe refactor (using templates is too complex for this simple case + //(templates were used because in C++ virtual methods can't be called from constructor) + template <class T, class F> + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator, F filter); + template <class T> + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator); + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags); + +public: + SortedCatalogItem(const NetworkCatalogItem &parent, const ZLResource &resource, const NetworkItem::List &children, int flags); + +public: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + bool isEmpty() const; + //TODO following method should be in class NetworkLibrary or smth like that + static const ZLResource &resource(const std::string &resourceKey); + +protected: + NetworkItem::List myChildren; +}; + +template <class T, class F> +SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator, F filter) { + NetworkItem::List tmpChildren; + for (std::size_t i = 0; i < children.size(); ++i) { + shared_ptr<NetworkItem> child = children.at(i); + if (filter.accepts(&(*child))) { + tmpChildren.push_back(child); + } + } + std::sort(tmpChildren.begin(), tmpChildren.end(), comparator); + return new SortedCatalogItem(parent, resource(resourceKey), tmpChildren, flags); +} + +template <class T> +SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator) { + return create(parent, resourceKey, children, flags, comparator, BookItemFilter()); +} + +inline SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags) { + BookItemFilter filter; + NetworkItem::List tmpChildren; + for (std::size_t i = 0; i < children.size(); ++i) { + shared_ptr<NetworkItem> child = children.at(i); + if (filter.accepts(&(*child))) { + tmpChildren.push_back(child); + } + } + return new SortedCatalogItem(parent, resource(resourceKey), tmpChildren, flags); +} + +#endif /* __SORTEDCATALOGITEM_H__ */ diff --git a/reader/src/network/opds/NetworkOPDSFeedReader.cpp b/reader/src/network/opds/NetworkOPDSFeedReader.cpp new file mode 100644 index 0000000..3c1ad0a --- /dev/null +++ b/reader/src/network/opds/NetworkOPDSFeedReader.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLMimeType.h> + +#include "NetworkOPDSFeedReader.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" + +#include "../NetworkOperationData.h" +#include "../NetworkItems.h" +#include "../BookReference.h" +#include "OPDSBookItem.h" + +#include "../litres/LitResUtil.h" + + +NetworkOPDSFeedReader::NetworkOPDSFeedReader( + const OPDSLink &link, + const std::string &baseURL, + NetworkOperationData &result +) : + myLink(link), + myBaseURL(baseURL), + myData(result), + myIndex(0), + myOpenSearchStartIndex(0) { +} + +void NetworkOPDSFeedReader::processFeedStart() { +} + +void NetworkOPDSFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) { + for (std::size_t i = 0; i < feed->links().size(); ++i) { + ATOMLink &link = *(feed->links()[i]); + const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = myLink.relation(link.rel(), link.type()); + if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + if (rel == "self") { + } else if (rel == "next") { + myData.ResumeURI = href; + } + } + } + myOpenSearchStartIndex = feed->getOpensearchStartIndex() - 1; +} + + +void NetworkOPDSFeedReader::processFeedEnd() { + for (std::size_t i = 0; i < myData.Items.size(); ++i) { + NetworkItem &item = *myData.Items[i]; + if (!item.isInstanceOf(NetworkBookItem::TYPE_ID)) { + continue; + } + NetworkBookItem &book = (NetworkBookItem&) item; + book.Index += myOpenSearchStartIndex; + } +} + +void NetworkOPDSFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + if (entry.isNull()) { + return; + } + + std::map<std::string,OPDSLink::FeedCondition>::const_iterator it = myLink.myFeedConditions.find(entry->id()->uri()); + if (it != myLink.myFeedConditions.end() && it->second == OPDSLink::CONDITION_NEVER) { + return; + } + OPDSEntry &e = *entry; + bool hasBookLink = false; + for (std::size_t i = 0; i < e.links().size(); ++i) { + ATOMLink &link = *(e.links()[i]); + const std::string &type = link.type(); + const std::string &rel = myLink.relation(link.rel(), type); + if (rel == OPDSConstants::REL_ACQUISITION || + rel == OPDSConstants::REL_ACQUISITION_OPEN || + rel == OPDSConstants::REL_ACQUISITION_SAMPLE || + rel == OPDSConstants::REL_ACQUISITION_BUY || + rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL || + rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL || + (rel.empty() && OPDSBookItem::formatByZLMimeType(type) != BookReference::NONE)) { + hasBookLink = true; + break; + } + } + + shared_ptr<NetworkItem> item; + if (hasBookLink) { + item = new OPDSBookItem(myLink, e, myBaseURL, myIndex++); + } else { + item = readCatalogItem(e); + } + if (!item.isNull()) { + myData.Items.push_back(item); + } +} + +shared_ptr<NetworkItem> NetworkOPDSFeedReader::readCatalogItem(OPDSEntry &entry) { + std::string coverURL; + std::string url; + bool urlIsAlternate = false; + std::string htmlURL; + std::string litresRel; + shared_ptr<ZLMimeType> litresMimeType; + int catalogFlags = NetworkCatalogItem::FLAGS_DEFAULT; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = myLink.relation(link.rel(), link.type()); + if (ZLMimeType::isImage(type)) { + if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + coverURL = href; + } else if (coverURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) { + coverURL = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + if (rel == ATOMConstants::REL_ALTERNATE) { + if (url.empty()) { + url = href; + urlIsAlternate = true; + } + } else { + url = href; + urlIsAlternate = false; + if (rel == OPDSConstants::REL_CATALOG_AUTHOR) { + catalogFlags &= !NetworkCatalogItem::FLAG_SHOW_AUTHOR; + } + } + } else if (type->weakEquals(*ZLMimeType::TEXT_HTML)) { + if (rel == OPDSConstants::REL_ACQUISITION || + rel == ATOMConstants::REL_ALTERNATE || + rel.empty()) { + htmlURL = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_LITRES_XML)) { + url = href; + litresRel = rel; + litresMimeType = type; + } + } + + if (url.empty() && htmlURL.empty()) { + return 0; + } + + if (!url.empty() && !urlIsAlternate) { + htmlURL.erase(); + } + + std::map<std::string,OPDSLink::FeedCondition>::const_iterator it = + myLink.myFeedConditions.find(entry.id()->uri()); + bool dependsOnAccount = + it != myLink.myFeedConditions.end() && + it->second == OPDSLink::CONDITION_SIGNED_IN; + + std::string annotation = entry.summary(); + annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x09), annotation.end()); + annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x0A), annotation.end()); + NetworkItem::UrlInfoCollection urlMap; + urlMap[NetworkItem::URL_COVER] = coverURL; + urlMap[NetworkItem::URL_CATALOG] = url; + urlMap[NetworkItem::URL_HTML_PAGE] = htmlURL; + + if (!litresMimeType.isNull()) { + return LitResUtil::createLitResNode(litresMimeType, litresRel, myData.Link, entry.title(), annotation, urlMap, dependsOnAccount); + } + return new OPDSCatalogItem( + (OPDSLink&)myData.Link, + entry.title(), + annotation, + urlMap, + dependsOnAccount ? NetworkCatalogItem::SIGNED_IN : NetworkCatalogItem::ALWAYS, + catalogFlags + ); +} diff --git a/reader/src/network/opds/NetworkOPDSFeedReader.h b/reader/src/network/opds/NetworkOPDSFeedReader.h new file mode 100644 index 0000000..f51b1bf --- /dev/null +++ b/reader/src/network/opds/NetworkOPDSFeedReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKOPDSFEEDREADER_H__ +#define __NETWORKOPDSFEEDREADER_H__ + +#include <map> +#include <string> + +#include "OPDSFeedReader.h" +#include "OPDSLink.h" + +class NetworkOperationData; + +class NetworkItem; + +class NetworkOPDSFeedReader : public OPDSFeedReader { + +public: + NetworkOPDSFeedReader( + const OPDSLink &link, + const std::string &baseURL, + NetworkOperationData &result + ); + +public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + +private: + shared_ptr<NetworkItem> readCatalogItem(OPDSEntry &entry); + +private: + const OPDSLink &myLink; + const std::string myBaseURL; + NetworkOperationData &myData; + unsigned int myIndex; + unsigned int myOpenSearchStartIndex; +}; + + +#endif /* __NETWORKOPDSFEEDREADER_H__ */ diff --git a/reader/src/network/opds/OPDSBookItem.cpp b/reader/src/network/opds/OPDSBookItem.cpp new file mode 100644 index 0000000..6899afa --- /dev/null +++ b/reader/src/network/opds/OPDSBookItem.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkManager.h> +#include <ZLNetworkUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "OPDSXMLParser.h" + +#include "OPDSBookItem.h" +#include "OPDSCatalogItem.h" + +#include "../tree/NetworkTreeFactory.h" + +OPDSBookItem::OPDSBookItem(const OPDSLink &link, OPDSEntry &entry, std::string baseUrl, unsigned int index) : + NetworkBookItem( + link, + entry.id()->uri(), + index, + entry.title(), + getAnnotation(entry), + entry.dcLanguage(), + getDate(entry), + getAuthors(entry), + getTags(entry), + entry.seriesTitle(), + entry.seriesIndex(), + getUrls(link, entry, baseUrl), + getReferences(link, entry, baseUrl) + ) { + myRelatedInfos = getRelatedUrls(link, entry, baseUrl); + myInformationIsFull = false; +} + +bool OPDSBookItem::isFullyLoaded() const { + return myInformationIsFull || URLByType.find(URL_SINGLE_ENTRY) == URLByType.end(); +} + +class OPDSBookItemFullInfoLoader : public ZLNetworkRequest::Listener { +public: + OPDSBookItemFullInfoLoader(OPDSBookItem &item, shared_ptr<ZLNetworkRequest> request, shared_ptr<ZLNetworkRequest::Listener> listener) : + myItem(item), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + + void finished(const std::string &error) { + if (error.empty()) { + myItem.myInformationIsFull = true; + } + myListener->finished(error); + } +private: + OPDSBookItem &myItem; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + +void OPDSBookItem::loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener) { + if (myInformationIsFull) { + listener->finished(); + return; + } + + if (URLByType.find(URL_SINGLE_ENTRY) == URLByType.end()) { + myInformationIsFull = true; + listener->finished(); + return; + } + + std::string url = URLByType[URL_SINGLE_ENTRY]; + shared_ptr<ZLNetworkRequest> request = ZLNetworkManager::Instance().createXMLParserRequest( + url, new OPDSXMLParser(new FullEntryReader(*this, (const OPDSLink&)Link, url), true) + ); + + new OPDSBookItemFullInfoLoader(*this, request, listener); +} + +std::vector<shared_ptr<NetworkItem> > OPDSBookItem::getRelatedCatalogsItems() const { + std::vector<shared_ptr<NetworkItem> > items; + for (std::size_t i = 0; i < myRelatedInfos.size(); ++i) { + shared_ptr<RelatedUrlInfo> urlInfo = myRelatedInfos.at(i); + if (!urlInfo->MimeType->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + continue; + //TODO implement items for loading link in browser + } + UrlInfoCollection urlByType = URLByType; + urlByType[URL_CATALOG] = urlInfo->Url; + OPDSCatalogItem *item = new OPDSCatalogItem(static_cast<const OPDSLink&>(Link), urlInfo->Title, std::string(), urlByType); + items.push_back(item); + } + return items; +} + +std::string OPDSBookItem::getAnnotation(OPDSEntry &entry) { + //TODO implement ATOMContent support (and return content) + return entry.summary(); +} + +std::string OPDSBookItem::getDate(OPDSEntry &entry) { + std::string date; + if (!entry.dcIssued().isNull()) { + date = entry.dcIssued()->getDateTime(true); + } + return date; +} + +std::vector<NetworkBookItem::AuthorData> OPDSBookItem::getAuthors(OPDSEntry &entry) { + std::vector<NetworkBookItem::AuthorData> authors; + for (std::size_t i = 0; i < entry.authors().size(); ++i) { + ATOMAuthor &author = *(entry.authors()[i]); + NetworkBookItem::AuthorData authorData; + std::string name = author.name(); + std::string lowerCased = ZLUnicodeUtil::toLower(name); + static const std::string authorPrefix = "author:"; + std::size_t index = lowerCased.find(authorPrefix); + if (index != std::string::npos) { + name = name.substr(index + authorPrefix.size()); + } else { + static const std::string authorsPrefix = "authors:"; + index = lowerCased.find(authorsPrefix); + if (index != std::string::npos) { + name = name.substr(index + authorsPrefix.size()); + } + } + index = name.find(','); + if (index != std::string::npos) { + std::string before = name.substr(0, index); + std::string after = name.substr(index + 1); + ZLUnicodeUtil::utf8Trim(before); + ZLUnicodeUtil::utf8Trim(after); + authorData.SortKey = before; + authorData.DisplayName = after + ' ' + before; + } else { + ZLUnicodeUtil::utf8Trim(name); + index = name.rfind(' '); + authorData.SortKey = name.substr(index + 1); + authorData.DisplayName = name; + } + authors.push_back(authorData); + } + return authors; +} + +std::vector<std::string> OPDSBookItem::getTags(OPDSEntry &entry) { + std::vector<std::string> tags; + for (std::size_t i = 0; i < entry.categories().size(); ++i) { + ATOMCategory &category = *(entry.categories()[i]); + tags.push_back(category.label()); + } + return tags; +} + +NetworkItem::UrlInfoCollection OPDSBookItem::getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ + NetworkItem::UrlInfoCollection urlMap; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + if (ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX) || rel == OPDSConstants::REL_COVER) { + if (urlMap[NetworkItem::URL_COVER].empty() && ZLMimeType::isImage(type)) { + urlMap[NetworkItem::URL_COVER] = href; + } + } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + if (ZLMimeType::isImage(type)) { + urlMap[NetworkItem::URL_COVER] = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML) && + rel == ATOMConstants::REL_ALTERNATE && + type->getParameter("type") == "entry") { + urlMap[NetworkItem::URL_SINGLE_ENTRY] = href; + } + } + return urlMap; +} + +OPDSBookItem::RelatedUrlsList OPDSBookItem::getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + OPDSBookItem::RelatedUrlsList relatedUrlList; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + if (rel == ATOMConstants::REL_RELATED) { + relatedUrlList.push_back(new RelatedUrlInfo(link.title(), type, href)); + } + } + return relatedUrlList; +} + +std::vector<shared_ptr<BookReference> > OPDSBookItem::getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ + std::vector<shared_ptr<BookReference> > references; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + const BookReference::Type referenceType = typeByRelation(rel); + if (referenceType == BookReference::BUY) { + std::string price = BuyBookReference::price( + link.userData(OPDSXMLParser::KEY_PRICE), + link.userData(OPDSXMLParser::KEY_CURRENCY) + ); + if (price.empty()) { + price = BuyBookReference::price( + entry.userData(OPDSXMLParser::KEY_PRICE), + entry.userData(OPDSXMLParser::KEY_CURRENCY) + ); + } + if (type == ZLMimeType::TEXT_HTML) { + references.push_back(new BuyBookReference( + href, BookReference::NONE, BookReference::BUY_IN_BROWSER, price + )); + } else { + BookReference::Format format = formatByZLMimeType(link.userData(OPDSXMLParser::KEY_FORMAT)); + if (format != BookReference::NONE) { + references.push_back(new BuyBookReference( + href, format, BookReference::BUY, price + )); + } + } + } else if (referenceType != BookReference::UNKNOWN) { + BookReference::Format format = formatByZLMimeType(link.type()); + if (format != BookReference::NONE) { + references.push_back(new BookReference(href, format, referenceType)); + } + } + } + return references; +} + +BookReference::Format OPDSBookItem::formatByZLMimeType(const std::string &mimeType) { + shared_ptr<ZLMimeType> type = ZLMimeType::get(mimeType); + if (type == ZLMimeType::APPLICATION_FB2_ZIP) { + return BookReference::FB2_ZIP; + } else if (type == ZLMimeType::APPLICATION_EPUB_ZIP) { + return BookReference::EPUB; + } else if (type == ZLMimeType::APPLICATION_MOBIPOCKET_EBOOK) { + return BookReference::MOBIPOCKET; + } + return BookReference::NONE; +} + +BookReference::Type OPDSBookItem::typeByRelation(const std::string &rel) { + if (rel == OPDSConstants::REL_ACQUISITION || rel == OPDSConstants::REL_ACQUISITION_OPEN || rel.empty()) { + return BookReference::DOWNLOAD_FULL; + } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE) { + return BookReference::DOWNLOAD_DEMO; + } else if (rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL) { + return BookReference::DOWNLOAD_FULL_CONDITIONAL; + } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL) { + return BookReference::DOWNLOAD_FULL_OR_DEMO; + } else if (rel == OPDSConstants::REL_ACQUISITION_BUY) { + return BookReference::BUY; + } else { + return BookReference::UNKNOWN; + } +} + +OPDSBookItem::FullEntryReader::FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url) : + myItem(item), myLink(link), myUrl(url) { +} + +void OPDSBookItem::FullEntryReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + NetworkItem::UrlInfoCollection urlMap = OPDSBookItem::getUrls(myLink, *entry, myUrl); + std::vector<shared_ptr<BookReference> > references = OPDSBookItem::getReferences(myLink, *entry, myUrl); + for (NetworkItem::UrlInfoCollection::iterator it = urlMap.begin(); it != urlMap.end(); ++it) { + myItem.URLByType[(*it).first] = (*it).second; + } + myItem.updateReferences(references); + std::string summary = OPDSBookItem::getAnnotation(*entry); + if (!summary.empty()) { + myItem.Summary = summary; + } + myItem.myRelatedInfos = OPDSBookItem::getRelatedUrls(myLink, *entry, myUrl); +} + +void OPDSBookItem::FullEntryReader::processFeedStart() { +} + +void OPDSBookItem::FullEntryReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> /*feed*/) { +} + +void OPDSBookItem::FullEntryReader::processFeedEnd() { +} + +OPDSBookItem::RelatedUrlInfo::RelatedUrlInfo(const std::string &title, shared_ptr<ZLMimeType> mimeType, const std::string url) : + Title(title), MimeType(mimeType), Url(url) { } + + diff --git a/reader/src/network/opds/OPDSBookItem.h b/reader/src/network/opds/OPDSBookItem.h new file mode 100644 index 0000000..8b3ddbd --- /dev/null +++ b/reader/src/network/opds/OPDSBookItem.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSBOOKITEM_H__ +#define __OPDSBOOKITEM_H__ + +#include "OPDSLink.h" +#include "OPDSMetadata.h" +#include "OPDSFeedReader.h" + +class OPDSBookItem : public NetworkBookItem { + +public: + OPDSBookItem(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl, unsigned int index); + +public: + bool isFullyLoaded() const; + void loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener); + std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + +public: + static BookReference::Format formatByZLMimeType(const std::string &mimeType); + static BookReference::Type typeByRelation(const std::string &rel); + +protected: + static std::string getAnnotation(OPDSEntry &entry); + static std::string getDate(OPDSEntry &entry); + static std::vector<AuthorData> getAuthors(OPDSEntry &entry); + static std::vector<std::string> getTags(OPDSEntry &entry); + static UrlInfoCollection getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); + //TODO implement one UrlInfoCollection to not duplicate similar methods + static std::vector<shared_ptr<BookReference> > getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); + +private: + class FullEntryReader : public OPDSFeedReader { + + public: + FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url); + + public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + + private: + OPDSBookItem &myItem; + const OPDSLink &myLink; + std::string myUrl; + }; + + class RelatedUrlInfo { + public: + RelatedUrlInfo(const std::string& title, shared_ptr<ZLMimeType> mimeType, const std::string url); + + std::string Title; + shared_ptr<ZLMimeType> MimeType; + std::string Url; + }; + + typedef std::vector<shared_ptr<RelatedUrlInfo> > RelatedUrlsList; + RelatedUrlsList myRelatedInfos; +protected: + static RelatedUrlsList getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); +private: + bool myInformationIsFull; + +friend class OPDSBookItemFullInfoLoader; + +}; + +#endif /* __OPDSBOOKITEM_H__ */ diff --git a/reader/src/network/opds/OPDSCatalogItem.cpp b/reader/src/network/opds/OPDSCatalogItem.cpp new file mode 100644 index 0000000..853bc4c --- /dev/null +++ b/reader/src/network/opds/OPDSCatalogItem.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkRequest.h> +#include <ZLNetworkManager.h> + +#include "OPDSCatalogItem.h" +#include "OPDSLink.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" + +OPDSCatalogItem::OPDSCatalogItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags + ) : NetworkCatalogItem(link, title, summary, urlByType, accessibility, flags), myLoadingState(Link) { +} + +class OPDSCatalogItemRunnable : public ZLNetworkRequest::Listener { +public: + OPDSCatalogItemRunnable(shared_ptr<ZLNetworkRequest> request, NetworkItem::List &children, NetworkOperationData &data, shared_ptr<ZLNetworkRequest::Listener> listener) : + myChildren(children), myLoadingData(data), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + void finished(const std::string &error) { + myChildren.insert(myChildren.end(), myLoadingData.Items.begin(), myLoadingData.Items.end()); + myListener->finished(error); + } + void setUIStatus(bool enabled) { + myListener->setUIStatus(enabled); //to hide refreshing while authentication dialog + } + +private: + NetworkItem::List &myChildren; + NetworkOperationData &myLoadingData; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + + +std::string OPDSCatalogItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + myLoadingState.clear(); + shared_ptr<ZLNetworkRequest> request = ((OPDSLink&)Link).createNetworkRequest(getCatalogUrl(), myLoadingState); + new OPDSCatalogItemRunnable(request, children, myLoadingState, listener); + return std::string(); +} + +bool OPDSCatalogItem::supportsResumeLoading() { + return true; +} + +std::string OPDSCatalogItem::resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + shared_ptr<ZLNetworkRequest> request = myLoadingState.resume(); + if (request.isNull()) { + listener->finished(); + return std::string(); + } + new OPDSCatalogItemRunnable(request, children, myLoadingState, listener); + return std::string(); +} diff --git a/reader/src/network/opds/OPDSCatalogItem.h b/reader/src/network/opds/OPDSCatalogItem.h new file mode 100644 index 0000000..e2bc787 --- /dev/null +++ b/reader/src/network/opds/OPDSCatalogItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSCATALOGITEM_H__ +#define __OPDSCATALOGITEM_H__ + +#include <ZLExecutionUtil.h> + +#include "../NetworkItems.h" +#include "../NetworkOperationData.h" + +class OPDSLink; + +class OPDSCatalogItem : public NetworkCatalogItem { + +public: + OPDSCatalogItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + +public: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + bool supportsResumeLoading(); + std::string resumeLoading(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + +private: + NetworkOperationData myLoadingState; +}; + +#endif /* __OPDSCATALOGITEM_H__ */ diff --git a/reader/src/network/opds/OPDSFeedReader.h b/reader/src/network/opds/OPDSFeedReader.h new file mode 100644 index 0000000..a842f41 --- /dev/null +++ b/reader/src/network/opds/OPDSFeedReader.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSFEEDREADER_H__ +#define __OPDSFEEDREADER_H__ + +#include "OPDSMetadata.h" + + +class OPDSFeedReader { + +public: + OPDSFeedReader() {} + virtual ~OPDSFeedReader() {} + +public: + virtual void processFeedEntry(shared_ptr<OPDSEntry> entry) = 0; + virtual void processFeedStart() = 0; + virtual void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) = 0; + virtual void processFeedEnd() = 0; +}; + + +#endif /* __OPDSFEEDREADER_H__ */ diff --git a/reader/src/network/opds/OPDSLink.cpp b/reader/src/network/opds/OPDSLink.cpp new file mode 100644 index 0000000..f682b7d --- /dev/null +++ b/reader/src/network/opds/OPDSLink.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> + +#include "OPDSLink.h" +#include "OPDSLink_AdvancedSearch.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" +#include "../authentication/NetworkAuthenticationManager.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "URLRewritingRule.h" + +OPDSLink::AdvancedSearch::AdvancedSearch( + const std::string &type, + const std::string &titleParameter, + const std::string &authorParameter, + const std::string &tagParameter, + const std::string &annotationParameter +) : myType(type), myTitleParameter(titleParameter), myAuthorParameter(authorParameter), myTagParameter(tagParameter), myAnnotationParameter(annotationParameter) { +} + +void OPDSLink::AdvancedSearch::addSubQuery(std::string &query, const std::string &name, const std::string &value) const { + if (value.empty()) { + return; + } + + if (myType == "separateWords") { + std::size_t start = 0, end; + do { + end = value.find(' ', start); + std::string ss = value.substr(start, end - start); + ZLUnicodeUtil::utf8Trim(ss); + if (!ss.empty()) { + if (!query.empty()) { + query.append("+"); + } + query.append(name + ':'); + query.append(ZLNetworkUtil::htmlEncode(ss)); + } + start = end + 1; + } while (end != std::string::npos); + } else if (myType == "quoted") { + std::string encodedValue = value; + ZLUnicodeUtil::utf8Trim(encodedValue); + + if (encodedValue.empty()) { + return; + } + encodedValue = '"' + encodedValue + '"'; + std::replace(encodedValue.begin(), encodedValue.end(), ' ', '+'); + + if (!query.empty()) { + query += '+'; + } + query += name + ':' + ZLNetworkUtil::htmlEncode(encodedValue); + } +} + +std::string OPDSLink::AdvancedSearch::query( + const std::string &titleOrSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation +) const { + std::string query; + addSubQuery(query, myTitleParameter, titleOrSeries); + addSubQuery(query, myAuthorParameter, author); + addSubQuery(query, myTagParameter, tag); + addSubQuery(query, myAnnotationParameter, annotation); + return query; +} + +//shared_ptr<NetworkLink> OPDSLink::read(const ZLFile &file) { +// Reader reader; +// reader.readDocument(file); +// return reader.link(); +//} + +shared_ptr<ZLNetworkRequest> OPDSLink::createNetworkRequest(const std::string &url, NetworkOperationData &result) const { + if (url.empty()) { + return 0; + } + std::string modifiedUrl(url); + rewriteUrl(modifiedUrl); + return ZLNetworkManager::Instance().createXMLParserRequest(modifiedUrl, new OPDSXMLParser(new NetworkOPDSFeedReader(*this, url, result)) ); +} + +OPDSLink::OPDSLink( + const std::string &siteName +) : NetworkLink(siteName) { +} + +OPDSLink::~OPDSLink() { +} + +shared_ptr<NetworkItem> OPDSLink::libraryItem() const { + NetworkItem::UrlInfoCollection urlMap; + urlMap[NetworkItem::URL_COVER] = getIcon(); + urlMap[NetworkItem::URL_CATALOG] = url(URL_MAIN); + return new OPDSCatalogItem(*this, getTitle(), getSummary(), urlMap); +} + +const std::string OPDSLink::searchURL(const std::string &query) const { + return ZLStringUtil::printf(url(URL_SEARCH), query); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::simpleSearchData(NetworkOperationData &result, const std::string &pattern) const { + return createNetworkRequest( + searchURL(ZLNetworkUtil::htmlEncode(pattern)), + result + ); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::advancedSearchData( + NetworkOperationData &result, + const std::string &titleAndSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation +) const { + if (myAdvancedSearch.isNull()) { + return 0; + } + std::string query = myAdvancedSearch->query( + titleAndSeries, author, tag, annotation + ); + return query.empty() ? 0 : createNetworkRequest(searchURL(query), result); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::resume(NetworkOperationData &data) const { + const std::string url = data.ResumeURI; + return createNetworkRequest(url, data); +} + +shared_ptr<NetworkAuthenticationManager> OPDSLink::authenticationManager() const { + return myAuthenticationManager; +} + +void OPDSLink::setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules) { + myUrlRewritingRules = rules; +} + +void OPDSLink::setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager) { + myAuthenticationManager = manager; +} + +void OPDSLink::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) { + myAdvancedSearch = advancedSearch; +} + +void OPDSLink::setRelationAliases(std::map<RelationAlias, std::string> relationAliases) { + myRelationAliases = relationAliases; +} + +void OPDSLink::rewriteUrl(std::string &url, bool isUrlExternal) const { + URLRewritingRule::RuleApply apply = isUrlExternal ? URLRewritingRule::EXTERNAL : URLRewritingRule::INTERNAL; + for (std::vector<shared_ptr<URLRewritingRule> >::const_iterator it = myUrlRewritingRules.begin(); it != myUrlRewritingRules.end(); ++it) { + const URLRewritingRule &rule = **it; + if (rule.whereToApply() == apply) { + url = rule.apply(url); + } + } +} + +OPDSLink::RelationAlias::RelationAlias(const std::string &alias, const std::string &type) : Alias(alias), Type(type) { +} + +bool OPDSLink::RelationAlias::operator < (const RelationAlias &alias) const { + int cmp = Alias.compare(alias.Alias); + if (cmp != 0) { + return cmp < 0; + } + return Type < alias.Type; +} + +const std::string &OPDSLink::relation(const std::string &rel, const std::string &type) const { + RelationAlias alias(rel, type); + std::map<RelationAlias,std::string>::const_iterator it = myRelationAliases.find(alias); + if (it != myRelationAliases.end()) { + return it->second; + } + if (!type.empty()) { + alias.Type.erase(); + it = myRelationAliases.find(alias); + if (it != myRelationAliases.end()) { + return it->second; + } + } + return rel; +} diff --git a/reader/src/network/opds/OPDSLink.h b/reader/src/network/opds/OPDSLink.h new file mode 100644 index 0000000..d6fd87e --- /dev/null +++ b/reader/src/network/opds/OPDSLink.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSLINK_H__ +#define __OPDSLINK_H__ + +#include <map> +#include <vector> +#include <string> + +#include "../NetworkLink.h" + +class ZLFile; + +class NetworkAuthenticationManager; +struct URLRewritingRule; + +class OPDSLink : public NetworkLink { + +public: + enum FeedCondition { + CONDITION_NEVER, + CONDITION_SIGNED_IN, + }; + +private: + class AdvancedSearch; + +public: + class GenericReader; + class FeedReader; + class GenericFeedReader; + class GenericXMLParser; + + OPDSLink( + const std::string &siteName + ); + +public: + ~OPDSLink(); + +private: + struct RelationAlias; + +public: + void setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules); + void setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager); + void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch); + void setRelationAliases(std::map<RelationAlias, std::string> relationAliases); + +private: + const std::string searchURL(const std::string &pattern) const; + + shared_ptr<ZLNetworkRequest> createNetworkRequest(const std::string &url, NetworkOperationData &result) const; + + shared_ptr<ZLNetworkRequest> simpleSearchData( + NetworkOperationData &result, + const std::string &pattern) const; + shared_ptr<ZLNetworkRequest> advancedSearchData( + NetworkOperationData &result, + const std::string &titleAndSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation) const; + shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &result) const; + + shared_ptr<NetworkItem> libraryItem() const; + shared_ptr<NetworkAuthenticationManager> authenticationManager() const; + + void rewriteUrl(std::string &url, bool isUrlExternal = false) const; + + const std::string &relation(const std::string &rel, const std::string &type) const; + +private: + shared_ptr<AdvancedSearch> myAdvancedSearch; + + struct RelationAlias { + std::string Alias; + std::string Type; + + RelationAlias(const std::string &alias, const std::string &type); + bool operator < (const RelationAlias &other) const; + }; + std::map<RelationAlias, std::string> myRelationAliases; + + std::map<std::string,FeedCondition> myFeedConditions; + std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules; + + shared_ptr<NetworkAuthenticationManager> myAuthenticationManager; + +friend class NetworkOPDSFeedReader; +friend class OPDSCatalogItem; +friend class OPDSBookItem; +}; + +#endif /* __OPDSLINK_H__ */ diff --git a/reader/src/network/opds/OPDSLink_AdvancedSearch.h b/reader/src/network/opds/OPDSLink_AdvancedSearch.h new file mode 100644 index 0000000..76519c9 --- /dev/null +++ b/reader/src/network/opds/OPDSLink_AdvancedSearch.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSLINK_ADVANCEDSEARCH_H__ +#define __OPDSLINK_ADVANCEDSEARCH_H__ + +#include <string> +/* +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> + +#include "OPDSLink.h" +#include "OPDSLinkReader.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" +#include "../authentication/NetworkAuthenticationManager.h" + +#include "URLRewritingRule.h" +*/ + +class OPDSLink::AdvancedSearch { + +public: + AdvancedSearch( + const std::string &type, + const std::string &titleParameter, + const std::string &authorParameter, + const std::string &tagParameter, + const std::string &annotationParameter + ); + + std::string query( + const std::string &titleOrSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation + ) const; + +private: + void addSubQuery(std::string &query, const std::string &name, const std::string &value) const; + +private: + const std::string myType; + const std::string myTitleParameter; + const std::string myAuthorParameter; + const std::string myTagParameter; + const std::string myAnnotationParameter; +}; + +#endif /* __OPDSLINK_ADVANCEDSEARCH_H__ */ diff --git a/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp b/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp new file mode 100644 index 0000000..5389f2d --- /dev/null +++ b/reader/src/network/opds/OPDSLink_GenericFeedReader.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkUtil.h> +#include <ZLStringUtil.h> +#include <ZLMimeType.h> +#include <ZLNetworkRequest.h> +#include <ZLNetworkManager.h> + +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "OPDSLink_GenericFeedReader.h" +#include "OpenSearchXMLReader.h" + +OPDSLink::GenericFeedReader::GenericFeedReader( + std::vector<shared_ptr<NetworkLink> >& links +) : + myLinks(links) { +} + +void OPDSLink::GenericFeedReader::processFeedStart() { +} + +void OPDSLink::GenericFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata>) { + +} + + +void OPDSLink::GenericFeedReader::processFeedEnd() { +} + +void OPDSLink::GenericFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + std::map<std::string,std::string> links; + std::string iconURL; + for (std::size_t i = 0; i < entry->links().size(); ++i) { + ATOMLink &link = *(entry->links()[i]); + const std::string &href = link.href(); + const std::string &rel = link.rel(); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + if (rel == NetworkLink::URL_SEARCH) { + links[rel] = OpenSearchXMLReader::convertOpenSearchURL(href); + } else if (rel == "") { + links[NetworkLink::URL_MAIN] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_IN) { + links[NetworkLink::URL_SIGN_IN] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_OUT) { + links[NetworkLink::URL_SIGN_OUT] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_UP) { + links[NetworkLink::URL_SIGN_UP] = href; + } else if (rel == OPDSConstants::REL_LINK_TOPUP) { + links[NetworkLink::URL_TOPUP] = href; + } else if (rel == OPDSConstants::REL_LINK_RECOVER_PASSWORD) { + links[NetworkLink::URL_RECOVER_PASSWORD] = href; + } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + if (ZLMimeType::isImage(type)) { + iconURL = href; + } + } else if (iconURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) { + if (ZLMimeType::isImage(type)) { + iconURL = href; + } + } else { + links[rel] = href; + } + } + if (entry->title().empty() || links[NetworkLink::URL_MAIN].empty()) { + return; + } + if (entry->id() == 0) { + return; + } + std::string id = entry->id()->uri(); + std::string summary = entry->summary(); + std::string language = entry->dcLanguage(); + + shared_ptr<NetworkLink> link = new OPDSLink(id.substr(25)); //why just 25 symbols? + link->setTitle(entry->title()); + link->setSummary(summary); + link->setLanguage(language); + link->setIcon(iconURL); + link->setLinks(links); + link->setPredefinedId(id); + link->setUpdated(entry->updated()); + + OPDSLink &opdsLink = static_cast<OPDSLink&>(*link); + opdsLink.setUrlRewritingRules(myUrlRewritingRules); + if (!myAdvancedSearch.isNull()) { + opdsLink.setAdvancedSearch(myAdvancedSearch); + } + opdsLink.setRelationAliases(myRelationAliases); + if (myAuthenticationType == "litres") { + opdsLink.setAuthenticationManager(new LitResAuthenticationManager(*link)); + } + myLinks.push_back(link); +} + +void OPDSLink::GenericFeedReader::clear() { + myAuthenticationType.clear(); + myUrlRewritingRules.clear(); + myAdvancedSearch.reset(); + myRelationAliases.clear(); +} + +void OPDSLink::GenericFeedReader::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) { + myAdvancedSearch = advancedSearch; +} + +void OPDSLink::GenericFeedReader::setAuthenticationType(std::string type) { + myAuthenticationType = type; +} + +void OPDSLink::GenericFeedReader::addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule) { + myUrlRewritingRules.push_back(rewritingRule); +} + +void OPDSLink::GenericFeedReader::addRelationAlias(const OPDSLink::RelationAlias& alias, std::string name) { + myRelationAliases[alias] = name; +} diff --git a/reader/src/network/opds/OPDSLink_GenericFeedReader.h b/reader/src/network/opds/OPDSLink_GenericFeedReader.h new file mode 100644 index 0000000..15ffe38 --- /dev/null +++ b/reader/src/network/opds/OPDSLink_GenericFeedReader.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSLINK_GENERICFEEDREADER_H__ +#define __OPDSLINK_GENERICFEEDREADER_H__ + +#include <map> +#include <string> + +#include "URLRewritingRule.h" +#include "OPDSFeedReader.h" +#include "OPDSLink.h" +#include "OPDSLink_AdvancedSearch.h" + +class OPDSLink::GenericFeedReader : public OPDSFeedReader { + +public: + GenericFeedReader( + std::vector<shared_ptr<NetworkLink> >& links + ); + +public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + +public: + void clear(); + void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch); + void setAuthenticationType(std::string type); + void addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule); + void addRelationAlias(const OPDSLink::RelationAlias&, std::string name); + +private: + std::vector<shared_ptr<NetworkLink> >& myLinks; + +private: + std::string myAuthenticationType; + std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules; + shared_ptr<OPDSLink::AdvancedSearch> myAdvancedSearch; + std::map<OPDSLink::RelationAlias,std::string> myRelationAliases; +}; + +#endif /* __OPDSLINK_GENERICFEEDREADER_H__ */ diff --git a/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp b/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp new file mode 100644 index 0000000..af5d866 --- /dev/null +++ b/reader/src/network/opds/OPDSLink_GenericXMLParser.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLXMLNamespace.h> + +#include "OPDSLink_GenericXMLParser.h" +#include "URLRewritingRule.h" +#include "OPDSLink_AdvancedSearch.h" + +static const std::string TAG_ENTRY = "entry"; +static const std::string READER_ADVANCED_SEARCH = "advancedSearch"; +static const std::string READER_AUTHENTICATION = "authentication"; +static const std::string READER_REWRITING_RULE = "urlRewritingRule"; +static const std::string READER_RELATION_ALIAS = "relationAlias"; +static const std::string READER_EXTRA = "extra"; + +OPDSLink::GenericXMLParser::GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader) : + OPDSXMLParser(feedReader) { +} + +OPDSLink::GenericFeedReader &OPDSLink::GenericXMLParser::getFeedReader() const { + return static_cast<OPDSLink::GenericFeedReader&>(*myFeedReader); +} + +void OPDSLink::GenericXMLParser::startElementHandler(const char *tag, const char **attributes) { + switch (myState) { + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + getFeedReader().clear(); + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_ADVANCED_SEARCH, tag)) { + const char *style = attributeValue(attributes, "style"); + const char *author = attributeValue(attributes, "author"); + const char *titleOrSeries = attributeValue(attributes, "titleOrSeries"); + const char *tag = attributeValue(attributes, "tag"); + const char *annotation = attributeValue(attributes, "annotation"); + if (style != 0 && author != 0 && titleOrSeries != 0 && tag != 0 && annotation != 0) { + getFeedReader().setAdvancedSearch(new OPDSLink::AdvancedSearch(style, titleOrSeries, author, tag, annotation)); + } + return; + } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_AUTHENTICATION, tag)) { + const char *type = attributeValue(attributes, "type"); + if (type != 0) { + getFeedReader().setAuthenticationType(type); + } + return; + } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_RELATION_ALIAS, tag)) { + const char *name = attributeValue(attributes, "name"); + const char *type = attributeValue(attributes, "type"); + const char *alias = attributeValue(attributes, "alias"); + if (name != 0 && alias != 0) { + getFeedReader().addRelationAlias(OPDSLink::RelationAlias(alias, (type != 0) ? type : std::string()), name); + } + } else if (testTag(ZLXMLNamespace::ReaderCatalogMetadata, READER_REWRITING_RULE, tag)) { + + getFeedReader().addUrlRewritingRule(new URLRewritingRule(getAttributesMap(attributes))); + +// const char *type = attributeValue(attributes, "type"); +// const char *apply = attributeValue(attributes, "apply"); +// const char *name = attributeValue(attributes, "name"); +// const char *value = attributeValue(attributes, "value"); + +// //TODO add rewrite type of 'rewriting rules' +// URLRewritingRule::RuleApply ruleApply = URLRewritingRule::ALWAYS; +// if (apply != 0) { +// const std::string applyStr = apply; +// if (applyStr == "external") { +// ruleApply = URLRewritingRule::EXTERNAL; +// } else if (applyStr == "internal") { +// ruleApply = URLRewritingRule::INTERNAL; +// } else if (applyStr != "always") { +// type = 0; +// } +// } + +// if (type != 0 && name != 0 && value != 0) { +// std::string typeStr = type; +// if (typeStr == "addUrlParameter") { +// getFeedReader().addUrlRewritingRule(new URLRewritingRule(URLRewritingRule::ADD_URL_PARAMETER, ruleApply, name, value)); +// } +// } + + return; + } + break; + default: + break; + } + OPDSXMLParser::startElementHandler(tag, attributes); +} + diff --git a/reader/src/network/opds/OPDSLink_GenericXMLParser.h b/reader/src/network/opds/OPDSLink_GenericXMLParser.h new file mode 100644 index 0000000..9bdf9d6 --- /dev/null +++ b/reader/src/network/opds/OPDSLink_GenericXMLParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSLINK_GENERICXMLPARSER_H__ +#define __OPDSLINK_GENERICXMLPARSER_H__ + +#include "OPDSXMLParser.h" +#include "OPDSLink_GenericFeedReader.h" + +class OPDSLink::GenericXMLParser : public OPDSXMLParser { +public: + GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader); + +protected: + void startElementHandler(const char *tag, const char **attributes); + OPDSLink::GenericFeedReader &getFeedReader() const; +}; + +#endif /* __OPDSLINK_GENERICXMLPARSER_H__ */ diff --git a/reader/src/network/opds/OPDSMetadata.cpp b/reader/src/network/opds/OPDSMetadata.cpp new file mode 100644 index 0000000..6595e05 --- /dev/null +++ b/reader/src/network/opds/OPDSMetadata.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "OPDSMetadata.h" + +// Feed level +const std::string OPDSConstants::REL_BOOKSHELF = "http://data.fbreader.org/rel/bookshelf"; +const std::string OPDSConstants::REL_RECOMMENDATIONS = "http://data.fbreader.org/rel/recommendations"; + +//const std::string OPDSConstants::REL_SUBSCRIPTIONS = "http://opds-spec.org/subscriptions"; + +const std::string OPDSConstants::REL_CATALOG_AUTHOR = "http://data.fbreader.org/catalog/author"; +const std::string OPDSConstants::REL_ACQUISITION = "http://opds-spec.org/acquisition"; +const std::string OPDSConstants::REL_ACQUISITION_OPEN = "http://opds-spec.org/acquisition/open-access"; +const std::string OPDSConstants::REL_ACQUISITION_BUY = "http://opds-spec.org/acquisition/buy"; +//const std::string OPDSConstants::REL_ACQUISITION_BORROW = "http://opds-spec.org/acquisition/borrow"; +//const std::string OPDSConstants::REL_ACQUISITION_SUBSCRIBE = "http://opds-spec.org/acquisition/subscribe"; +const std::string OPDSConstants::REL_ACQUISITION_SAMPLE = "http://opds-spec.org/acquisition/sample"; +const std::string OPDSConstants::REL_ACQUISITION_CONDITIONAL = "http://data.fbreader.org/acquisition/conditional"; +const std::string OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL = "http://data.fbreader.org/acquisition/sampleOrFull"; + +// Entry level / other +const std::string OPDSConstants::REL_IMAGE_PREFIX = "http://opds-spec.org/image"; +//const std::string OPDSConstants::REL_IMAGE = "http://opds-spec.org/image"; +const std::string OPDSConstants::REL_IMAGE_THUMBNAIL = "http://opds-spec.org/image/thumbnail"; +// FIXME: This relations have been removed from OPDS-1.0 standard. Use RelationAlias instead??? +const std::string OPDSConstants::REL_COVER = "http://opds-spec.org/cover"; +const std::string OPDSConstants::REL_THUMBNAIL = "http://opds-spec.org/thumbnail"; + +// Entry level / OPDS Link Relations +const std::string OPDSConstants::REL_LINK_SIGN_IN = "http://data.fbreader.org/catalog/sign-in"; +const std::string OPDSConstants::REL_LINK_SIGN_OUT = "http://data.fbreader.org/catalog/sign-out"; +const std::string OPDSConstants::REL_LINK_SIGN_UP = "http://data.fbreader.org/catalog/sign-up"; +const std::string OPDSConstants::REL_LINK_TOPUP = "http://data.fbreader.org/catalog/refill-account"; +const std::string OPDSConstants::REL_LINK_RECOVER_PASSWORD = "http://data.fbreader.org/catalog/recover-password"; + +DCDate::DCDate() : + ATOMDateConstruct(0) { +} + +DCDate::DCDate(int year) : + ATOMDateConstruct(year) { +} + +DCDate::DCDate(int year, int month, int day) : + ATOMDateConstruct(year, month, day) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + +OPDSEntry::OPDSEntry() { +} + +OPDSEntry::OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMEntry(id, title, updated) { +} + +OPDSFeedMetadata::OPDSFeedMetadata() : myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) { +} + +OPDSFeedMetadata::OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMFeedMetadata(id, title, updated), myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) { +} diff --git a/reader/src/network/opds/OPDSMetadata.h b/reader/src/network/opds/OPDSMetadata.h new file mode 100644 index 0000000..51554dd --- /dev/null +++ b/reader/src/network/opds/OPDSMetadata.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSMETADATA_H__ +#define __OPDSMETADATA_H__ + +#include <map> + +#include "../atom/ATOMContainers.h" + + +class OPDSConstants { + +private: + OPDSConstants(); + +public: + + //TODO get other relations from FBReaderJ + + // Feed level + static const std::string REL_BOOKSHELF; + static const std::string REL_RECOMMENDATIONS; + + //static const std::string REL_SUBSCRIPTIONS; + + // Entry level / catalog types + static const std::string REL_CATALOG_AUTHOR; + + // Entry level / acquisition links + static const std::string REL_ACQUISITION; + static const std::string REL_ACQUISITION_OPEN; + static const std::string REL_ACQUISITION_BUY; +// static const std::string REL_ACQUISITION_BORROW; +// static const std::string REL_ACQUISITION_SUBSCRIBE; + static const std::string REL_ACQUISITION_SAMPLE; + static const std::string REL_ACQUISITION_CONDITIONAL; + static const std::string REL_ACQUISITION_SAMPLE_OR_FULL; + + // Entry level / other + static const std::string REL_IMAGE_PREFIX; + //static const std::string REL_IMAGE; + static const std::string REL_IMAGE_THUMBNAIL; + static const std::string REL_COVER; + static const std::string REL_THUMBNAIL; + + // Entry level / OPDS Link Relations + static const std::string REL_LINK_SIGN_IN; + static const std::string REL_LINK_SIGN_OUT; + static const std::string REL_LINK_SIGN_UP; + static const std::string REL_LINK_TOPUP; + static const std::string REL_LINK_RECOVER_PASSWORD; +}; + + +class DCDate : public ATOMDateConstruct { + +public: + DCDate(); + DCDate(int year); + DCDate(int year, int month, int day); + DCDate(int year, int month, int day, int hour, int minutes, int seconds); + DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + +class OPDSEntry : public ATOMEntry { + +public: + OPDSEntry(); + OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + const std::string &dcLanguage() const { return myDCLanguage; } + const std::string &dcPublisher() const { return myDCPublisher; } + shared_ptr<DCDate> dcIssued() { return myDCIssued; } + const std::string &seriesTitle() const { return mySeriesTitle; } + int seriesIndex() const { return mySeriesIndex; } + + void setDCLanguage(const std::string &language) { myDCLanguage = language; } + void setDCPublisher(const std::string &publisher) { myDCPublisher = publisher; } + void setDCIssued(shared_ptr<DCDate> issued) { myDCIssued = issued; } + void setSeriesTitle(const std::string &seriesTitle) { mySeriesTitle = seriesTitle; } + void setSeriesIndex(int seriesIndex) { mySeriesIndex = seriesIndex; } + +private: + std::string myDCLanguage; + std::string myDCPublisher; + shared_ptr<DCDate> myDCIssued; + + std::string mySeriesTitle; + int mySeriesIndex; +}; + + + +class OPDSFeedMetadata : public ATOMFeedMetadata { + +public: + OPDSFeedMetadata(); + OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + unsigned long getOpensearchTotalResults() const; + unsigned long getOpensearchItemsPerPage() const; + unsigned long getOpensearchStartIndex() const; + + void setOpensearchTotalResults(unsigned long number); + void setOpensearchItemsPerPage(unsigned long number); + void setOpensearchStartIndex(unsigned long number); + +private: + unsigned long myOpensearchTotalResults; + unsigned long myOpensearchItemsPerPage; + unsigned long myOpensearchStartIndex; +}; + +inline unsigned long OPDSFeedMetadata::getOpensearchTotalResults() const { return myOpensearchTotalResults; } +inline unsigned long OPDSFeedMetadata::getOpensearchItemsPerPage() const { return myOpensearchItemsPerPage; } +inline unsigned long OPDSFeedMetadata::getOpensearchStartIndex() const { return myOpensearchStartIndex; } +inline void OPDSFeedMetadata::setOpensearchTotalResults(unsigned long number) { myOpensearchTotalResults = number; } +inline void OPDSFeedMetadata::setOpensearchItemsPerPage(unsigned long number) { myOpensearchItemsPerPage = number; } +inline void OPDSFeedMetadata::setOpensearchStartIndex(unsigned long number) { myOpensearchStartIndex = number; } + +#endif /* __OPDSMETADATA_H__ */ diff --git a/reader/src/network/opds/OPDSXMLParser.cpp b/reader/src/network/opds/OPDSXMLParser.cpp new file mode 100644 index 0000000..2b9fb4c --- /dev/null +++ b/reader/src/network/opds/OPDSXMLParser.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cstdlib> + +#include <ZLUnicodeUtil.h> +#include <ZLXMLNamespace.h> + +#include "OPDSXMLParser.h" + +static const std::string TAG_FEED = "feed"; +static const std::string TAG_ENTRY = "entry"; +static const std::string TAG_AUTHOR = "author"; +static const std::string TAG_NAME = "name"; +static const std::string TAG_URI = "uri"; +static const std::string TAG_EMAIL = "email"; +static const std::string TAG_ID = "id"; +static const std::string TAG_CATEGORY = "category"; +static const std::string TAG_LINK = "link"; +static const std::string TAG_PUBLISHED = "published"; +static const std::string TAG_SUMMARY = "summary"; +static const std::string TAG_CONTENT = "content"; +static const std::string TAG_SUBTITLE = "subtitle"; +static const std::string TAG_TITLE = "title"; +static const std::string TAG_UPDATED = "updated"; +static const std::string TAG_PRICE = "price"; +static const std::string TAG_ICON = "icon"; + +static const std::string TAG_HACK_SPAN = "span"; + +static const std::string DC_TAG_LANGUAGE = "language"; +static const std::string DC_TAG_ISSUED = "issued"; +static const std::string DC_TAG_PUBLISHER = "publisher"; +static const std::string DC_TAG_FORMAT = "format"; + +static const std::string CALIBRE_TAG_SERIES = "series"; +static const std::string CALIBRE_TAG_SERIES_INDEX = "series_index"; + +static const std::string OPENSEARCH_TAG_TOTALRESULTS = "totalResults"; +static const std::string OPENSEARCH_TAG_ITEMSPERPAGE = "itemsPerPage"; +static const std::string OPENSEARCH_TAG_STARTINDEX = "startIndex"; + +const std::string OPDSXMLParser::KEY_PRICE = "price"; +const std::string OPDSXMLParser::KEY_CURRENCY = "currency"; +const std::string OPDSXMLParser::KEY_FORMAT = "format"; + +static const std::string TAG_SEARCH_DESCRIPTION = "reader:advancedSearch"; +static const std::string TAG_AUTHENTICATION = "reader:authentication"; +static const std::string TAG_URL_REWRITING_RULES = "reader:urlRewritingRule"; +static const std::string TAG_RELATION_ALIASES = "reader:relationAlias"; + +OPDSXMLParser::OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed) : myFeedReader(feedReader) { + myState = readEntryNotFeed ? FEED : START; +} + +bool OPDSXMLParser::processNamespaces() const { + return true; +} + +void OPDSXMLParser::startElementHandler(const char *tag, const char **attributes) { + std::map<std::string,std::string> attributeMap = getAttributesMap(attributes); + switch (myState) { + case START: + if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) { + myFeedReader->processFeedStart(); + myFeed = new OPDSFeedMetadata(); + myFeed->readAttributes(attributeMap); + myState = FEED; + } + break; + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myAuthor = new ATOMAuthor(); + myAuthor->readAttributes(attributeMap); + myState = F_AUTHOR; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + myId = new ATOMId(); + myId->readAttributes(attributeMap); + myState = F_ID; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon = new ATOMIcon(); + myIcon->readAttributes(attributeMap); + myState = F_ICON; + } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myLink = new ATOMLink(); + myLink->readAttributes(attributeMap); + myState = F_LINK; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myCategory = new ATOMCategory(); + myCategory->readAttributes(attributeMap); + myState = F_CATEGORY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle + //myTitle->readAttributes(attributeMap); + myState = F_TITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + myState = F_SUBTITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + myState = F_SUMMARY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + myUpdated = new ATOMUpdated(); + myUpdated->readAttributes(attributeMap); + myState = F_UPDATED; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + myEntry = new OPDSEntry(); + myEntry->readAttributes(attributeMap); + mySummaryTagFound = false; + myState = F_ENTRY; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) { + myState = OPENSEARCH_TOTALRESULTS; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) { + myState = OPENSEARCH_ITEMSPERPAGE; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) { + myState = OPENSEARCH_STARTINDEX; + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myAuthor = new ATOMAuthor(); + myAuthor->readAttributes(attributeMap); + myState = FE_AUTHOR; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + myId = new ATOMId(); + myId->readAttributes(attributeMap); + myState = FE_ID; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myCategory = new ATOMCategory(); + myCategory->readAttributes(attributeMap); + myState = FE_CATEGORY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon = new ATOMIcon(); + myIcon->readAttributes(attributeMap); + myState = FE_ICON; + } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myLink = new ATOMLink(); + myLink->readAttributes(attributeMap); + myState = FE_LINK; + } else if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) { + myPublished = new ATOMPublished(); + myPublished->readAttributes(attributeMap); + myState = FE_PUBLISHED; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + //mySummary = new ATOMSummary(); // TODO:implement ATOMTextConstruct & ATOMSummary + //mySummary->readAttributes(attributeMap); + myState = FE_SUMMARY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) { + // ??? + myState = FE_CONTENT; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + // ??? + myState = FE_SUBTITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle + //myTitle->readAttributes(attributeMap); + myState = FE_TITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + myUpdated = new ATOMUpdated(); + myUpdated->readAttributes(attributeMap); + myState = FE_UPDATED; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) { + myState = FE_DC_LANGUAGE; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) { + myState = FE_DC_ISSUED; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) { + myState = FE_DC_PUBLISHER; + } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) { + myState = FE_CALIBRE_SERIES; + } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) { + myState = FE_CALIBRE_SERIES_INDEX; + } + break; + case F_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myState = FA_NAME; + } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myState = FA_URI; + } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myState = FA_EMAIL; + } + break; + case FE_TITLE: + // TODO: remove this temporary code + // DON'T clear myBuffer + return; + case FE_LINK: + if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) { + myLink->setUserData(KEY_CURRENCY, attributeMap["currencycode"]); + myState = FEL_PRICE; + } if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) { + myState = FEL_FORMAT; + } + break; + case FE_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myState = FEA_NAME; + } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myState = FEA_URI; + } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myState = FEA_EMAIL; + } + break; + case FE_CONTENT: + if (TAG_HACK_SPAN == tag || attributeMap["class"] == "price") { + myState = FEC_HACK_SPAN; + } + break; + default: + break; + } + + myBuffer.clear(); +} + +void OPDSXMLParser::endElementHandler(const char *tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + + switch (myState) { + case START: + break; + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) { + myFeedReader->processFeedMetadata(myFeed); + myFeed.reset(); + myFeedReader->processFeedEnd(); + myState = START; + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + myFeedReader->processFeedEntry(myEntry); + myEntry.reset(); + myState = FEED; + } + break; + case F_ID: + if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + myId->setUri(myBuffer); + if (!myFeed.isNull()) { + myFeed->setId(myId); + } + myId.reset(); + myState = FEED; + } + break; + case F_ICON: + if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon->setUri(myBuffer); + if (!myFeed.isNull()) { + myFeed->setIcon(myIcon); + } + myIcon.reset(); + myState = FEED; + } + break; + case F_LINK: + if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + if (!myFeed.isNull()) { + myFeed->links().push_back(myLink); + } + myLink.reset(); + myState = FEED; + } + break; + case F_CATEGORY: + if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + if (!myFeed.isNull()) { + myFeed->categories().push_back(myCategory); + } + myCategory.reset(); + myState = FEED; + } + break; + case F_TITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag + // TODO:implement ATOMTextConstruct & ATOMTitle + if (!myFeed.isNull()) { + myFeed->setTitle(myBuffer); + } + myState = FEED; + } + break; + case F_SUBTITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + if (!myFeed.isNull()) { + myFeed->setSubtitle(myBuffer); + } + myState = FEED; + } + break; + case F_SUMMARY: + if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + if (!myFeed.isNull()) { + myFeed->setSummary(myBuffer); + } + myState = FEED; + } + break; + case F_UPDATED: + if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myUpdated); + if (!myFeed.isNull()) { + myFeed->setUpdated(myUpdated); + } + myUpdated.reset(); + myState = FEED; + } + break; + case F_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + if (!myFeed.isNull()) { + myFeed->authors().push_back(myAuthor); + } + myAuthor.reset(); + myState = FEED; + } + break; + case FA_NAME: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myAuthor->setName(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_NAME: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myAuthor->setName(myBuffer); + myState = FE_AUTHOR; + } + break; + case FEL_PRICE: + if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) { + myLink->setUserData(KEY_PRICE, myBuffer); + myState = FE_LINK; + } + break; + case FEL_FORMAT: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) { + myLink->setUserData(KEY_FORMAT, myBuffer); + myState = FE_LINK; + } + break; + case FA_URI: + if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myAuthor->setUri(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_URI: + if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myAuthor->setUri(myBuffer); + myState = FE_AUTHOR; + } + break; + case FA_EMAIL: + if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myAuthor->setEmail(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_EMAIL: + if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myAuthor->setEmail(myBuffer); + myState = FE_AUTHOR; + } + break; + case FE_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myEntry->authors().push_back(myAuthor); + myAuthor.reset(); + myState = F_ENTRY; + } + break; + case FE_ICON: + if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon->setUri(myBuffer); + if (!myEntry.isNull()) { + myEntry->setIcon(myIcon); + } + myIcon.reset(); + myState = F_ENTRY; + } + break; + case FE_ID: + if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + myId->setUri(myBuffer); + myEntry->setId(myId); + myId.reset(); + myState = F_ENTRY; + } + break; + case FE_CATEGORY: + if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myEntry->categories().push_back(myCategory); + myCategory.reset(); + myState = F_ENTRY; + } + break; + case FE_LINK: + if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myEntry->links().push_back(myLink); + myLink.reset(); + myState = F_ENTRY; + } + break; + case FE_PUBLISHED: + if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myPublished); + myEntry->setPublished(myPublished); + myPublished.reset(); + myState = F_ENTRY; + } + break; + case FE_SUMMARY: + if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + // FIXME:summary can be lost:buffer will be truncated, if there are extension tags inside the <summary> tag + // TODO:implement ATOMTextConstruct & ATOMSummary + myEntry->setSummary(myBuffer); + mySummaryTagFound = true; + myState = F_ENTRY; + } + break; + case FE_CONTENT: + if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) { + // TODO:check this accurately + if (!mySummaryTagFound) { + myEntry->setSummary(myBuffer); + } + myState = F_ENTRY; + } + break; + case FEC_HACK_SPAN: + myEntry->setUserData(KEY_PRICE, myBuffer); + myState = FE_CONTENT; + break; + case FE_SUBTITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + // TODO:check this accurately + if (!mySummaryTagFound) { + myEntry->setSummary(myBuffer); + } + myState = F_ENTRY; + } + break; + case FE_TITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag + // TODO:implement ATOMTextConstruct & ATOMTitle + myEntry->setTitle(myBuffer); + myState = F_ENTRY; + } else { + // TODO: remove this temporary code + // DON'T clear myBuffer + return; + } + break; + case FE_UPDATED: + if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myUpdated); + myEntry->setUpdated(myUpdated); + myUpdated.reset(); + myState = F_ENTRY; + } + break; + case FE_DC_LANGUAGE: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) { + // FIXME:language can be lost:buffer will be truncated, if there are extension tags inside the <dc:language> tag + myEntry->setDCLanguage(myBuffer); + myState = F_ENTRY; + } + break; + case FE_DC_ISSUED: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) { + // FIXME:issued can be lost:buffer will be truncated, if there are extension tags inside the <dc:issued> tag + DCDate *issued = new DCDate(); + ATOMDateConstruct::parse(myBuffer, *issued); + myEntry->setDCIssued(issued); + myState = F_ENTRY; + } + break; + case FE_DC_PUBLISHER: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) { + // FIXME:publisher can be lost:buffer will be truncated, if there are extension tags inside the <dc:publisher> tag + myEntry->setDCPublisher(myBuffer); + myState = F_ENTRY; + } + break; + case FE_CALIBRE_SERIES: + if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) { + myEntry->setSeriesTitle(myBuffer); + myState = F_ENTRY; + } + break; + case FE_CALIBRE_SERIES_INDEX: + if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) { + myEntry->setSeriesIndex(std::atoi(myBuffer.c_str())); + myState = F_ENTRY; + } + break; + case OPENSEARCH_TOTALRESULTS: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchTotalResults(number); + } + myState = FEED; + } + break; + case OPENSEARCH_ITEMSPERPAGE: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchItemsPerPage(number); + } + myState = FEED; + } + break; + case OPENSEARCH_STARTINDEX: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchStartIndex(number); + } + myState = FEED; + } + break; + } + + myBuffer.clear(); +} + +void OPDSXMLParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} diff --git a/reader/src/network/opds/OPDSXMLParser.h b/reader/src/network/opds/OPDSXMLParser.h new file mode 100644 index 0000000..82f0124 --- /dev/null +++ b/reader/src/network/opds/OPDSXMLParser.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPDSXMLPARSER_H__ +#define __OPDSXMLPARSER_H__ + +#include <ZLXMLReader.h> + +#include "OPDSMetadata.h" +#include "OPDSFeedReader.h" + + +class OPDSXMLParser : public ZLXMLReader { + +public: + static const std::string KEY_PRICE; + static const std::string KEY_CURRENCY; + static const std::string KEY_FORMAT; + +public: + OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed = false); + +protected: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + bool processNamespaces() const; + +protected: + enum State { + START, + FEED, F_ENTRY, F_ID, F_LINK, F_CATEGORY, F_TITLE, F_UPDATED, F_AUTHOR, F_SUBTITLE, F_ICON, F_SUMMARY, + FA_NAME, FA_URI, FA_EMAIL, + FE_AUTHOR, FE_ID, FE_CATEGORY, FE_LINK, FE_PUBLISHED, FE_SUMMARY, FE_CONTENT, FE_SUBTITLE, FE_TITLE, FE_ICON, FE_UPDATED, FE_DC_LANGUAGE, FE_DC_ISSUED, FE_DC_PUBLISHER, FE_CALIBRE_SERIES, FE_CALIBRE_SERIES_INDEX, + FEL_PRICE, FEL_FORMAT, + FEA_NAME, FEA_URI, FEA_EMAIL, + OPENSEARCH_TOTALRESULTS, OPENSEARCH_ITEMSPERPAGE, OPENSEARCH_STARTINDEX, + FEC_HACK_SPAN, + }; + +protected: + shared_ptr<OPDSFeedReader> myFeedReader; + State myState; + +private: + std::string myBuffer; + shared_ptr<OPDSFeedMetadata> myFeed; + shared_ptr<OPDSEntry> myEntry; + + shared_ptr<ATOMAuthor> myAuthor; + shared_ptr<ATOMId> myId; + shared_ptr<ATOMIcon> myIcon; + shared_ptr<ATOMLink> myLink; + shared_ptr<ATOMCategory> myCategory; + shared_ptr<ATOMUpdated> myUpdated; + shared_ptr<ATOMPublished> myPublished; + + //shared_ptr<ATOMTitle> myTitle; // TODO: implement ATOMTextConstruct & ATOMTitle + //shared_ptr<ATOMSummary> mySummary; // TODO: implement ATOMTextConstruct & ATOMSummary + bool mySummaryTagFound; +}; + +#endif /* __OPDSXMLPARSER_H__ */ diff --git a/reader/src/network/opds/OpenSearchXMLReader.cpp b/reader/src/network/opds/OpenSearchXMLReader.cpp new file mode 100644 index 0000000..686d8c1 --- /dev/null +++ b/reader/src/network/opds/OpenSearchXMLReader.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "OpenSearchXMLReader.h" +#include <ZLMimeType.h> + +static const std::string TAG_URL = "Url"; + +std::string OpenSearchXMLReader::convertOpenSearchURL(const std::string& raws) { //TODO + std::size_t pos = raws.find('{'); + return raws.substr(0, pos) + "%s"; +} + +void OpenSearchXMLReader::startElementHandler(const char *tag, const char **attributes) { + if (TAG_URL == tag) { + const char *type = attributeValue(attributes, "type"); + if (ZLMimeType::get(type)->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + const char *templ = attributeValue(attributes, "template"); + if (templ != 0) { + myTemplateURL = convertOpenSearchURL(templ); + } + } + } +} + +void OpenSearchXMLReader::endElementHandler(const char *tag) { + (void)tag; +} + +void OpenSearchXMLReader::characterDataHandler(const char *text, std::size_t len) { + (void)text; + (void)len; +} diff --git a/reader/src/network/opds/OpenSearchXMLReader.h b/reader/src/network/opds/OpenSearchXMLReader.h new file mode 100644 index 0000000..2b53f19 --- /dev/null +++ b/reader/src/network/opds/OpenSearchXMLReader.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPENSEARCHXMLREADER_H__ +#define __OPENSEARCHXMLREADER_H__ + +#include <string> +#include <ZLXMLReader.h> + +class OpenSearchXMLReader : public ZLXMLReader { + +public: + OpenSearchXMLReader() {} + std::string templateURL() {return myTemplateURL;} + + static std::string convertOpenSearchURL(const std::string& raws); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + std::string myTemplateURL; + +}; + +#endif /* __OPENSEARCHXMLREADER_H__ */ diff --git a/reader/src/network/opds/URLRewritingRule.cpp b/reader/src/network/opds/URLRewritingRule.cpp new file mode 100644 index 0000000..8cea851 --- /dev/null +++ b/reader/src/network/opds/URLRewritingRule.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkUtil.h> + +#include "URLRewritingRule.h" + +URLRewritingRule::URLRewritingRule(const std::map<std::string,std::string> &map) : myType(UNKNOWN), myApply(ALWAYS) { + for (std::map<std::string, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) { + std::string key = (*it).first; + std::string value = (*it).second; + + if (key == "type") { + if (value == "addUrlParameter") { + myType = ADD_URL_PARAMETER; + } else if (value == "rewrite") { + myType = REWRITE; + } + } else if (key == "apply") { + if (value == "internal") { + myApply = INTERNAL; + } else if (value == "external") { + myApply = EXTERNAL; + } + } else { + myParameters.insert(std::make_pair(key, value)); + } + + } +} + +std::string URLRewritingRule::apply(const std::string &url) const { + std::string appliedUrl = url; + switch (myType) { + case ADD_URL_PARAMETER: + { + std::string name, value; + std::map<std::string, std::string>::const_iterator it; + it = myParameters.find("name"); + if (it != myParameters.end()) { + name = (*it).second; + } + it = myParameters.find("value"); + if (it != myParameters.end()) { + value = (*it).second; + } + if (name.empty() || value.empty()) { + break; + } + ZLNetworkUtil::appendParameter(appliedUrl, name, value); + } + case REWRITE: //TODO implement (regular expressions should be used here) + default: + break; + } + return appliedUrl; +} + +URLRewritingRule::RuleApply URLRewritingRule::whereToApply() const { + return myApply; +} diff --git a/reader/src/network/opds/URLRewritingRule.h b/reader/src/network/opds/URLRewritingRule.h new file mode 100644 index 0000000..1251139 --- /dev/null +++ b/reader/src/network/opds/URLRewritingRule.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __URLREWRITINGRULE_H__ +#define __URLREWRITINGRULE_H__ + +#include <string> +#include <map> + +class URLRewritingRule { + +public: + enum RuleType { + ADD_URL_PARAMETER, + REWRITE, + UNKNOWN, + }; + + enum RuleApply { + ALWAYS, EXTERNAL, INTERNAL + }; + + URLRewritingRule(const std::map<std::string,std::string> &attributesMap); + std::string apply(const std::string &url) const; + RuleApply whereToApply() const; + +private: + RuleType myType; + RuleApply myApply; + std::map<std::string, std::string> myParameters; +}; + + +#endif /* __URLREWRITINGRULE_H__ */ diff --git a/reader/src/network/tree/NetworkAuthorTree.cpp b/reader/src/network/tree/NetworkAuthorTree.cpp new file mode 100644 index 0000000..8106838 --- /dev/null +++ b/reader/src/network/tree/NetworkAuthorTree.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLImage.h> + +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkAuthorTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkAuthorTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkAuthorTree::resource() const { + return ZLResource::resource("networkView")["authorNode"]; +} + +NetworkAuthorTree::NetworkAuthorTree(NetworkTree *parent, const NetworkBookItem::AuthorData &author) : NetworkTree(parent), myAuthor(author) { + init(); +} + +void NetworkAuthorTree::init() { + //registerExpandTreeAction(); +} + +std::string NetworkAuthorTree::title() const { + return myAuthor.DisplayName; +} + +shared_ptr<const ZLImage> NetworkAuthorTree::image() const { + return defaultCoverImage("booktree-author.png"); +} + +const NetworkBookItem::AuthorData &NetworkAuthorTree::author() { + return myAuthor; +} diff --git a/reader/src/network/tree/NetworkBookTree.cpp b/reader/src/network/tree/NetworkBookTree.cpp new file mode 100644 index 0000000..c59d247 --- /dev/null +++ b/reader/src/network/tree/NetworkBookTree.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLImage.h> +#include <ZLExecutionUtil.h> +#include <ZLNetworkManager.h> + +#include "NetworkTreeNodes.h" +#include "NetworkTreeFactory.h" +#include "NetworkLibrary.h" +#include "NetworkCatalogUtil.h" + +#include "../../networkActions/NetworkActions.h" + +const ZLTypeId NetworkBookTree::TYPE_ID(ZLTreePageNode::TYPE_ID); + +const ZLTypeId &NetworkBookTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkBookTree::resource() const { + return ZLResource::resource("networkView")["bookNode"]; +} + +NetworkBookTree::NetworkBookTree(NetworkTree *parent, shared_ptr<NetworkItem> book, SummaryType summaryType) : ZLTreePageNode(parent), myBook(book), mySummaryType(summaryType) { + init(); +} + +//TODO we don't need a actions wrappers since we don't use old network library +class NetworkTreeBookReadAction : public NetworkBookReadAction { +public: + NetworkTreeBookReadAction(const NetworkBookTree &tree, const NetworkBookItem &book, bool demo) : NetworkBookReadAction(book, demo), myTree(tree) {} + void run() { + NetworkBookReadAction::run(); + myTree.close(); + } + +private: + const NetworkBookTree &myTree; +}; + +static std::vector<shared_ptr<ZLTreeAction> > getBookActions(NetworkBookTree &tree) { + std::vector<shared_ptr<ZLTreeAction> > actions; + const NetworkBookItem &book = tree.book(); + if (!book.reference(BookReference::DOWNLOAD_FULL).isNull() || + !book.reference(BookReference::DOWNLOAD_FULL_CONDITIONAL).isNull()) { + actions.push_back(new NetworkTreeBookReadAction(tree, book, false)); + actions.push_back(new NetworkBookDownloadAction(tree, book, false)); + actions.push_back(new NetworkBookDeleteAction(book)); + } + if (!book.reference(BookReference::DOWNLOAD_DEMO).isNull()) { + actions.push_back(new NetworkTreeBookReadAction(tree, book, true)); + actions.push_back(new NetworkBookDownloadAction(tree, book, true, tree.resource()["demo"].value())); + } + if (!book.reference(BookReference::BUY).isNull()) { + actions.push_back(new NetworkBookBuyDirectlyAction(tree, book)); + } else if (!book.reference(BookReference::BUY_IN_BROWSER).isNull()) { + actions.push_back(new NetworkBookBuyInBrowserAction(book)); + } + return actions; +} + +void NetworkBookTree::init() { + std::vector<shared_ptr<ZLTreeAction> > actions = getBookActions(*this); + for (std::size_t i = 0; i < actions.size(); ++i) { + registerAction(actions.at(i)); + } +} + +std::string NetworkBookTree::title() const { + return myBook->Title; +} + +std::string NetworkBookTree::subtitle() const { + int count = 0; + std::string authorsString; + const std::vector<NetworkBookItem::AuthorData> authors = book().Authors; + for (std::vector<NetworkBookItem::AuthorData>::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (!authorsString.empty()) { + authorsString += ", "; + } + authorsString += it->DisplayName; + ++count; + } + if (mySummaryType == NONE && count == 1) { + return std::string(); + } + return authorsString; +} + +shared_ptr<ZLTreePageInfo> NetworkBookTree::getPageInfo() /*const*/ { + if (myPageInfo.isNull()) { + myPageInfo = new BookItemWrapper(*this, myBook); + } + return myPageInfo; +} + + +shared_ptr<const ZLImage> NetworkBookTree::image() const { + if (myImage.isNull()) { + myImage = NetworkCatalogUtil::getAndDownloadImageByUrl(myBook->URLByType[NetworkItem::URL_COVER], this); + } + return (!myImage.isNull() && myImage->good()) ? myImage : FBTree::defaultCoverImage("booktree-book.png"); +} + +shared_ptr<const ZLImage> NetworkBookTree::fullImage() const { + if (myBook->URLByType.find(NetworkItem::URL_FULL_COVER) == myBook->URLByType.end()) { + return 0; + } + shared_ptr<const ZLImage> fullImage = NetworkCatalogUtil::getImageByUrl(myBook->URLByType[NetworkItem::URL_FULL_COVER]); + return !fullImage.isNull() ? fullImage : 0; +} + +const NetworkBookItem &NetworkBookTree::book() const { + return (const NetworkBookItem&)*myBook; +} + + +NetworkBookTree::BookItemWrapper::BookItemWrapper(NetworkBookTree &tree, shared_ptr<NetworkItem> bookItem) : + myTree(tree), myBookItem(bookItem), myIsInitialized(false) { +} + +bool NetworkBookTree::BookItemWrapper::isPageInfoLoaded() { + return myIsInitialized; +} + +class BookItemWrapperScope : public ZLUserData { +public: + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +void NetworkBookTree::BookItemWrapper::loadAll(shared_ptr<ZLNetworkRequest::Listener> listener) { + if (myIsInitialized) { + listener->finished(); + return; + } + + NetworkBookItem &bookItem = book(); + + BookItemWrapperScope *scope = new BookItemWrapperScope; + scope->listener = listener; + shared_ptr<ZLUserDataHolder> scopeData = new ZLUserDataHolder; + scopeData->addUserData("scope", scope); + + if (bookItem.isFullyLoaded()) { + onInformationLoaded(*scopeData, std::string()); + return; + } + bookItem.loadFullInformation(ZLExecutionUtil::createListener(scopeData, this, &NetworkBookTree::BookItemWrapper::onInformationLoaded)); +} + +void NetworkBookTree::BookItemWrapper::onInformationLoaded(ZLUserDataHolder &data, const std::string &error){ + shared_ptr<const ZLImage> cover = image(); + if (!cover.isNull()) { + shared_ptr<ZLNetworkRequest> request = cover->synchronizationData(); + if (!request.isNull()) { + request->setListener(ZLExecutionUtil::createListener(new ZLUserDataHolder(data), this, &NetworkBookTree::BookItemWrapper::onCoverLoaded)); + ZLNetworkManager::Instance().performAsync(request); + return; + } + } + onCoverLoaded(data, error); //if image is loaded already +} + +void NetworkBookTree::BookItemWrapper::onCoverLoaded(ZLUserDataHolder &data, const std::string &error) { + BookItemWrapperScope &scope = static_cast<BookItemWrapperScope&>(*data.getUserData("scope")); + if (error.empty()) { + myIsInitialized = true; + } + scope.listener->finished(error); +} + +std::string NetworkBookTree::BookItemWrapper::title() const { + return book().Title; +} + +std::vector<std::string> NetworkBookTree::BookItemWrapper::authors() const { + const NetworkBookItem &bookItem = book(); + std::vector<std::string> authors; + for (std::size_t i = 0; i < bookItem.Authors.size(); ++i) { + authors.push_back(bookItem.Authors.at(i).DisplayName); + } + return authors; +} + +std::vector<std::string> NetworkBookTree::BookItemWrapper::tags() const { + return book().Tags; +} + +std::string NetworkBookTree::BookItemWrapper::summary() const { + return book().Summary; +} + +shared_ptr<const ZLImage> NetworkBookTree::BookItemWrapper::image() const { + shared_ptr<const ZLImage> fullImage = myTree.fullImage(); + if (!fullImage.isNull()) { + return fullImage; + } + return myTree.image(); +} + +const std::vector<shared_ptr<ZLTreeAction> > &NetworkBookTree::BookItemWrapper::actions() const { + return myTree.actions(); +} + +std::string NetworkBookTree::BookItemWrapper::actionText(const shared_ptr<ZLTreeAction> &action) const { + return myTree.actionText(action); +} + +class RelatedAction : public ZLTreeAction { +public: + RelatedAction(shared_ptr<NetworkItem> item) : myTitle(item->Title) { + myNode = new NetworkCatalogTree(&NetworkLibrary::Instance().getFakeCatalogTree(), item); + //myNode = NetworkTreeFactory::createNetworkTree(0, item); + } + ZLResourceKey key() const { return ZLResourceKey(""); } + std::string text(const ZLResource &/*resource*/) const { + return myTitle; + } + void run() { + if (NetworkCatalogTree *tree = zlobject_cast<NetworkCatalogTree*>(&*myNode)){ + tree->expand(); + } + } + +private: + shared_ptr<ZLTreeTitledNode> myNode; + std::string myTitle; +}; + +const std::vector<shared_ptr<ZLTreeAction> > NetworkBookTree::BookItemWrapper::relatedActions() const { + if (!myRelatedActions.empty()) { + return myRelatedActions; + } + std::vector<shared_ptr<NetworkItem> > catalogItems = static_cast<NetworkBookItem&>(*myBookItem).getRelatedCatalogsItems(); + for (std::size_t i = 0; i < catalogItems.size(); ++i) { + shared_ptr<NetworkItem> item = catalogItems.at(i); + myRelatedActions.push_back(new RelatedAction(item)); + } + return myRelatedActions; +} + +NetworkBookItem &NetworkBookTree::BookItemWrapper::book() const { + return (NetworkBookItem&)*myBookItem; +} diff --git a/reader/src/network/tree/NetworkCatalogRootTree.cpp b/reader/src/network/tree/NetworkCatalogRootTree.cpp new file mode 100644 index 0000000..27ac665 --- /dev/null +++ b/reader/src/network/tree/NetworkCatalogRootTree.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLExecutionUtil.h> + +#include "../../reader/Reader.h" + +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../../networkActions/AuthenticationDialogManager.h" +#include "../../networkActions/PasswordRecoveryDialog.h" +#include "../../networkActions/RegisterUserDialog.h" + +#include "NetworkLibrary.h" + +#include "NetworkTreeNodes.h" + +class NetworkTreeCatalogAuthAction : public ZLTreeAction { + +protected: + NetworkTreeCatalogAuthAction(NetworkAuthenticationManager &mgr, bool forLoggedUsers); + +protected: + bool makesSense() const; + +protected: + NetworkAuthenticationManager &myManager; + +private: + const bool myForLoggedUsers; +}; + +class NetworkCatalogRootTree::LoginAction : public NetworkTreeCatalogAuthAction { + +public: + LoginAction(NetworkAuthenticationManager &mgr, ZLTreeNode *node); + void run(); + ZLResourceKey key() const; + +private: + void onAuthorised(const std::string &error); + +private: + ZLTreeNode *myNode; + +friend class LoginActionListener; +}; + +class NetworkCatalogRootTree::LogoutAction : public NetworkTreeCatalogAuthAction { + +public: + LogoutAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; + std::string text(const ZLResource &resource) const; +}; + +class NetworkCatalogRootTree::TopupAccountAction : public NetworkTreeCatalogAuthAction { + +public: + TopupAccountAction(NetworkAuthenticationManager &mgr); + +private: + void run(); + ZLResourceKey key() const; + std::string text(const ZLResource &resource) const; + bool makesSense() const; +}; + +class NetworkCatalogRootTree::PasswordRecoveryAction : public NetworkTreeCatalogAuthAction { + +public: + PasswordRecoveryAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; +}; + +class NetworkCatalogRootTree::RegisterUserAction : public NetworkTreeCatalogAuthAction { + +public: + RegisterUserAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; +}; + +const ZLTypeId NetworkCatalogRootTree::TYPE_ID(NetworkCatalogTree::TYPE_ID); + +const ZLTypeId &NetworkCatalogRootTree::typeId() const { + return TYPE_ID; +} + +NetworkCatalogRootTree::NetworkCatalogRootTree(RootTree *parent, NetworkLink &link, std::size_t position) : + NetworkCatalogTree(parent, link.libraryItem(), position), myLink(link) { + init(); //at old version, init is called when node should be painted (and if initialized yet) +} + +void NetworkCatalogRootTree::init() { + shared_ptr<NetworkAuthenticationManager> mgr = myLink.authenticationManager(); + //registerAction(new ExpandCatalogAction(*this)); + //registerAction(new ReloadAction(*this)); + if (!mgr.isNull()) { + registerAction(new LoginAction(*mgr, this)); + registerAction(new LogoutAction(*mgr)); + registerAction(new TopupAccountAction(*mgr)); + + if (mgr->registrationSupported()) { + registerAction(new RegisterUserAction(*mgr)); + } + if (mgr->passwordRecoverySupported()) { + registerAction(new PasswordRecoveryAction(*mgr)); + } + } +} + +const ZLResource &NetworkCatalogRootTree::resource() const { + return ZLResource::resource("networkView")["libraryItemRootNode"]; +} + +NetworkTreeCatalogAuthAction::NetworkTreeCatalogAuthAction(NetworkAuthenticationManager &mgr, bool forLoggedUsers) : myManager(mgr), myForLoggedUsers(forLoggedUsers) { +} + +bool NetworkTreeCatalogAuthAction::makesSense() const { + return (myManager.isAuthorised().Status == B3_FALSE) != myForLoggedUsers; +} + +NetworkCatalogRootTree::LoginAction::LoginAction(NetworkAuthenticationManager &mgr, ZLTreeNode *node) : + NetworkTreeCatalogAuthAction(mgr, false), myNode(node) { +} + +ZLResourceKey NetworkCatalogRootTree::LoginAction::key() const { + return ZLResourceKey("login"); +} + +class LoginActionListener : public ZLNetworkRequest::Listener { +public: + LoginActionListener(NetworkCatalogRootTree::LoginAction &action) : myAction(action) {} + + virtual void finished(const std::string &error) { + myAction.onAuthorised(error); + } + + virtual void setUIStatus(bool enabled) { + if (enabled) { + myAction.myNode->notifyDownloadStarted(); + } else { + myAction.myNode->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogRootTree::LoginAction &myAction; +}; + +void NetworkCatalogRootTree::LoginAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + AuthenticationDialogManager::authAndInitAsync( + myManager, + new LoginActionListener(*this) + ); +} + +void NetworkCatalogRootTree::LoginAction::onAuthorised(const std::string &/*error*/) { + myNode->notifyDownloadStopped(); + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + +NetworkCatalogRootTree::LogoutAction::LogoutAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, true) { +} + +ZLResourceKey NetworkCatalogRootTree::LogoutAction::key() const { + return ZLResourceKey("logout"); +} + +std::string NetworkCatalogRootTree::LogoutAction::text(const ZLResource &resource) const { + const std::string text = ZLTreeAction::text(resource); + return ZLStringUtil::printf(text, myManager.currentUserName()); +} + +void NetworkCatalogRootTree::LogoutAction::run() { + myManager.logOut(); + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + + +NetworkCatalogRootTree::TopupAccountAction::TopupAccountAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, true) { +} + +ZLResourceKey NetworkCatalogRootTree::TopupAccountAction::key() const { + return !myManager.currentAccount().empty() ? ZLResourceKey("topupAccount") : ZLResourceKey("topupAccountUndefined"); +} + +std::string NetworkCatalogRootTree::TopupAccountAction::text(const ZLResource &resource) const { + const std::string text = ZLTreeAction::text(resource); + std::string account = myManager.currentAccount(); + if (!account.empty() && !myManager.topupAccountLink().empty()) { + return ZLStringUtil::printf(text, account); + } + return text; +} + +void NetworkCatalogRootTree::TopupAccountAction::run() { + Reader::Instance().openLinkInBrowser(myManager.topupAccountLink()); + NetworkLibrary::Instance().refresh(); +} + +bool NetworkCatalogRootTree::TopupAccountAction::makesSense() const { + return NetworkTreeCatalogAuthAction::makesSense(); +} + +NetworkCatalogRootTree::PasswordRecoveryAction::PasswordRecoveryAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, false) { +} + +ZLResourceKey NetworkCatalogRootTree::PasswordRecoveryAction::key() const { + return ZLResourceKey("passwordRecovery"); +} + +void NetworkCatalogRootTree::PasswordRecoveryAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + PasswordRecoveryDialog::run(myManager); + Reader::Instance().refreshWindow(); + NetworkLibrary::Instance().refresh(); +} + +NetworkCatalogRootTree::RegisterUserAction::RegisterUserAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, false) { +} + +ZLResourceKey NetworkCatalogRootTree::RegisterUserAction::key() const { + return ZLResourceKey("register"); +} + +void NetworkCatalogRootTree::RegisterUserAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + RegisterUserDialog::run(myManager); + Reader::Instance().refreshWindow(); + NetworkLibrary::Instance().refresh(); +} diff --git a/reader/src/network/tree/NetworkCatalogTree.cpp b/reader/src/network/tree/NetworkCatalogTree.cpp new file mode 100644 index 0000000..6b6bf6e --- /dev/null +++ b/reader/src/network/tree/NetworkCatalogTree.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLDialogManager.h> + +#include "../authentication/NetworkAuthenticationManager.h" +#include "NetworkCatalogUtil.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../NetworkErrors.h" +#include "NetworkTreeFactory.h" +#include "../../networkActions/AuthenticationDialogManager.h" +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkCatalogTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkCatalogTree::typeId() const { + return TYPE_ID; +} + +NetworkCatalogTree::NetworkCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkTree(parent, position), myItem(item) { +} + +NetworkCatalogTree::NetworkCatalogTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkTree(parent, position), myItem(item) { + init(); +} + +void NetworkCatalogTree::init() { +// if (!item().URLByType[NetworkItem::URL_CATALOG].empty()) { +// registerAction(new ExpandCatalogAction(*this)); +// } +// const std::string htmlUrl = +// item().URLByType[NetworkItem::URL_HTML_PAGE]; +// if (!htmlUrl.empty()) { +// registerAction(new OpenInBrowserAction(htmlUrl)); +// } + //registerAction(new ReloadAction(*this)); +} + +std::string NetworkCatalogTree::title() const { + return myItem->Title; +} + +std::string NetworkCatalogTree::subtitle() const { + return ((const NetworkCatalogItem&)*myItem).Summary; +} + + +shared_ptr<const ZLImage> NetworkCatalogTree::image() const { + const std::string &url = myItem->URLByType[NetworkItem::URL_COVER]; + if (url.empty()) { + if (ZLTreeTitledNode* node = zlobject_cast<ZLTreeTitledNode*>(parent())) { + return node->image(); + } + } + if (myImage.isNull()) { + myImage = NetworkCatalogUtil::getAndDownloadImageByUrl(url, this); + } + return (!myImage.isNull() && myImage->good()) ? myImage : FBTree::defaultCoverImage("booktree-catalog.png"); +} + +class AsyncLoadSubCatalogRunnable : public ZLNetworkRequest::Listener { + +public: + AsyncLoadSubCatalogRunnable(NetworkCatalogTree *tree, bool resumeMode) : + myTree(tree), myResumeMode(resumeMode) { + myTree->notifyDownloadStarted(); + if (myResumeMode) { + myTree->item().resumeLoading(myChildrens, this); + } else { + myTree->item().loadChildren(myChildrens, this); + } + } + + void finished(const std::string &error) { + myTree->notifyDownloadStopped(); + myTree->onChildrenReceived(myChildrens, error); + } + + void setUIStatus(bool enabled) { + if (enabled) { + myTree->notifyDownloadStarted(); + } else { + myTree->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogTree *myTree; + NetworkItem::List myChildrens; + bool myResumeMode; +}; + +//class NetworkCatalogTreeAuthScope : public ZLUserData { +//public: +// shared_ptr<ZLNetworkRequest::Listener> listener; +//}; + +class NetworkCatalogTreeAuthListener : public ZLNetworkRequest::Listener { +public: + NetworkCatalogTreeAuthListener(NetworkCatalogTree *tree) : myTree(tree) { + } + + void finished(const std::string &error) { + myTree->onAuthCheck(error); + } + + void setUIStatus(bool enabled) { + if (enabled) { + myTree->notifyDownloadStarted(); + } else { + myTree->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogTree *myTree; +}; + +void NetworkCatalogTree::requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + myListeners.push_back(listener); + if (myListeners.size() > 1) { + return; + } + + const NetworkLink &link = item().Link; + shared_ptr<NetworkAuthenticationManager> manager = link.authenticationManager(); + + if (item().getVisibility() == B3_UNDEFINED && !manager.isNull()) { + AuthenticationDialogManager::authAndInitAsync(*manager, new NetworkCatalogTreeAuthListener(this)); + return; + } + + if (!manager.isNull() && manager->isAuthorised(0).Status == B3_TRUE) { + AuthenticationDialogManager::athoriseIfCan(*manager, new NetworkCatalogTreeAuthListener(this)); + return; + } + onAuthCheck(std::string()); +} + +void NetworkCatalogTree::onAuthCheck(const std::string &error) { + if (!error.empty()) { + notifyListeners(error); + return; + } + + if (!myChildrenItems.empty()) { + notifyDownloadStopped(); + notifyListeners(std::string()); //TODO maybe not be silent about auth error here + return; + } + new AsyncLoadSubCatalogRunnable(this, false); + +} + +void NetworkCatalogTree::requestMoreChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + //TODO does double requesting is processed correct? + if (!item().supportsResumeLoading()) { + listener->finished(); + return; + } + myListeners.push_back(listener); + if (myListeners.size() == 1) { + new AsyncLoadSubCatalogRunnable(this, true); + } +} + +void NetworkCatalogTree::onChildrenReceived(NetworkItem::List &childrens, const std::string &error) { + if (!error.empty()) { + //special case for authenticationFailed after 'cancel' button pressed in AuthDialog? + //TODO maybe it'll be work wrong at some cases? maybe we should have another error this case? + if (error != NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + NetworkErrors::showErrorMessage(error); + } + notifyListeners(error); + return; + } + + myChildrenItems.insert(myChildrenItems.end(), childrens.begin(), childrens.end()); + + if (myChildrenItems.empty()) { + ZLDialogManager::Instance().informationBox(ZLResourceKey("emptyCatalogBox")); + notifyListeners(error); + return; + } + + bool hasSubcatalogs = false; + for (NetworkItem::List::iterator it = myChildrenItems.begin(); it != myChildrenItems.end(); ++it) { + if ((*it)->typeId() == NetworkCatalogItem::TYPE_ID) { + hasSubcatalogs = true; + break; + } + } + + //TODO rewrite this method + if (hasSubcatalogs) { + for (NetworkItem::List::iterator it = childrens.begin(); it != childrens.end(); ++it) { + NetworkTreeFactory::createNetworkTree(this, *it); + } + } else { + NetworkTreeFactory::fillAuthorTree(this, childrens); + } + notifyListeners(error); + + this->updated(); +} + +void NetworkCatalogTree::notifyListeners(const std::string &error) { + for (std::size_t i = 0; i < myListeners.size(); ++i) { + if (!myListeners.at(i).isNull()) + myListeners.at(i)->finished(error); + } + myListeners.clear(); +} + +NetworkCatalogItem &NetworkCatalogTree::item() { + return (NetworkCatalogItem&)*myItem; +} + +void NetworkCatalogTree::updateVisibility() { + //adding to remove list and clearing all existed nodes + List toRemove; + NetworkItem::List itemsWithNodes; //used in loop for creating new nodes (for these items new nodes won't be created) + for (size_t i = 0; i < children().size(); ++i) { + ZLTreeNode* tree = children().at(i); + if (!tree->isInstanceOf(NetworkCatalogTree::TYPE_ID)) { + continue; + } + NetworkCatalogTree *child = (NetworkCatalogTree*)tree; + itemsWithNodes.push_back(child->myItem); + switch (child->item().getVisibility()) { + case B3_TRUE: + child->updateVisibility(); + break; + case B3_FALSE: + toRemove.push_back(child); + break; + case B3_UNDEFINED: + child->clearCatalog(); + break; + } + } + + //creating new nodes (if necessary) + for (size_t i = 0; i < myChildrenItems.size(); ++i) { + shared_ptr<NetworkItem> item = myChildrenItems.at(i); + if (!item->isInstanceOf(NetworkCatalogItem::TYPE_ID)) { + continue; + } + if (std::find(itemsWithNodes.begin(), itemsWithNodes.end(), item) != itemsWithNodes.end()) { + continue; + } + NetworkCatalogItem *catalogItem = (NetworkCatalogItem*)(&*item); + if (catalogItem->getVisibility() != B3_FALSE) { + NetworkTreeFactory::createNetworkTree(this, item, i); + } + } + + for (size_t i = 0; i < toRemove.size(); ++i) { + ZLTreeNode* tree = toRemove.at(i); + remove(tree); + } + +} + +void NetworkCatalogTree::clearCatalog() { + myChildrenItems.clear(); + clear(); +} + +const ZLResource &NetworkCatalogTree::resource() const { + return ZLResource::resource("networkView")["libraryItemNode"]; +} diff --git a/reader/src/network/tree/NetworkCatalogUtil.cpp b/reader/src/network/tree/NetworkCatalogUtil.cpp new file mode 100644 index 0000000..953bf67 --- /dev/null +++ b/reader/src/network/tree/NetworkCatalogUtil.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLNetworkManager.h> + +#include <ZLBase64EncodedImage.h> +#include <ZLNetworkImage.h> + +#include "NetworkCatalogUtil.h" + +#include "../NetworkLinkCollection.h" + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByNetworkUrl(const std::string &url, const std::string &prefix) { + if (!ZLStringUtil::stringStartsWith(url, prefix)) { + return 0; + } + + return new ZLNetworkImage(ZLMimeType::IMAGE_AUTO, url); +} + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByDataUrl(const std::string &url) { + if (!ZLStringUtil::stringStartsWith(url, "data:")) { + return 0; + } + + std::size_t index = url.find(','); + if (index == std::string::npos) { + return 0; + } + + ZLBase64EncodedImage *image = new ZLBase64EncodedImage(ZLMimeType::IMAGE_AUTO); + image->addData(url, index + 1, std::string::npos); + return image; +} + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByUrl(const std::string &url) { + shared_ptr<const ZLImage> image; + + image = getImageByNetworkUrl(url, "http://"); + if (!image.isNull()) { + return image; + } + + image = getImageByNetworkUrl(url, "https://"); + if (!image.isNull()) { + return image; + } + + return getImageByDataUrl(url); +} + +class NetworkImageDownloadListener : public ZLNetworkRequest::Listener { +public: + NetworkImageDownloadListener(ZLTreeNode *node) : myNode(node) {} + void finished(const std::string &error) { + if (error.empty()) { + myNode->updated(); + } + } +private: + ZLTreeNode *myNode; +}; + +shared_ptr<const ZLImage> NetworkCatalogUtil::getAndDownloadImageByUrl(const std::string &url, const ZLTreeNode *node) { + shared_ptr<const ZLImage> image = getImageByUrl(url); + + if (!image.isNull()) { + shared_ptr<ZLNetworkRequest> downloadRequest = image->synchronizationData(); + if (!downloadRequest.isNull()) { + downloadRequest->setListener(new NetworkImageDownloadListener(const_cast<ZLTreeNode*>(node))); + ZLNetworkManager::Instance().performAsync(downloadRequest); + } + } + return image; +} diff --git a/reader/src/network/tree/NetworkCatalogUtil.h b/reader/src/network/tree/NetworkCatalogUtil.h new file mode 100644 index 0000000..0196896 --- /dev/null +++ b/reader/src/network/tree/NetworkCatalogUtil.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKCATALOGUTIL_H__ +#define __NETWORKCATALOGUTIL_H__ + +#include <string> + +#include <shared_ptr.h> + +#include <ZLTreeNode.h> + +class ZLImage; + +class NetworkCatalogUtil { + +public: + static shared_ptr<const ZLImage> getImageByUrl(const std::string &url); + static shared_ptr<const ZLImage> getAndDownloadImageByUrl(const std::string &url, const ZLTreeNode *node); + +private: + static shared_ptr<const ZLImage> getImageByNetworkUrl(const std::string &url, const std::string &prefix); + static shared_ptr<const ZLImage> getImageByDataUrl(const std::string &url); + +private: + NetworkCatalogUtil(); +}; + +#endif /* __NETWORKCATALOGUTIL_H__ */ diff --git a/reader/src/network/tree/NetworkLibrary.cpp b/reader/src/network/tree/NetworkLibrary.cpp new file mode 100644 index 0000000..118abd0 --- /dev/null +++ b/reader/src/network/tree/NetworkLibrary.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> + +#include "../NetworkLinkCollection.h" + +//#include "NetworkNodesFactory.h" + +#include "../NetworkItems.h" +#include "../NetworkLinkCollection.h" +#include "../NetworkLink.h" +#include "../SearchResult.h" +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "NetworkSearcher.h" +#include "NetworkTreeNodes.h" + +#include "NetworkLibrary.h" + +NetworkLibrary *NetworkLibrary::ourInstance = 0; + +NetworkLibrary &NetworkLibrary::Instance() { + if (ourInstance == 0) { + ourInstance = new NetworkLibrary(); + } + return *ourInstance; +} + +NetworkLibrary::NetworkLibrary() { + //TODO maybe it should be created in showDialog method? + myDialog = ZLDialogManager::Instance().createTreeDialog(ZLResource::resource("networkView")); + myRootTree.setDialog(myDialog); + myFakeRootTree.setDialog(myDialog); + myUpdateVisibility = false; + myChildrenAreInvalid = true; +} + +void NetworkLibrary::showDialog() { + synchronize(); + myDialog->run(&myRootTree); + myDialog->setSearcher(new NetworkSearcher); +} + +void NetworkLibrary::refresh() { + myDialog->onRefresh(); +} + +void NetworkLibrary::makeUpToDate() { + //TODO rewrite this method + NetworkLinkCollection::Instance().initialize(); + NetworkLinkCollection &collection = NetworkLinkCollection::Instance(); + for (std::size_t i = 0; i < collection.size(); ++i) { + NetworkLink &link = collection.link(i); + new NetworkCatalogRootTree(&myRootTree, link, i); + } +} + +void NetworkLibrary::updateVisibility() { + for (size_t i = 0; i < myRootTree.children().size(); ++i) { + ZLTreeNode* tree = myRootTree.children().at(i); + if (NetworkCatalogTree* catalogTree = zlobject_cast<NetworkCatalogTree*>(tree)) { + catalogTree->updateVisibility(); + } + } +} + +RootTree &NetworkLibrary::getFakeCatalogTree() { + return myFakeRootTree; +} + +void NetworkLibrary::synchronize() { + if (myChildrenAreInvalid) { + myChildrenAreInvalid = false; + makeUpToDate(); + } + if (myUpdateVisibility) { + myUpdateVisibility = false; + updateVisibility(); + } +} + +void NetworkLibrary::invalidateVisibility() { + myUpdateVisibility = true; +} diff --git a/reader/src/network/tree/NetworkLibrary.h b/reader/src/network/tree/NetworkLibrary.h new file mode 100644 index 0000000..026cbbd --- /dev/null +++ b/reader/src/network/tree/NetworkLibrary.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKLIBRARY_H__ +#define __NETWORKLIBRARY_H__ + +#include <ZLTreeDialog.h> + +#include "NetworkTreeNodes.h" + +class NetworkLibrary { + +public: + static NetworkLibrary &Instance(); + +private: + static NetworkLibrary *ourInstance; + +public: + void showDialog(); + void refresh(); + RootTree &getFakeCatalogTree(); + + void synchronize(); + void invalidateVisibility(); + +private: + NetworkLibrary(); + void makeUpToDate(); + + void updateVisibility(); + +private: + shared_ptr<ZLTreeDialog> myDialog; + RootTree myRootTree; + RootTree myFakeRootTree; + bool myUpdateVisibility; + bool myChildrenAreInvalid; +}; + +#endif /* __NETWORKLIBRARY_H__ */ diff --git a/reader/src/network/tree/NetworkSearcher.cpp b/reader/src/network/tree/NetworkSearcher.cpp new file mode 100644 index 0000000..10d318e --- /dev/null +++ b/reader/src/network/tree/NetworkSearcher.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLNetworkManager.h> +#include <ZLDialogManager.h> +#include <ZLTimeManager.h> + +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../NetworkLinkCollection.h" +#include "../NetworkLink.h" +#include "../NetworkOperationData.h" +#include "../NetworkErrors.h" +#include "NetworkTreeNodes.h" +#include "NetworkLibrary.h" +#include "NetworkSearcher.h" + +//TODO rewrite code to not to use fake network link + +NetworkSearcher::NetworkSearcher() { } + +void NetworkSearcher::simpleSearch(const std::string &pattern) { + //TODO maybe move code for simple search from NetworkLinkCollection to here + NetworkCatalogTree *tree = new SearchCatalogTree(&NetworkLibrary::Instance().getFakeCatalogTree(), new AllCatalogsSearchItem(myFakeLink, pattern)); + tree->expand(); +} + +AllCatalogsSearchItem::AllCatalogsSearchItem(const NetworkLink &link, const std::string &pattern) : + NetworkCatalogItem(link, std::string(), std::string(), UrlInfoCollection()), + myPattern(pattern) { +} + +class AllCatalogsSearchItemListener : public ZLNetworkRequest::Listener { +public: + AllCatalogsSearchItemListener(AllCatalogsSearchItem &item, + NetworkItem::List &children, + shared_ptr<ZLNetworkRequest::Listener> listener, + ZLNetworkRequest::Vector requestList, + std::vector<shared_ptr<NetworkOperationData> > dataList) : + myItem(item), + myChildren(children), + myListener(listener), + myDataList(dataList), + myHolder(this) { + myItemFound = false; + myCollection = new NetworkBookCollection; + myCounter = 0; + performRequests(requestList); + } + + void performRequests(ZLNetworkRequest::Vector requestList) { + for (std::size_t i = 0; i < requestList.size(); ++i) { + shared_ptr<ZLNetworkRequest> request = requestList.at(i); + request->setListener(myHolder); + ++myCounter; + ZLNetworkManager::Instance().performAsync(request); + } + } + + void finished(const std::string &error) { + --myCounter; + + ZLNetworkRequest::Vector requestList; + + for (std::size_t i = 0; i < myDataList.size(); ++i) { + shared_ptr<NetworkOperationData> data = myDataList.at(i); + for (std::size_t j = 0; j < data->Items.size(); ++j) { + myCollection->addBook(data->Items.at(j)); + } + + if (!data->Items.empty()) { + shared_ptr<ZLNetworkRequest> request = data->resume(); + if (!request.isNull()) { + request->setListener(myHolder); + requestList.push_back(request); + } + } + } + + + if (!myCollection->books().empty()) { + myItem.onChildrenLoaded(myChildren, myCollection, myListener); + myChildren.clear(); + myCollection->clear(); + } + + if (!requestList.empty()) { + performRequests(requestList); + } + + if (myCounter == 0) { + ZLTimeManager::deleteLater(myHolder); + myHolder.reset(); //destroy itself + } + } + +private: + AllCatalogsSearchItem &myItem; + NetworkItem::List &myChildren; + shared_ptr<ZLNetworkRequest::Listener> myListener; + shared_ptr<NetworkBookCollection> myCollection; //TODO maybe remove this class using + + bool myItemFound; + + std::vector<shared_ptr<NetworkOperationData> > myDataList; + int myCounter; +// std::string myErrorMessage; + shared_ptr<ZLNetworkRequest::Listener> myHolder; //for keeping this instance alive +}; + +std::string AllCatalogsSearchItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + ZLNetworkRequest::Vector requestList; + std::vector<shared_ptr<NetworkOperationData> > dataList; + + const NetworkLinkCollection::LinkVector &links = NetworkLinkCollection::Instance().activeLinks(); + for (std::size_t i = 0; i < links.size(); ++i) { + const NetworkLink &link = *links.at(i); + shared_ptr<NetworkOperationData> data = new NetworkOperationData(link); + + shared_ptr<ZLNetworkRequest> request = link.simpleSearchData(*data, myPattern); + if (!request.isNull()) { + dataList.push_back(data); + requestList.push_back(request); + } + } + + new AllCatalogsSearchItemListener(*this, children, listener, requestList, dataList); + + return std::string(); +} + +void AllCatalogsSearchItem::onChildrenLoaded(NetworkItem::List &children, shared_ptr<NetworkBookCollection> collection, shared_ptr<ZLNetworkRequest::Listener> listener) { + if (!collection.isNull()) { + const NetworkItem::List &books = collection->books(); + children.assign(books.begin(), books.end()); + } + listener->finished(); +} + +FakeNetworkLink::FakeNetworkLink() : NetworkLink("") { } + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::simpleSearchData(NetworkOperationData &/*data*/, const std::string &/*pattern*/) const { + return 0; +} + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::advancedSearchData(NetworkOperationData &/*data*/, const std::string &/*titleAndSeries*/, const std::string &/*author*/, const std::string &/*tag*/, const std::string &/*annotation*/) const { + return 0; +} + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::resume(NetworkOperationData &/*data*/) const { + return 0; +} + +shared_ptr<NetworkAuthenticationManager> FakeNetworkLink::authenticationManager() const { + return 0; +} + +shared_ptr<NetworkItem> FakeNetworkLink::libraryItem() const { + return 0; +} + +void FakeNetworkLink::rewriteUrl(std::string &/*url*/, bool /*isUrlExternal*/) const { +} diff --git a/reader/src/network/tree/NetworkSearcher.h b/reader/src/network/tree/NetworkSearcher.h new file mode 100644 index 0000000..08ebc35 --- /dev/null +++ b/reader/src/network/tree/NetworkSearcher.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKSEARCHER_H__ +#define __NETWORKSEARCHER_H__ + +#include <ZLTreeSearcher.h> + +#include "../NetworkBookCollection.h" +#include "../NetworkItems.h" + +//TODO rewrite code to not to use fake network link +class FakeNetworkLink : public NetworkLink { +public: + FakeNetworkLink(); + shared_ptr<ZLNetworkRequest> simpleSearchData(NetworkOperationData &data, const std::string &pattern) const; + shared_ptr<ZLNetworkRequest> advancedSearchData(NetworkOperationData &data, const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) const; + shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &data) const; + shared_ptr<NetworkAuthenticationManager> authenticationManager() const; + shared_ptr<NetworkItem> libraryItem() const; + void rewriteUrl(std::string &url, bool isUrlExternal = false) const; +}; + +class NetworkSearcher : public ZLTreeSearcher { +public: + NetworkSearcher(); + void simpleSearch(const std::string &pattern); +private: + const FakeNetworkLink myFakeLink; +}; + +class AllCatalogsSearchItem : public NetworkCatalogItem { + +public: + AllCatalogsSearchItem(const NetworkLink &link, const std::string &pattern); + std::string loadChildren(List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + void onChildrenLoaded(List &children, shared_ptr<NetworkBookCollection> collection, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + std::string myPattern; +}; + +#endif /* __NETWORKSEARCHER_H__ */ diff --git a/reader/src/network/tree/NetworkSeriesTree.cpp b/reader/src/network/tree/NetworkSeriesTree.cpp new file mode 100644 index 0000000..4456ade --- /dev/null +++ b/reader/src/network/tree/NetworkSeriesTree.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <set> +#include <algorithm> + +#include <ZLResource.h> +#include <ZLImage.h> +#include <ZLStringUtil.h> + +#include "NetworkCatalogUtil.h" +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkSeriesTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkSeriesTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkSeriesTree::resource() const { + return ZLResource::resource("networkView")["seriesNode"]; +} + +NetworkSeriesTree::NetworkSeriesTree(NetworkTree *parent, const std::string &seriesTitle) : + NetworkTree(parent), mySeriesTitle(seriesTitle) { + init(); +} + +void NetworkSeriesTree::init() { + //registerExpandTreeAction(); +} + +std::string NetworkSeriesTree::title() const { + return mySeriesTitle; +} + +std::string NetworkSeriesTree::subtitle() const { + return ZLStringUtil::printf(resource()["booksCount"].value((int)children().size()), (unsigned int)children().size()); +} + +static const size_t MAX_BATCH_SIZE = 6; + +shared_ptr<const ZLImage> NetworkSeriesTree::image() const { + if (myImages.empty()) { + for (size_t i = 0; i < std::min(children().size(), MAX_BATCH_SIZE); ++i) { + NetworkBookTree *bookTree = zlobject_cast<NetworkBookTree*>(children().at(i)); + if (!bookTree) { + continue; + } + NetworkItem::UrlInfoCollection urlByType = bookTree->book().URLByType; + std::string url = urlByType[NetworkItem::URL_COVER]; + myImages.push_back(NetworkCatalogUtil::getAndDownloadImageByUrl(url, this)); + } + } + return ZLImageManager::Instance().makeBatchImage(myImages, FBTree::defaultCoverImage("booktree-book.png")); +} diff --git a/reader/src/network/tree/NetworkTree.cpp b/reader/src/network/tree/NetworkTree.cpp new file mode 100644 index 0000000..ac7b39a --- /dev/null +++ b/reader/src/network/tree/NetworkTree.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkTree::TYPE_ID(FBTree::TYPE_ID); + +const ZLTypeId &NetworkTree::typeId() const { + return TYPE_ID; +} + + +NetworkTree::NetworkTree(RootTree *parent, std::size_t position) : FBTree(parent, position) { } + +NetworkTree::NetworkTree(NetworkTree *parent, std::size_t position) : FBTree(parent, position) { } diff --git a/reader/src/network/tree/NetworkTreeFactory.cpp b/reader/src/network/tree/NetworkTreeFactory.cpp new file mode 100644 index 0000000..0868034 --- /dev/null +++ b/reader/src/network/tree/NetworkTreeFactory.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkTreeFactory.h" + +#include "NetworkTreeNodes.h" + +#include "../NetworkBookCollection.h" + +NetworkTreeFactory::NetworkTreeFactory() { +} + +ZLTreeTitledNode *NetworkTreeFactory::createNetworkTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position) { + if (item->isInstanceOf(NetworkCatalogItem::TYPE_ID)) { + NetworkCatalogItem *catalogItem = (NetworkCatalogItem*)(&*item); + if (catalogItem->getVisibility() == B3_FALSE) { + return 0; + } + NetworkCatalogTree *ptr = new NetworkCatalogTree(parent, item, position); + ptr->item().onDisplayItem(); + return ptr; + } else if (item->isInstanceOf(NetworkBookItem::TYPE_ID)) { + return new NetworkBookTree(parent, item, NetworkBookTree::AUTHORS); + } + return 0; +} + +void NetworkTreeFactory::fillAuthorTree(NetworkTree *parent, const NetworkItem::List &books) { + NetworkSeriesTree *seriesTree = 0; + NetworkAuthorTree *authorTree = 0; + + int flags = NetworkCatalogItem::FLAGS_DEFAULT; + if (NetworkCatalogTree* catalogTree = zlobject_cast<NetworkCatalogTree*>(parent)) { + flags = catalogTree->item().getFlags(); + } + NetworkBookTree::SummaryType booksSummaryType = NetworkBookTree::AUTHORS; + if ((parent->isInstanceOf(NetworkCatalogTree::TYPE_ID) && + (flags & NetworkCatalogItem::FLAG_SHOW_AUTHOR) == 0) || + parent->isInstanceOf(NetworkAuthorTree::TYPE_ID)) { + booksSummaryType = NetworkBookTree::NONE; + } + + for (NetworkItem::List::const_iterator it = books.begin(); it != books.end(); ++it) { + if (!(*it)->isInstanceOf(NetworkBookItem::TYPE_ID)) { + continue; + } + const NetworkBookItem &book = (const NetworkBookItem &) **it; + + //TODO split this method on smaller parts + switch (flags & NetworkCatalogItem::FLAGS_GROUP) { + case NetworkCatalogItem::FLAG_GROUP_BY_SERIES: + if (book.SeriesTitle.empty()) { + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + if (seriesTree == 0 || seriesTree->title() != book.SeriesTitle) { + seriesTree = new NetworkSeriesTree(parent, book.SeriesTitle); + } + new NetworkBookTree(seriesTree, *it, booksSummaryType); + } + break; + case NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES: + { + std::string seriesTitle = book.SeriesTitle; + if (!seriesTitle.empty() && (seriesTree == 0 || seriesTree->title() != seriesTitle)) { + NetworkItem::List::const_iterator jt = it + 1; + while (jt != books.end() && !(*jt)->isInstanceOf(NetworkBookItem::TYPE_ID)) { + ++jt; + } + if (jt == books.end()) { + seriesTitle.clear(); + } else { + const NetworkBookItem &next = (const NetworkBookItem&)**jt; + if (next.SeriesTitle != seriesTitle) { + seriesTitle.clear(); + } + } + } + if (seriesTitle.empty()) { + seriesTree = 0; + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + if (seriesTree == 0 || seriesTree->title() != seriesTitle) { + seriesTree = new NetworkSeriesTree(parent, seriesTitle); + } + new NetworkBookTree(seriesTree, *it, booksSummaryType); + } + } + break; + case NetworkCatalogItem::FLAG_GROUP_BY_AUTHOR: + if (book.Authors.empty()) { + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + const NetworkBookItem::AuthorData &author = book.Authors.front(); + if (authorTree == 0 || authorTree->author() != author) { + authorTree = new NetworkAuthorTree(parent, author); + } + new NetworkBookTree(authorTree, *it, booksSummaryType); + } + break; + default: + new NetworkBookTree(parent, *it, booksSummaryType); + break; + } + + + } +} diff --git a/reader/src/network/tree/NetworkTreeFactory.h b/reader/src/network/tree/NetworkTreeFactory.h new file mode 100644 index 0000000..b53213e --- /dev/null +++ b/reader/src/network/tree/NetworkTreeFactory.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKTREEFACTORY_H__ +#define __NETWORKTREEFACTORY_H__ + +#include "../NetworkItems.h" + +class NetworkBookCollection; +class FBTree; +class NetworkCatalogTree; +class NetworkTree; +class ZLTreeTitledNode; + + +class NetworkTreeFactory { + +private: + NetworkTreeFactory(); + +public: + static ZLTreeTitledNode *createNetworkTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + static void fillAuthorTree(NetworkTree *parent, const NetworkItem::List &books); +}; + +#endif /* __NETWORKTREEFACTORY_H__ */ diff --git a/reader/src/network/tree/NetworkTreeNodes.h b/reader/src/network/tree/NetworkTreeNodes.h new file mode 100644 index 0000000..fcc76f6 --- /dev/null +++ b/reader/src/network/tree/NetworkTreeNodes.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKTREENODES_H__ +#define __NETWORKTREENODES_H__ + +#include <ZLResource.h> +#include <ZLExecutionUtil.h> + +#include <ZLTreeNode.h> +#include <ZLTreeDialog.h> +#include <ZLTreePageNode.h> + +#include "../NetworkLink.h" +#include "../../tree/FBTree.h" + +//maybe RootTree should be nested class for NetworkLibrary? +class RootTree : public ZLTreeNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + RootTree(); + void setDialog(shared_ptr<ZLTreeDialog> dialog); + + +protected: + ZLTreeListener *listener() const; + +private: + shared_ptr<ZLTreeDialog> myListener; +}; + +class NetworkTree : public FBTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + NetworkTree(RootTree *parent, std::size_t position); + NetworkTree(NetworkTree *parent, std::size_t position = (std::size_t)-1); +}; + +class NetworkCatalogTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + NetworkCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + NetworkCatalogTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + + std::string title() const; + std::string subtitle() const; + shared_ptr<const ZLImage> image() const; + + void requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + void requestMoreChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + virtual void onChildrenReceived(NetworkItem::List &childrens, const std::string &error); + + NetworkCatalogItem &item(); + + void updateVisibility(); + void clearCatalog(); + +private: + void init(); + void notifyListeners(const std::string &error); + +private: + void onAuthCheck(const std::string &error); + +private: + const ZLResource &resource() const; + +private: + shared_ptr<NetworkItem> myItem; + NetworkItem::List myChildrenItems; + + std::vector<shared_ptr<ZLNetworkRequest::Listener> > myListeners; + mutable shared_ptr<const ZLImage> myImage; + +friend class NetworkTreeFactory; +friend class NetworkCatalogTreeAuthListener; +}; + +class NetworkCatalogRootTree : public NetworkCatalogTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + class LoginAction; + class LogoutAction; + class TopupAccountAction; + class PasswordRecoveryAction; + class RegisterUserAction; + +public: + NetworkCatalogRootTree(RootTree *parent, NetworkLink &link, std::size_t position); + void init(); + +private: + const ZLResource &resource() const; + +private: + NetworkLink &myLink; +}; + +class SearchCatalogTree : public NetworkCatalogTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + SearchCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + + void requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + void onChildrenReceived(NetworkItem::List &childrens, const std::string &error); +}; + +class NetworkAuthorTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +protected: + NetworkAuthorTree(NetworkTree *parent, const NetworkBookItem::AuthorData &author); + +friend class NetworkTreeFactory; + +public: + const NetworkBookItem::AuthorData &author(); + +private: + void init(); + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + std::string title() const; + +private: + NetworkBookItem::AuthorData myAuthor; +}; + +class NetworkSeriesTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +protected: + NetworkSeriesTree(NetworkTree *parent, const std::string &seriesTitle); + +friend class NetworkTreeFactory; + +private: + void init(); + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + std::string title() const; + std::string subtitle() const; + +private: + std::string mySeriesTitle; + mutable std::vector<shared_ptr<const ZLImage> > myImages; +}; + +class NetworkBookTree : public ZLTreePageNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + enum SummaryType { AUTHORS, NONE }; + +private: + NetworkBookTree(NetworkTree *parent, shared_ptr<NetworkItem> book, SummaryType summaryType); + void init(); + +friend class NetworkTreeFactory; + +public: + const NetworkBookItem &book() const; + +public: + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + shared_ptr<const ZLImage> fullImage() const; + std::string title() const; + std::string subtitle() const; + + shared_ptr<ZLTreePageInfo> getPageInfo(); + +private: + class BookItemWrapper : public ZLTreePageInfo { + + public: + BookItemWrapper(NetworkBookTree &tree, shared_ptr<NetworkItem> bookItem); + + bool isPageInfoLoaded(); + void loadAll(shared_ptr<ZLNetworkRequest::Listener> listener); + void onInformationLoaded(ZLUserDataHolder &data, const std::string &error); + void onCoverLoaded(ZLUserDataHolder &data, const std::string &error); + + public: + std::string title() const; + std::vector<std::string> authors() const; + std::vector<std::string> tags() const; + std::string summary() const; + shared_ptr<const ZLImage> image() const; + + //TODO maybe store actions in other place? + const std::vector<shared_ptr<ZLTreeAction> > &actions() const; + std::string actionText(const shared_ptr<ZLTreeAction> &action) const; + const std::vector<shared_ptr<ZLTreeAction> > relatedActions() const; + + private: + NetworkBookItem &book() const; + + private: + NetworkBookTree &myTree; + shared_ptr<NetworkItem> myBookItem; + mutable bool myIsInitialized; + + mutable std::vector<shared_ptr<ZLTreeAction> > myRelatedActions; + }; + +private: + shared_ptr<NetworkItem> myBook; + SummaryType mySummaryType; + mutable shared_ptr<const ZLImage> myImage; + shared_ptr<ZLTreePageInfo> myPageInfo; +}; + +#endif /* __NETWORKTREENODES_H__ */ diff --git a/reader/src/network/tree/RootTree.cpp b/reader/src/network/tree/RootTree.cpp new file mode 100644 index 0000000..8aad8a5 --- /dev/null +++ b/reader/src/network/tree/RootTree.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkTreeNodes.h" + +const ZLTypeId RootTree::TYPE_ID(ZLTreeNode::TYPE_ID); + +const ZLTypeId &RootTree::typeId() const { + return TYPE_ID; +} + + +RootTree::RootTree() { + +} + +void RootTree::setDialog(shared_ptr<ZLTreeDialog> dialog) { + myListener = dialog; +} + +ZLTreeListener *RootTree::listener() const { + if (myListener.isNull()) { + return 0; + } + return &(*myListener); +} diff --git a/reader/src/network/tree/SearchCatalogTree.cpp b/reader/src/network/tree/SearchCatalogTree.cpp new file mode 100644 index 0000000..62ee967 --- /dev/null +++ b/reader/src/network/tree/SearchCatalogTree.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkTreeNodes.h" + +const ZLTypeId SearchCatalogTree::TYPE_ID(NetworkCatalogTree::TYPE_ID); + +const ZLTypeId &SearchCatalogTree::typeId() const { + return TYPE_ID; +} + +SearchCatalogTree::SearchCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkCatalogTree(parent, item, position) { + //TODO maybe remove this class +} + +void SearchCatalogTree::requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + notifySearchStarted(); + NetworkCatalogTree::requestChildren(listener); +} + +void SearchCatalogTree::onChildrenReceived(NetworkItem::List &childrens, const std::string &error) { + notifySearchStopped(); + NetworkCatalogTree::onChildrenReceived(childrens, error); +} diff --git a/reader/src/networkActions/AuthenticationDialog.cpp b/reader/src/networkActions/AuthenticationDialog.cpp new file mode 100644 index 0000000..4f4ed1a --- /dev/null +++ b/reader/src/networkActions/AuthenticationDialog.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialog.h> +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> + +#include <ZLSimpleOptionEntry.h> + +#include "../network/NetworkLink.h" +#include "AuthenticationDialog.h" +#include "NetworkOperationRunnable.h" +#include "../network/UserList.h" +#include "../network/authentication/NetworkAuthenticationManager.h" + +class UserNamesEntry : public ZLComboOptionEntry { + +public: + UserNamesEntry(UserList &userList, ZLStringOption &userNameOption); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + +private: + UserList &myUserList; + ZLStringOption &myUserNameOption; +}; + +UserNamesEntry::UserNamesEntry(UserList &userList, ZLStringOption &userNameOption) : + ZLComboOptionEntry(true), myUserList(userList), myUserNameOption(userNameOption) { +} + +const std::string &UserNamesEntry::initialValue() const { + return myUserNameOption.value(); +} + +const std::vector<std::string> &UserNamesEntry::values() const { + return myUserList.users(); +} + +void UserNamesEntry::onAccept(const std::string &value) { + myUserList.addUser(value); + myUserNameOption.setValue(value); +} + + +class PasswordOptionEntry : public ZLPasswordOptionEntry { + +public: + PasswordOptionEntry(std::string &password); + + virtual const std::string &initialValue() const; + virtual void onAccept(const std::string &value); + +private: + std::string &myPassword; +}; + +PasswordOptionEntry::PasswordOptionEntry(std::string &password) : myPassword(password) { +} + +const std::string &PasswordOptionEntry::initialValue() const { + static const std::string _empty; + return _empty; +} + +void PasswordOptionEntry::onAccept(const std::string &value) { + myPassword = value; +} + +AuthenticationDialog::AuthenticationDialog(ZLStringOption &userNameOption, UserList &userList, const std::string &errorMessage, std::string &password) : + myUserList(userList) { + myDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("AuthenticationDialog")); + + if (!errorMessage.empty()) { + myDialog->addOption("", "", new ZLSimpleStaticTextOptionEntry(errorMessage)); + } + + myDialog->addOption(ZLResourceKey("login"), new UserNamesEntry(myUserList, userNameOption)); + myDialog->addOption(ZLResourceKey("password"), new PasswordOptionEntry(password)); + + myDialog->addButton(ZLDialogManager::OK_BUTTON, true); + myDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); +} + +bool AuthenticationDialog::run(ZLStringOption &userNameOption, UserList &userList, const std::string &errorMessage, std::string &password) { + AuthenticationDialog dlg(userNameOption, userList, errorMessage, password); + if (dlg.dialog().run()) { + dlg.dialog().acceptValues(); + return true; + } + return false; +} + +bool AuthenticationDialog::run(const std::string &siteName, std::string &userName, std::string &password, const std::string &message) { + UserList userList(siteName); + //TODO fix it: using unexisted string option, just for dialog showing + ZLStringOption userNameOption(ZLCategoryKey::NETWORK, "", "userName", userName); + userNameOption.setValue(std::string()); + bool result = run(userNameOption, userList, message, password); + userName = userNameOption.value(); + userNameOption.clearGroup(""); + return result; +} diff --git a/reader/src/networkActions/AuthenticationDialog.h b/reader/src/networkActions/AuthenticationDialog.h new file mode 100644 index 0000000..ff5148c --- /dev/null +++ b/reader/src/networkActions/AuthenticationDialog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __AUTHENTICATIONDIALOG_H__ +#define __AUTHENTICATIONDIALOG_H__ + +#include <string> + +#include <ZLOptionEntry.h> + +#include "../network/UserList.h" + +class ZLDialog; +class NetworkAuthenticationManager; + +class AuthenticationDialog { + +public: + static bool run(ZLStringOption &userNameOption, UserList &userList, const std::string &errorMessage, std::string &password); + static bool run(const std::string &siteName, std::string &username, std::string &password, const std::string &message); + +private: + AuthenticationDialog(ZLStringOption &userNameOption, UserList &userList, const std::string &errorMessage, std::string &password); + + ZLDialog &dialog(); + +private: + shared_ptr<ZLDialog> myDialog; + UserList &myUserList; +}; + +inline ZLDialog &AuthenticationDialog::dialog() { return *myDialog; } + +#endif /* __AUTHENTICATIONDIALOG_H__ */ diff --git a/reader/src/networkActions/AuthenticationDialogManager.cpp b/reader/src/networkActions/AuthenticationDialogManager.cpp new file mode 100644 index 0000000..165ab01 --- /dev/null +++ b/reader/src/networkActions/AuthenticationDialogManager.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLExecutionUtil.h> +#include <ZLResource.h> +#include <ZLTimeManager.h> + +#include "../network/NetworkErrors.h" +#include "../network/NetworkLink.h" +#include "AuthenticationDialog.h" +#include "NetworkOperationRunnable.h" + +#include "AuthenticationDialogManager.h" + +class AuthenticationDialogListener : public ZLNetworkRequest::Listener { +public: + AuthenticationDialogListener(NetworkAuthenticationManager &mgr, shared_ptr<ZLNetworkRequest::Listener> listener); + + void returnAnswer(bool result); + virtual void finished(const std::string &error = std::string()); + +private: + void restart(const std::string &error); + + enum State { LogOut, Authorisation, Initialization }; + + shared_ptr<ZLNetworkRequest::Listener> myHolder; + + NetworkAuthenticationManager &myManager; + shared_ptr<ZLNetworkRequest::Listener> myListener; + std::string myPassword; + UserList myUserList; + std::string myError; + State myState; +}; + +AuthenticationDialogListener::AuthenticationDialogListener(NetworkAuthenticationManager &mgr, shared_ptr<ZLNetworkRequest::Listener> listener) + : myHolder(this), myManager(mgr), myListener(listener), myUserList(mgr.Link.getSiteName()), myState(LogOut) { + finished(std::string()); //start state machine from LogOut state +} + +void AuthenticationDialogListener::returnAnswer(bool result) { + if (result) { + myUserList.saveUser(myManager.currentUserName()); + } + // TODO: Return notable error + myListener->setUIStatus(false); + myListener->finished(result ? std::string() : "Some error"); + ZLTimeManager::deleteLater(myHolder); + myHolder.reset(); +} + + + +void AuthenticationDialogListener::finished(const std::string &error) { + myError = error; + myListener->setUIStatus(false); + switch (myState) { + case LogOut: + if (!AuthenticationDialog::run(myManager.UserNameOption, myUserList, myError, myPassword)) { + myManager.logOut(); + returnAnswer(false); + return; + } + if (myManager.UserNameOption.value().empty()) { + const ZLResource &resource = ZLResource::resource("dialog")["AuthenticationDialog"]; + restart(resource["loginIsEmpty"].value()); + } else { + myState = Authorisation; + myListener->setUIStatus(true); + myManager.authorise(myPassword, myHolder); + return; + } + break; + case Authorisation: + if (!myError.empty()) { + restart(myError); + return; + } + if (myManager.needsInitialization()) { + myState = Initialization; + myListener->setUIStatus(true); + myManager.initialize(myHolder); + } else { + returnAnswer(true); + } + break; + case Initialization: + if (!myError.empty()) { + restart(myError); + return; + } + returnAnswer(true); + break; + } +} + +void AuthenticationDialogListener::restart(const std::string &error) { + myPassword.clear(); + myState = LogOut; + finished(error); + //TODO it was autoremovable task here +} + + +class AuthoriseIfCanListener : public ZLNetworkRequest::Listener { +public: + AuthoriseIfCanListener(NetworkAuthenticationManager &mgr, shared_ptr<ZLNetworkRequest::Listener> listener); + + void returnAnswer(std::string answer = std::string()); + virtual void finished(const std::string &error = std::string()); + +private: + enum State { Init, AuthorisationCheck, Initialization}; + + shared_ptr<ZLNetworkRequest::Listener> myHolder; + + NetworkAuthenticationManager &myManager; + shared_ptr<ZLNetworkRequest::Listener> myListener; + State myState; +}; + +AuthoriseIfCanListener::AuthoriseIfCanListener(NetworkAuthenticationManager &mgr, shared_ptr<ZLNetworkRequest::Listener> listener) + : myHolder(this), myManager(mgr), myListener(listener), myState(Init) { + finished(std::string()); //start state machine from Init state +} + +void AuthoriseIfCanListener::returnAnswer(std::string answer) { + myListener->setUIStatus(false); + myListener->finished(answer); + ZLTimeManager::deleteLater(myHolder); + myHolder.reset(); +} + +void AuthoriseIfCanListener::finished(const std::string &error) { + myListener->setUIStatus(false); + switch (myState) { + case Init: + myListener->setUIStatus(true); + myState = AuthorisationCheck; + myManager.isAuthorised(myHolder); + break; + case AuthorisationCheck: + if (!error.empty()) { + NetworkErrors::showErrorMessage(error); + returnAnswer(error); + return; + } + if (myManager.needsInitialization()) { + myState = Initialization; + myListener->setUIStatus(true); + myManager.initialize(myHolder); + } else { + returnAnswer(); + } + break; + case Initialization: + if (!error.empty()) { + NetworkErrors::showErrorMessage(error); + returnAnswer(error); + return; + } + returnAnswer(); + break; + } +} + +std::string AuthenticationDialogManager::authAndInitAsync(NetworkAuthenticationManager &manager, shared_ptr<ZLNetworkRequest::Listener> listener) { + new AuthenticationDialogListener(manager, listener); + return std::string(); +} + +std::string AuthenticationDialogManager::athoriseIfCan(NetworkAuthenticationManager &manager, shared_ptr<ZLNetworkRequest::Listener> listener) { + new AuthoriseIfCanListener(manager, listener); + return std::string(); +} diff --git a/reader/src/networkActions/AuthenticationDialogManager.h b/reader/src/networkActions/AuthenticationDialogManager.h new file mode 100644 index 0000000..3648d59 --- /dev/null +++ b/reader/src/networkActions/AuthenticationDialogManager.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __AUTHENTICATIONDIALOGMANAGER_H__ +#define __AUTHENTICATIONDIALOGMANAGER_H__ + +#include <ZLNetworkRequest.h> + +#include "../network/authentication/NetworkAuthenticationManager.h" + +class AuthenticationDialogManager { + +public: + static std::string authAndInitAsync(NetworkAuthenticationManager &manager, shared_ptr<ZLNetworkRequest::Listener> listener); + static std::string athoriseIfCan(NetworkAuthenticationManager &manager, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + AuthenticationDialogManager() {} +}; + +#endif /* __AUTHENTICATIONDIALOGMANAGER_H__ */ diff --git a/reader/src/networkActions/NetworkActions.cpp b/reader/src/networkActions/NetworkActions.cpp new file mode 100644 index 0000000..4f2f2c6 --- /dev/null +++ b/reader/src/networkActions/NetworkActions.cpp @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLResource.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> +#include <ZLDialogManager.h> +#include <ZLNetworkRequest.h> +#include <ZLExecutionUtil.h> + +#include "../network/NetworkLinkCollection.h" +#include "../network/NetworkErrors.h" +#include "NetworkActions.h" +#include "AuthenticationDialogManager.h" +#include "NetworkOperationRunnable.h" + +#include "../network/NetworkItems.h" +#include "../network/NetworkLink.h" +#include "../network/authentication/NetworkAuthenticationManager.h" + +#include "../library/Book.h" +#include "../reader/Reader.h" + +NetworkBookReadAction::NetworkBookReadAction(const NetworkBookItem &book, bool demo) : myBook(book), myDemo(demo) { +} + +ZLResourceKey NetworkBookReadAction::key() const { + return ZLResourceKey(myDemo ? "readDemo" : "read"); +} + +bool NetworkBookReadAction::makesSense() const { + if (myDemo) { + if (!myBook.localCopyFileName().empty() || + !myBook.reference(BookReference::DOWNLOAD_FULL).isNull()) { + return false; + } + shared_ptr<BookReference> reference = + myBook.reference(BookReference::DOWNLOAD_DEMO); + return !reference.isNull() && !reference->localCopyFileName().empty(); + } else { + return !myBook.localCopyFileName().empty(); + } +} + +void NetworkBookReadAction::run() { + std::string fileName; + if (myDemo) { + shared_ptr<BookReference> reference = + myBook.reference(BookReference::DOWNLOAD_DEMO); + if (!reference.isNull()) { + fileName = reference->localCopyFileName(); + } + } else { + fileName = myBook.localCopyFileName(); + } + if (!fileName.empty()) { + Reader &reader = Reader::Instance(); + shared_ptr<Book> bookPtr; + reader.createBook(ZLFile(fileName), bookPtr); + if (!bookPtr.isNull()) { + reader.openBook(bookPtr); + reader.setMode(Reader::BOOK_TEXT_MODE); + reader.refreshWindow(); + NetworkLibrary::Instance().refresh(); + } + } +} + +NetworkBookDownloadAction::NetworkBookDownloadAction(NetworkBookTree &tree, const NetworkBookItem &book, bool demo, const std::string &tag) : myTree(tree), myBook(book), myDemo(demo), myTag(tag) { +} + +ZLResourceKey NetworkBookDownloadAction::key() const { + return ZLResourceKey(myDemo ? "downloadDemo" : "download"); +} + +bool NetworkBookDownloadAction::makesSense() const { + if (myDemo) { + if (!myBook.localCopyFileName().empty() || + !myBook.reference(BookReference::DOWNLOAD_FULL).isNull()) { + return false; + } + shared_ptr<BookReference> reference = + myBook.reference(BookReference::DOWNLOAD_DEMO); + return !reference.isNull() && reference->localCopyFileName().empty(); + } else { + return + myBook.localCopyFileName().empty() && + !myBook.reference(BookReference::DOWNLOAD_FULL).isNull(); + } +} + +class NetworkBookDownloadActionListener : public ZLNetworkRequest::Listener { +public: + NetworkBookDownloadActionListener(NetworkBookDownloadAction *action) : myAction(action) {} + void finished(const std::string &error) { + myAction->onBookDownloaded(error); + } + +private: + NetworkBookDownloadAction *myAction; +}; + +void NetworkBookDownloadAction::run() { + + myTree.notifyDownloadStarted(); + + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + shared_ptr<BookReference> reference = myBook.reference( + myDemo ? BookReference::DOWNLOAD_DEMO : BookReference::DOWNLOAD_FULL + ); + if (reference.isNull()) { + return; + } + bool result = NetworkLinkCollection::Instance().downloadBook(*reference, myFileName, new NetworkBookDownloadActionListener(this)); + if (!result) { + NetworkErrors::showErrorMessage(NetworkLinkCollection::Instance().errorMessage()); + } +} + +void NetworkBookDownloadAction::onBookDownloaded(const std::string &error) { + + myTree.notifyDownloadStopped(); + + if (!error.empty()) { + NetworkErrors::showErrorMessage(error); + } + Reader &reader = Reader::Instance(); + shared_ptr<Book> downloaderBook; + reader.createBook(ZLFile(myFileName), downloaderBook); + if (downloaderBook.isNull()) { + ZLFile(myFileName).remove(); + ZLResourceKey boxKey("cantOpenDownloadedFile"); + const std::string message = ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), myBook.Title); + ZLDialogManager::Instance().errorBox(boxKey, message); + reader.refreshWindow(); + NetworkLibrary::Instance().refresh(); + return; + } + + downloaderBook->removeAllAuthors(); + for (std::vector<NetworkBookItem::AuthorData>::const_iterator it = myBook.Authors.begin(); it != myBook.Authors.end(); ++it) { + downloaderBook->addAuthor(it->DisplayName, it->SortKey); + } + std::string bookTitle = myBook.Title; + if (!myTag.empty()) { + bookTitle += " (" + myTag + ")"; + } + downloaderBook->setTitle(bookTitle); + downloaderBook->setLanguage(myBook.Language); + for (std::vector<std::string>::const_iterator it = myBook.Tags.begin(); it != myBook.Tags.end(); ++it) { + downloaderBook->addTag(*it); + } + if (!myTag.empty()) { + downloaderBook->addTag(myTag); + } + Library::Instance().addBook(downloaderBook); + + reader.openBook(downloaderBook); + reader.setMode(Reader::BOOK_TEXT_MODE); + reader.refreshWindow(); + NetworkLibrary::Instance().refresh(); +} + +NetworkBookBuyDirectlyAction::NetworkBookBuyDirectlyAction(NetworkBookTree &tree, const NetworkBookItem &book) :NetworkBookDownloadAction(tree, book, false) { +} + +ZLResourceKey NetworkBookBuyDirectlyAction::key() const { + return ZLResourceKey("buy"); +} + +bool NetworkBookBuyDirectlyAction::makesSense() const { + return + myBook.localCopyFileName().empty() && + myBook.reference(BookReference::DOWNLOAD_FULL).isNull() && + !myBook.reference(BookReference::BUY).isNull(); +} + +std::string NetworkBookBuyDirectlyAction::text(const ZLResource &resource) const { + const std::string text = ZLRunnableWithKey::text(resource); + shared_ptr<BookReference> reference = myBook.reference(BookReference::BUY); + if (!reference.isNull()) { + return ZLStringUtil::printf(text, ((BuyBookReference&)*reference).Price); + } + return text; +} + +void NetworkBookBuyDirectlyAction::run() { + if (myBook.Link.authenticationManager().isNull()) { + finished(std::string()); + return; + } + if (!NetworkOperationRunnable::tryConnect()) { + finished(std::string()); + return; + } + + NetworkAuthenticationManager &mgr = *myBook.Link.authenticationManager(); + myTree.notifyDownloadStarted(); + mgr.isAuthorised(ZLExecutionUtil::createListener(this, &NetworkBookBuyDirectlyAction::onAuthorisationCheck)); +} + +class BuyActionAuthListener : public ZLNetworkRequest::Listener { +public: + BuyActionAuthListener(NetworkBookBuyDirectlyAction &action) : myAction(action) { + } + + void finished(const std::string &error) { + myAction.onAuthorised(error); + } + + void setUIStatus(bool enabled) { + if (enabled) { + myAction.myTree.notifyDownloadStarted(); + } else { + myAction.myTree.notifyDownloadStopped(); + } + } + +private: + NetworkBookBuyDirectlyAction &myAction; +}; + +void NetworkBookBuyDirectlyAction::onAuthorisationCheck(ZLUserDataHolder &/*data*/, const std::string &error) { + myTree.notifyDownloadStopped(); + if (error.empty()) { + onAuthorised(error); + } else { + AuthenticationDialogManager::authAndInitAsync( + *myBook.Link.authenticationManager(), + new BuyActionAuthListener(*this) + ); + } +} + +void NetworkBookBuyDirectlyAction::onAuthorised(const std::string &error) { + if (!error.empty()) { + finished(std::string()); //ignore error message + return; + } + NetworkAuthenticationManager &mgr = *myBook.Link.authenticationManager(); + if (!mgr.needPurchase(myBook)) { + finished(std::string()); + return; + } + ZLResourceKey boxKey("purchaseConfirmBox"); + const std::string message = ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), myBook.Title); + const int code = ZLDialogManager::Instance().questionBox(boxKey, message, ZLResourceKey("buy"), ZLResourceKey("buyAndDownload"), ZLDialogManager::CANCEL_BUTTON); + if (code == 2) { + finished(std::string()); + return; + } + bool downloadBook = code == 1; + if (mgr.needPurchase(myBook)) { + ZLUserDataHolder *bookData = new ZLUserDataHolder; + if (downloadBook) { + bookData->addUserData("downloadBook", new ZLUserData); + } + myTree.notifyDownloadStarted(); + mgr.purchaseBook(myBook, ZLExecutionUtil::createListener(bookData, this, &NetworkBookBuyDirectlyAction::onPurchased)); + } else if (downloadBook) { + NetworkBookDownloadAction::run(); + } +} + +void NetworkBookBuyDirectlyAction::onPurchased(ZLUserDataHolder &data, const std::string &error) { + if (!error.empty()) { + finished(error); + return; + } + if (data.getUserData("downloadBook").isNull()) { + finished(std::string()); + } else { + NetworkBookDownloadAction::run(); + } +} + +void NetworkBookBuyDirectlyAction::finished(const std::string &error) { + myTree.notifyDownloadStopped(); + NetworkLibrary::Instance().refresh(); + if (!error.empty()) { + ZLDialogManager::Instance().errorBox(ZLResourceKey("networkError"), error); + } +} + +NetworkBookBuyInBrowserAction::NetworkBookBuyInBrowserAction(const NetworkBookItem &book) : myBook(book) { +} + +ZLResourceKey NetworkBookBuyInBrowserAction::key() const { + return ZLResourceKey("buy"); +} + +bool NetworkBookBuyInBrowserAction::makesSense() const { + return + myBook.localCopyFileName().empty() && + myBook.reference(BookReference::DOWNLOAD_FULL).isNull() && + myBook.reference(BookReference::BUY).isNull() && + !myBook.reference(BookReference::BUY_IN_BROWSER).isNull(); +} + +std::string NetworkBookBuyInBrowserAction::text(const ZLResource &resource) const { + const std::string text = ZLRunnableWithKey::text(resource); + shared_ptr<BookReference> reference = myBook.reference(BookReference::BUY_IN_BROWSER); + if (!reference.isNull()) { + return ZLStringUtil::printf(text, ((BuyBookReference&)*reference).Price); + } + return text; +} + +void NetworkBookBuyInBrowserAction::run() { + shared_ptr<BookReference> reference = myBook.reference(BookReference::BUY_IN_BROWSER); + if (!reference.isNull()) { + Reader::Instance().openLinkInBrowser(reference->URL); + } + NetworkLibrary::Instance().refresh(); +} + +NetworkBookDeleteAction::NetworkBookDeleteAction(const NetworkBookItem &book) : myBook(book) { +} + +ZLResourceKey NetworkBookDeleteAction::key() const { + return ZLResourceKey("delete"); +} + +bool NetworkBookDeleteAction::makesSense() const { + return !myBook.localCopyFileName().empty(); +} + +void NetworkBookDeleteAction::run() { + ZLResourceKey boxKey("deleteLocalCopyBox"); + const std::string message = ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), myBook.Title); + if (ZLDialogManager::Instance().questionBox(boxKey, message, ZLDialogManager::YES_BUTTON, ZLDialogManager::NO_BUTTON) != 0) { + return; + } + + myBook.removeLocalFiles(); + Reader::Instance().refreshWindow(); + NetworkLibrary::Instance().refresh(); +} diff --git a/reader/src/networkActions/NetworkActions.h b/reader/src/networkActions/NetworkActions.h new file mode 100644 index 0000000..f0cf513 --- /dev/null +++ b/reader/src/networkActions/NetworkActions.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKACTIONS_H__ +#define __NETWORKACTIONS_H__ + +#include <ZLRunnable.h> +#include <ZLNetworkRequest.h> +#include "../network/tree/NetworkLibrary.h" + +class NetworkBookItem; + +class NetworkBookDownloadAction : public ZLRunnableWithKey { + +public: + NetworkBookDownloadAction(NetworkBookTree &tree, const NetworkBookItem &book, bool demo, const std::string &tag = std::string()); + ZLResourceKey key() const; + bool makesSense() const; + void run(); + + virtual void onBookDownloaded(const std::string &error); //virtual for using redefined in NetworkTreeBookDownloadAction + +protected: + NetworkBookTree &myTree; + const NetworkBookItem &myBook; + const bool myDemo; + const std::string myTag; + std::string myFileName; +}; + +class NetworkBookReadAction : public ZLRunnableWithKey { + +public: + NetworkBookReadAction(const NetworkBookItem &book, bool demo); + ZLResourceKey key() const; + bool makesSense() const; + void run(); + +private: + const NetworkBookItem &myBook; + const bool myDemo; +}; + +class NetworkBookBuyDirectlyAction : public NetworkBookDownloadAction { + +public: + NetworkBookBuyDirectlyAction(NetworkBookTree &tree, const NetworkBookItem &book); + ZLResourceKey key() const; + bool makesSense() const; + std::string text(const ZLResource &resource) const; + void run(); + +private: + void onAuthorisationCheck(ZLUserDataHolder &data, const std::string &error); + void onAuthorised(const std::string &error); + void onPurchased(ZLUserDataHolder &data, const std::string &error); + void finished(const std::string &error); + +friend class BuyActionAuthListener; +}; + +class NetworkBookBuyInBrowserAction : public ZLRunnableWithKey { + +public: + NetworkBookBuyInBrowserAction(const NetworkBookItem &book); + ZLResourceKey key() const; + bool makesSense() const; + std::string text(const ZLResource &resource) const; + void run(); + +private: + const NetworkBookItem &myBook; +}; + +class NetworkBookDeleteAction : public ZLRunnableWithKey { + +public: + NetworkBookDeleteAction(const NetworkBookItem &book); + ZLResourceKey key() const; + bool makesSense() const; + void run(); + +private: + const NetworkBookItem &myBook; +}; + +#endif /* __NETWORKACTIONS_H__ */ diff --git a/reader/src/networkActions/NetworkOperationRunnable.cpp b/reader/src/networkActions/NetworkOperationRunnable.cpp new file mode 100644 index 0000000..11a874c --- /dev/null +++ b/reader/src/networkActions/NetworkOperationRunnable.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLProgressDialog.h> +#include <ZLNetworkManager.h> + +#include "NetworkOperationRunnable.h" + +#include "../network/NetworkItems.h" +#include "../network/NetworkLink.h" +#include "../network/NetworkLinkCollection.h" +#include "../network/authentication/NetworkAuthenticationManager.h" + +NetworkOperationRunnable::NetworkOperationRunnable(const std::string &uiMessageKey) { + myDialog = + ZLDialogManager::Instance().createProgressDialog(ZLResourceKey(uiMessageKey), true); +} + +NetworkOperationRunnable::~NetworkOperationRunnable() { +} + +void NetworkOperationRunnable::executeWithUI() { + myDialog->run(*this); +} + +bool NetworkOperationRunnable::hasErrors() const { + return !myErrorMessage.empty(); +} + +void NetworkOperationRunnable::showErrorMessage(const std::string &message) { + ZLDialogManager::Instance().errorBox( + ZLResourceKey("networkError"), + message + ); +} + +const std::string &NetworkOperationRunnable::errorMessage() const { + return myErrorMessage; +} + +bool NetworkOperationRunnable::tryConnect() { + if (!ZLNetworkManager::Instance().connect()) { + showErrorMessage( + ZLResource::resource("dialog") + ["networkError"] + ["couldntConnectToNetworkMessage"].value() + ); + return false; + } + return true; +} + +void NetworkOperationRunnable::showErrorMessage() const { + if (!myErrorMessage.empty()) { + showErrorMessage(myErrorMessage); + } +} + +DownloadBookRunnable::DownloadBookRunnable(shared_ptr<BookReference> reference, shared_ptr<NetworkAuthenticationManager> authManager) : NetworkOperationRunnable("downloadBook") { + myReference = reference; + myAuthManager = authManager; +} + +DownloadBookRunnable::DownloadBookRunnable(const std::string &url) : NetworkOperationRunnable("downloadBook") { + myReference = new BookReference(url, BookReference::NONE, BookReference::DOWNLOAD_FULL); +} + +DownloadBookRunnable::~DownloadBookRunnable() { +} + +void DownloadBookRunnable::run() { + NetworkLinkCollection::Instance().downloadBook( + *myReference, myFileName, + myDialog->listener() + ); + myErrorMessage = NetworkLinkCollection::Instance().errorMessage(); +} + +const std::string &DownloadBookRunnable::fileName() const { + return myFileName; +} + +//AuthoriseRunnable::AuthoriseRunnable(NetworkAuthenticationManager &mgr, const std::string &password) : +// NetworkOperationRunnable("authentication"), +// myManager(mgr), +// myPassword(password) { +//} + +//void AuthoriseRunnable::run() { +// myErrorMessage = myManager.authorise(myPassword); +//} + +//LogOutRunnable::LogOutRunnable(NetworkAuthenticationManager &mgr) : +// NetworkOperationRunnable("signOut"), +// myManager(mgr) { +//} + +//void LogOutRunnable::run() { +// if (myManager.isAuthorised().Status != B3_FALSE) { +// myManager.logOut(); +// } +//} + +PasswordRecoveryRunnable::PasswordRecoveryRunnable(NetworkAuthenticationManager &mgr, const std::string &email) : + NetworkOperationRunnable("passwordRecovery"), + myManager(mgr), + myEMail(email) { +} + +void PasswordRecoveryRunnable::run() { + myErrorMessage = myManager.recoverPassword(myEMail); +} + +RegisterUserRunnable::RegisterUserRunnable(NetworkAuthenticationManager &mgr, const std::string &login, const std::string &password, const std::string &email) : + NetworkOperationRunnable("registerUser"), + myManager(mgr), + myLogin(login), + myPassword(password), + myEMail(email) { +} + +void RegisterUserRunnable::run() { + myErrorMessage = myManager.registerUser(myLogin, myPassword, myEMail); +} + + +SearchRunnable::SearchRunnable() : NetworkOperationRunnable("downloadBookList") { +} + + +SimpleSearchRunnable::SimpleSearchRunnable(const std::string &pattern) : myPattern(pattern) { +} + +void SimpleSearchRunnable::run() { + mySearchResult = NetworkLinkCollection::Instance().simpleSearch(myPattern); + myErrorMessage = NetworkLinkCollection::Instance().errorMessage(); +} + + +AdvancedSearchRunnable::AdvancedSearchRunnable(const std::string &titleAndSeries, const std::string &author, const std::string &category, const std::string &description) : myTitleAndSeries(titleAndSeries), myAuthor(author), myCategory(category), myDescription(description) { +} + +void AdvancedSearchRunnable::run() { + mySearchResult = NetworkLinkCollection::Instance().advancedSearch(myTitleAndSeries, myAuthor, myCategory, myDescription); + myErrorMessage = NetworkLinkCollection::Instance().errorMessage(); +} + + +LoadSubCatalogRunnable::LoadSubCatalogRunnable(NetworkCatalogItem &item, NetworkItem::List &children) : + NetworkOperationRunnable("loadSubCatalog"), + myItem(item), + myChildren(children) { +} + +void LoadSubCatalogRunnable::run() { + myErrorMessage = myItem.loadChildren(myChildren); +} + +DownloadBookRunnableAsync::DownloadBookRunnableAsync(shared_ptr<BookReference> reference, shared_ptr<NetworkAuthenticationManager> authManager) { + myReference = reference; + myAuthManager = authManager; +} + +void DownloadBookRunnableAsync::run() { +} + +void DownloadBookRunnableAsync::showPercent(int /*ready*/, int /*full*/) {} + +void DownloadBookRunnableAsync::finished(const std::string &error) { +} diff --git a/reader/src/networkActions/NetworkOperationRunnable.h b/reader/src/networkActions/NetworkOperationRunnable.h new file mode 100644 index 0000000..4a7e8da --- /dev/null +++ b/reader/src/networkActions/NetworkOperationRunnable.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKOPERATIONRUNNABLE_H__ +#define __NETWORKOPERATIONRUNNABLE_H__ + +#include <string> + +#include <ZLRunnable.h> +#include <ZLBoolean3.h> + +#include "../network/NetworkItems.h" +#include "../network/NetworkBookCollection.h" + +class ZLProgressDialog; + +class NetworkAuthenticationManager; + +class NetworkOperationRunnable : public ZLRunnable { + +public: + static void showErrorMessage(const std::string &message); + static bool tryConnect(); + +protected: + NetworkOperationRunnable(const std::string &uiMessageKey); + ~NetworkOperationRunnable(); + +public: + void executeWithUI(); + bool hasErrors() const; + void showErrorMessage() const; + const std::string &errorMessage() const; + +protected: + std::string myErrorMessage; + shared_ptr<ZLProgressDialog> myDialog; +}; + +class DownloadBookRunnable : public NetworkOperationRunnable { + +public: + DownloadBookRunnable(shared_ptr<BookReference> reference, shared_ptr<NetworkAuthenticationManager> authManager); + DownloadBookRunnable(const std::string &url); + ~DownloadBookRunnable(); + void run(); + + const std::string &fileName() const; + +private: + shared_ptr<BookReference> myReference; + shared_ptr<NetworkAuthenticationManager> myAuthManager; + std::string myFileName; +}; + +class DownloadBookRunnableAsync : public ZLNetworkRequest::Listener { + +public: + DownloadBookRunnableAsync(shared_ptr<BookReference> reference, shared_ptr<NetworkAuthenticationManager> authManager); + void run(); + + void showPercent(int ready, int full); + void finished(const std::string &error); + +private: + shared_ptr<BookReference> myReference; + shared_ptr<NetworkAuthenticationManager> myAuthManager; + std::string myFileName; +}; + +//class AuthoriseRunnable : public NetworkOperationRunnable { + +//public: +// AuthoriseRunnable(NetworkAuthenticationManager &mgr, const std::string &password); +// void run(); + +//private: +// NetworkAuthenticationManager &myManager; +// const std::string &myPassword; +//}; + +//class LogOutRunnable : public NetworkOperationRunnable { + +//public: +// LogOutRunnable(NetworkAuthenticationManager &mgr); +// void run(); + +//private: +// NetworkAuthenticationManager &myManager; +//}; + +class PasswordRecoveryRunnable : public NetworkOperationRunnable { + +public: + PasswordRecoveryRunnable(NetworkAuthenticationManager &mgr, const std::string &email); + void run(); + +private: + NetworkAuthenticationManager &myManager; + const std::string &myEMail; +}; + +class RegisterUserRunnable : public NetworkOperationRunnable { + +public: + RegisterUserRunnable(NetworkAuthenticationManager &mgr, const std::string &login, const std::string &password, const std::string &email); + void run(); + +private: + NetworkAuthenticationManager &myManager; + const std::string &myLogin; + const std::string &myPassword; + const std::string &myEMail; +}; + + +class SearchRunnable : public NetworkOperationRunnable { + +protected: + SearchRunnable(); + +public: + shared_ptr<NetworkBookCollection> result(); + +protected: + shared_ptr<NetworkBookCollection> mySearchResult; +}; + +inline shared_ptr<NetworkBookCollection> SearchRunnable::result() { return mySearchResult; } + + +class SimpleSearchRunnable : public SearchRunnable { + +public: + SimpleSearchRunnable(const std::string &pattern); + void run(); + +private: + const std::string myPattern; +}; + + +class AdvancedSearchRunnable : public SearchRunnable { + +public: + AdvancedSearchRunnable(const std::string &titleAndSeries, const std::string &author, const std::string &category, const std::string &description); + void run(); + +private: + const std::string myTitleAndSeries; + const std::string myAuthor; + const std::string myCategory; + const std::string myDescription; +}; + + +class LoadSubCatalogRunnable : public NetworkOperationRunnable { + +public: + LoadSubCatalogRunnable(NetworkCatalogItem &item, NetworkItem::List &children); + void run(); + +private: + NetworkCatalogItem &myItem; + NetworkItem::List &myChildren; +}; + +#endif /* __NETWORKOPERATIONRUNNABLE_H__ */ diff --git a/reader/src/networkActions/PasswordRecoveryDialog.cpp b/reader/src/networkActions/PasswordRecoveryDialog.cpp new file mode 100644 index 0000000..70d6c61 --- /dev/null +++ b/reader/src/networkActions/PasswordRecoveryDialog.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLDialog.h> +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLStringEditOptionEntry.h> + +#include "PasswordRecoveryDialog.h" +#include "NetworkOperationRunnable.h" + +#include "../network/authentication/NetworkAuthenticationManager.h" +#include "../network/NetworkErrors.h" + +#include "../reader/Reader.h" + +PasswordRecoveryDialog::PasswordRecoveryDialog(std::string &email, const std::string &errorMessage) { + myDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("PasswordRecoveryDialog")); + + if (!errorMessage.empty()) { + myDialog->addOption("", "", new ZLSimpleStaticTextOptionEntry(errorMessage)); + } + + myDialog->addOption(ZLResourceKey("email"), new ZLStringEditOptionEntry(email)); + + myDialog->addButton(ZLDialogManager::OK_BUTTON, true); + myDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); +} + +bool PasswordRecoveryDialog::runDialog(std::string &email, std::string &errorMessage) { + //const ZLResource &resource = ZLResource::resource("dialog")["PasswordRecoveryDialog"]; + while (true) { + PasswordRecoveryDialog dlg(email, errorMessage); + if (dlg.dialog().run()) { + dlg.dialog().acceptValues(); + if (email.empty()) { + errorMessage = NetworkErrors::errorMessage(NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED); + continue; + } + std::size_t atPos = email.find('@'); + if (atPos >= (email.size() - 1) || email.find('.', atPos) == std::string::npos) { + errorMessage = NetworkErrors::errorMessage(NetworkErrors::ERROR_INVALID_EMAIL); + continue; + } + return true; + } + return false; + } +} + +bool PasswordRecoveryDialog::run(NetworkAuthenticationManager &mgr) { + std::string errorMessage; + std::string email; + while (true) { + if (!runDialog(email, errorMessage)) { + mgr.logOut(); + return false; + } + + PasswordRecoveryRunnable recovery(mgr, email); + recovery.executeWithUI(); + if (recovery.hasErrors()) { + errorMessage = recovery.errorMessage(); + mgr.logOut(); + continue; + } + + ZLResourceKey boxKey("recoverySuccessfulBox"); + const std::string message = + ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), email); + ZLDialogManager::Instance().informationBox(boxKey, message); + + return true; + } +} diff --git a/reader/src/networkActions/PasswordRecoveryDialog.h b/reader/src/networkActions/PasswordRecoveryDialog.h new file mode 100644 index 0000000..b2d9c86 --- /dev/null +++ b/reader/src/networkActions/PasswordRecoveryDialog.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PASSWORDRECOVERYDIALOG_H__ +#define __PASSWORDRECOVERYDIALOG_H__ + +#include <string> + +class ZLDialog; +class NetworkAuthenticationManager; + +class PasswordRecoveryDialog { + +private: + PasswordRecoveryDialog(std::string &email, const std::string &errorMessage); + + ZLDialog &dialog(); + + static bool runDialog(std::string &email, std::string &errorMessage); + +public: + static bool run(NetworkAuthenticationManager &mgr); + +private: + shared_ptr<ZLDialog> myDialog; +}; + +inline ZLDialog &PasswordRecoveryDialog::dialog() { return *myDialog; } + +#endif /* __PASSWORDRECOVERYDIALOG_H__ */ diff --git a/reader/src/networkActions/RegisterUserDialog.cpp b/reader/src/networkActions/RegisterUserDialog.cpp new file mode 100644 index 0000000..589aae6 --- /dev/null +++ b/reader/src/networkActions/RegisterUserDialog.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialog.h> +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLStringEditOptionEntry.h> + + +#include "RegisterUserDialog.h" +#include "NetworkOperationRunnable.h" + +#include "../network/authentication/NetworkAuthenticationManager.h" +#include "../network/NetworkErrors.h" + +#include "../reader/Reader.h" + + +class HiddenValueEntry : public ZLPasswordOptionEntry { + +public: + HiddenValueEntry(std::string &value); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + std::string &myValue; +}; + +HiddenValueEntry::HiddenValueEntry(std::string &value) : myValue(value) { +} + +const std::string &HiddenValueEntry::initialValue() const { + return myValue; +} + +void HiddenValueEntry::onAccept(const std::string &value) { + myValue = value; +} + + +RegisterUserDialog::RegisterUserDialog(const std::string &login, const std::string &password, const std::string &email, const std::string &errorMessage) { + myDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("RegisterUserDialog")); + + if (!errorMessage.empty()) { + myDialog->addOption("", "", new ZLSimpleStaticTextOptionEntry(errorMessage)); + } + + myLogin = login; + myPassword0 = myPassword1 = password; + myEMail = email; + + myDialog->addOption(ZLResourceKey("login"), new ZLStringEditOptionEntry(myLogin)); + myDialog->addOption(ZLResourceKey("password"), new HiddenValueEntry(myPassword0)); + myDialog->addOption(ZLResourceKey("confirmPassword"), new HiddenValueEntry(myPassword1)); + myDialog->addOption(ZLResourceKey("email"), new ZLStringEditOptionEntry(myEMail)); + + myDialog->addButton(ZLDialogManager::OK_BUTTON, true); + myDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); +} + +bool RegisterUserDialog::runDialog(std::string &login, std::string &password, std::string &email, std::string &errorMessage) { + const ZLResource &resource = ZLResource::resource("dialog")["RegisterUserDialog"]; + while (true) { + RegisterUserDialog dlg(login, password, email, errorMessage); + if (dlg.dialog().run()) { + dlg.dialog().acceptValues(); + login = dlg.myLogin; + password = dlg.myPassword0; + email = dlg.myEMail; + if (login.empty()) { + errorMessage = NetworkErrors::errorMessage(NetworkErrors::ERROR_LOGIN_WAS_NOT_SPECIFIED); + continue; + } + if (dlg.myPassword0 != dlg.myPassword1) { + errorMessage = resource["differentPasswords"].value(); + password.clear(); + continue; + } + if (email.empty()) { + errorMessage = NetworkErrors::errorMessage(NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED); + continue; + } + std::size_t atPos = email.find('@'); + if (atPos >= (email.size() - 1) || email.find('.', atPos) == std::string::npos) { + errorMessage = NetworkErrors::errorMessage(NetworkErrors::ERROR_INVALID_EMAIL); + continue; + } + return true; + } + return false; + } +} + +bool RegisterUserDialog::run(NetworkAuthenticationManager &mgr) { + std::string errorMessage; + std::string login; + std::string password; + std::string email; + while (true) { + if (!runDialog(login, password, email, errorMessage)) { + mgr.logOut(); + return false; + } + + RegisterUserRunnable registration(mgr, login, password, email); + registration.executeWithUI(); + if (registration.hasErrors()) { + errorMessage = registration.errorMessage(); + mgr.logOut(); + continue; + } + +// if (mgr.isAuthorised().Status != B3_FALSE && mgr.needsInitialization()) { +// InitializeAuthenticationManagerRunnable initializer(mgr); +// initializer.executeWithUI(); +// if (initializer.hasErrors()) { +// initializer.showErrorMessage(); +// LogOutRunnable logout(mgr); +// logout.executeWithUI(); +// return false; +// } +// } + return true; + } +} diff --git a/reader/src/networkActions/RegisterUserDialog.h b/reader/src/networkActions/RegisterUserDialog.h new file mode 100644 index 0000000..6dcb3d1 --- /dev/null +++ b/reader/src/networkActions/RegisterUserDialog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __REGISTERUSERDIALOG_H__ +#define __REGISTERUSERDIALOG_H__ + +#include <string> + +class ZLDialog; +class NetworkAuthenticationManager; + +class RegisterUserDialog { + +private: + RegisterUserDialog(const std::string &login, const std::string &password, const std::string &email, const std::string &errorMessage); + + ZLDialog &dialog(); + + static bool runDialog(std::string &login, std::string &password, std::string &email, std::string &errorMessage); + +public: + static bool run(NetworkAuthenticationManager &mgr); + +private: + shared_ptr<ZLDialog> myDialog; + std::string myLogin; + std::string myPassword0; + std::string myPassword1; + std::string myEMail; +}; + +inline ZLDialog &RegisterUserDialog::dialog() { return *myDialog; } + +#endif /* __REGISTERUSERDIALOG_H__ */ diff --git a/reader/src/options/FBCategoryKey.cpp b/reader/src/options/FBCategoryKey.cpp new file mode 100644 index 0000000..b1ab431 --- /dev/null +++ b/reader/src/options/FBCategoryKey.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "FBCategoryKey.h" + +FBCategoryKey::FBCategoryKey(const std::string &name) : ZLCategoryKey(name) { +} + +const FBCategoryKey FBCategoryKey::BOOKS("books"); +const FBCategoryKey FBCategoryKey::SEARCH("search"); +const FBCategoryKey FBCategoryKey::EXTERNAL("external"); diff --git a/reader/src/options/FBCategoryKey.h b/reader/src/options/FBCategoryKey.h new file mode 100644 index 0000000..8550340 --- /dev/null +++ b/reader/src/options/FBCategoryKey.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBCATEGORYKEY_H__ +#define __FBCATEGORYKEY_H__ + +#include <ZLOptions.h> + +class FBCategoryKey : public ZLCategoryKey { + +public: + static const FBCategoryKey BOOKS; + static const FBCategoryKey SEARCH; + static const FBCategoryKey EXTERNAL; + +private: + FBCategoryKey(const std::string &name); +}; + +#endif /* __FBCATEGORYKEY_H__ */ diff --git a/reader/src/options/FBOptions.cpp b/reader/src/options/FBOptions.cpp new file mode 100644 index 0000000..c7d8f97 --- /dev/null +++ b/reader/src/options/FBOptions.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "FBOptions.h" + +FBOptions* FBOptions::ourInstance = 0; + +static const std::string OPTIONS = "Options"; +static const std::string COLORS = "Colors"; + +FBOptions::FBOptions() : + LeftMarginOption(ZLCategoryKey::LOOK_AND_FEEL, OPTIONS, "LeftMargin", 0, 1000, 4), + RightMarginOption(ZLCategoryKey::LOOK_AND_FEEL, OPTIONS, "RightMargin", 0, 1000, 4), + TopMarginOption(ZLCategoryKey::LOOK_AND_FEEL, OPTIONS, "TopMargin", 0, 1000, 0), + BottomMarginOption(ZLCategoryKey::LOOK_AND_FEEL, OPTIONS, "BottomMargin", 0, 1000, 4), + BackgroundColorOption(ZLCategoryKey::LOOK_AND_FEEL, COLORS, "Background", ZLColor(255, 255, 255)), + RegularTextColorOption(ZLCategoryKey::LOOK_AND_FEEL, COLORS, "Text", ZLColor(0, 0, 0)) { + myColorOptions["internal"] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "Hyperlink", ZLColor(33, 96, 180) + ); + myColorOptions["external"] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "ExternalHyperlink", ZLColor(33, 96, 180) + ); + myColorOptions["book"] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "BookHyperlink", ZLColor(23, 68, 128) + ); + myColorOptions[ZLTextStyle::SELECTION_BACKGROUND] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "SelectionBackground", ZLColor(82, 131, 194) + ); + myColorOptions[ZLTextStyle::HIGHLIGHTED_TEXT] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "SelectedText", ZLColor(60, 139, 255) + ); + myColorOptions[ZLTextStyle::TREE_LINES] = new ZLColorOption( + ZLCategoryKey::LOOK_AND_FEEL, COLORS, + "TreeLines", ZLColor(127, 127, 127) + ); +} + +ZLColorOption &FBOptions::colorOption(const std::string &style) { + std::map<std::string,shared_ptr<ZLColorOption> >::const_iterator it = + myColorOptions.find(style); + return it != myColorOptions.end() ? *it->second : RegularTextColorOption; +} diff --git a/reader/src/options/FBOptions.h b/reader/src/options/FBOptions.h new file mode 100644 index 0000000..be1e1fc --- /dev/null +++ b/reader/src/options/FBOptions.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBOPTIONS_H__ +#define __FBOPTIONS_H__ + +#include <string> +#include <map> + +#include <shared_ptr.h> + +#include <ZLOptions.h> +#include <ZLTextStyle.h> + +class FBOptions { + +public: + static FBOptions& Instance(); + +private: + static FBOptions *ourInstance; + +public: + ZLIntegerRangeOption LeftMarginOption; + ZLIntegerRangeOption RightMarginOption; + ZLIntegerRangeOption TopMarginOption; + ZLIntegerRangeOption BottomMarginOption; + ZLColorOption BackgroundColorOption; + ZLColorOption RegularTextColorOption; + + ZLColorOption &colorOption(const std::string &style); + +private: + FBOptions(); + FBOptions(const FBOptions&); + const FBOptions &operator = (const FBOptions&); + +private: + std::map<std::string,shared_ptr<ZLColorOption> > myColorOptions; +}; + +inline FBOptions& FBOptions::Instance() { + if (ourInstance == 0) { + ourInstance = new FBOptions(); + } + return *ourInstance; +} + +#endif /* __FBOPTIONS_H__ */ diff --git a/reader/src/options/FBTextStyle.cpp b/reader/src/options/FBTextStyle.cpp new file mode 100644 index 0000000..c8ad9c5 --- /dev/null +++ b/reader/src/options/FBTextStyle.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptions.h> + +#include "FBTextStyle.h" + +shared_ptr<ZLTextStyle> FBTextStyle::ourInstance; + +shared_ptr<ZLTextStyle> FBTextStyle::InstanceAsPtr() { + if (ourInstance.isNull()) { + ourInstance = new FBTextStyle(); + } + return ourInstance; +} + +FBTextStyle &FBTextStyle::Instance() { + return (FBTextStyle&)*InstanceAsPtr(); +} + +static const std::string GROUP = "Style"; + +FBTextStyle::FBTextStyle() : + FontFamilyOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:fontFamily", ""), + FontSizeOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:fontSize", 5, 72, 26), + BoldOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:bold", false), + ItalicOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:italic", false), + AlignmentOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:alignment", ALIGN_JUSTIFY), + LineSpaceOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:lineSpacing", 1.4), + LineSpacePercentOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP, "Base:lineSpacingPercent", 140) { +} + +const std::string &FBTextStyle::colorStyle() const { + return REGULAR_TEXT; +} + +bool FBTextStyle::isDecorated() const { + return false; +} + +const std::string &FBTextStyle::fontFamily() const { + return FontFamilyOption.value(); +} + +int FBTextStyle::fontSize() const { + return FontSizeOption.value(); +} + +bool FBTextStyle::bold() const { + return BoldOption.value(); +} + +bool FBTextStyle::italic() const { + return ItalicOption.value(); +} + +short FBTextStyle::spaceBefore(const ZLTextStyleEntry::Metrics&) const { + return 0; +} + +short FBTextStyle::spaceAfter(const ZLTextStyleEntry::Metrics&) const { + return 0; +} + +short FBTextStyle::lineStartIndent(const ZLTextStyleEntry::Metrics&, bool) const { + return 0; +} + +short FBTextStyle::lineEndIndent(const ZLTextStyleEntry::Metrics&, bool) const { + return 0; +} + +short FBTextStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics&) const { + return 0; +} + +int FBTextStyle::verticalShift() const { + return 0; +} + +ZLTextAlignmentType FBTextStyle::alignment() const { + return (ZLTextAlignmentType)AlignmentOption.value(); +} + +double FBTextStyle::lineSpace() const { + return LineSpacePercentOption.value() / 100.0; +} + +bool FBTextStyle::allowHyphenations() const { + return true; +} diff --git a/reader/src/options/FBTextStyle.h b/reader/src/options/FBTextStyle.h new file mode 100644 index 0000000..8bc0762 --- /dev/null +++ b/reader/src/options/FBTextStyle.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBTEXTSTYLE_H__ +#define __FBTEXTSTYLE_H__ + +#include <ZLTextStyle.h> + +class FBTextStyle : public ZLTextStyle { + +public: + static shared_ptr<ZLTextStyle> InstanceAsPtr(); + static FBTextStyle &Instance(); + +private: + static shared_ptr<ZLTextStyle> ourInstance; + +private: + FBTextStyle(); + +public: + bool isDecorated() const; + + const std::string &fontFamily() const; + + int fontSize() const; + bool bold() const; + bool italic() const; + + const std::string &colorStyle() const; + + short spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const; + short spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const; + short lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const; + short lineEndIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const; + short firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const; + int verticalShift() const; + + ZLTextAlignmentType alignment() const; + + double lineSpace() const; + + bool allowHyphenations() const; + +public: + ZLStringOption FontFamilyOption; + ZLIntegerRangeOption FontSizeOption; + ZLBooleanOption BoldOption; + ZLBooleanOption ItalicOption; + ZLIntegerOption AlignmentOption; + ZLDoubleOption LineSpaceOption; + ZLIntegerOption LineSpacePercentOption; +}; + +#endif /* __FBTEXTSTYLE_H__ */ diff --git a/reader/src/optionsDialog/AbstractOptionsDialog.cpp b/reader/src/optionsDialog/AbstractOptionsDialog.cpp new file mode 100644 index 0000000..b49596d --- /dev/null +++ b/reader/src/optionsDialog/AbstractOptionsDialog.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> + +#include "AbstractOptionsDialog.h" + +#include "../reader/Reader.h" + + +class OptionsApplyRunnable : public ZLRunnable { + +public: + void run(); +}; + +void OptionsApplyRunnable::run() { + Reader &reader = Reader::Instance(); + reader.grabAllKeys(reader.KeyboardControlOption.value()); + reader.clearTextCaches(); + reader.refreshWindow(); +} + + +AbstractOptionsDialog::AbstractOptionsDialog(const ZLResourceKey &key, bool showApplyButton) { + myDialog = ZLDialogManager::Instance().createOptionsDialog(key, new OptionsApplyRunnable(), showApplyButton); +} + +void AbstractOptionsDialog::storeTemporaryOption(ZLOption *option) { + myTemporaryOptions.push_back(option); +} diff --git a/reader/src/optionsDialog/AbstractOptionsDialog.h b/reader/src/optionsDialog/AbstractOptionsDialog.h new file mode 100644 index 0000000..31f4904 --- /dev/null +++ b/reader/src/optionsDialog/AbstractOptionsDialog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __ABSTRACTOPTIONSDIALOG_H__ +#define __ABSTRACTOPTIONSDIALOG_H__ + +#include <vector> +#include <shared_ptr.h> + +class ZLOptionsDialog; +class ZLResourceKey; +class ProgramCollection; +class ZLOption; +class ZLOptionEntry; + +class AbstractOptionsDialog { + +public: + AbstractOptionsDialog(const ZLResourceKey &key, bool showApplyButton); + + ZLOptionsDialog &dialog(); + +protected: + void createIntegrationTab(shared_ptr<ProgramCollection> collection, const ZLResourceKey &key, std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> > &additionalOptions); + void storeTemporaryOption(ZLOption *option); + +private: + shared_ptr<ZLOptionsDialog> myDialog; + std::vector<shared_ptr<ZLOption> > myTemporaryOptions; +}; + +inline ZLOptionsDialog &AbstractOptionsDialog::dialog() { return *myDialog; } + +#endif /* __ABSTRACTOPTIONSDIALOG_H__ */ diff --git a/reader/src/optionsDialog/IntegrationTab.cpp b/reader/src/optionsDialog/IntegrationTab.cpp new file mode 100644 index 0000000..ca3ebf0 --- /dev/null +++ b/reader/src/optionsDialog/IntegrationTab.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> +#include <ZLStringUtil.h> + +#include <ZLToggleBooleanOptionEntry.h> +#include <ZLSimpleOptionEntry.h> + +#include "AbstractOptionsDialog.h" + +#include "../options/FBCategoryKey.h" +#include "../external/ProgramCollection.h" + + +class ProgramChoiceEntry : public ZLComboOptionEntry { + +public: + ProgramChoiceEntry(const ProgramCollection &collection); + +private: + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + void onValueSelected(int index); + +public: + const std::string &initialValue() const; + void addDependentEntry(const std::string &name, ZLOptionEntry *dependentEntry); + void updateDependentEntries(bool visible); + +private: + const ProgramCollection &myCollection; + std::string myValue; + std::map<ZLOptionEntry*,std::string> myDependentEntries; +}; + +class EnableIntegrationEntry : public ZLToggleBooleanOptionEntry { + +public: + EnableIntegrationEntry(ZLBooleanOption &option); + void setProgramChoiceEntry(ProgramChoiceEntry *programChoiceEntry); + void onStateChanged(bool state); + +private: + ProgramChoiceEntry *myProgramChoiceEntry; +}; + +ProgramChoiceEntry::ProgramChoiceEntry(const ProgramCollection &collection) : myCollection(collection) { + myValue = initialValue(); +} + +const std::string &ProgramChoiceEntry::initialValue() const { + return myCollection.CurrentNameOption.value(); +} + +const std::vector<std::string> &ProgramChoiceEntry::values() const { + return myCollection.names(); +} + +void ProgramChoiceEntry::onAccept(const std::string &value) { + myCollection.CurrentNameOption.setValue(value); +} + +void ProgramChoiceEntry::addDependentEntry(const std::string &name, ZLOptionEntry *dependentEntry) { + myDependentEntries[dependentEntry] = name; +} + +void ProgramChoiceEntry::onValueSelected(int index) { + myValue = values()[index]; + updateDependentEntries(true); +} + +void ProgramChoiceEntry::updateDependentEntries(bool visible) { + for (std::map<ZLOptionEntry*,std::string>::const_iterator it = myDependentEntries.begin(); it != myDependentEntries.end(); ++it) { + it->first->setVisible(visible && (it->second == myValue)); + } +} + +EnableIntegrationEntry::EnableIntegrationEntry(ZLBooleanOption &option) : ZLToggleBooleanOptionEntry(option), myProgramChoiceEntry(0) { +} + +void EnableIntegrationEntry::setProgramChoiceEntry(ProgramChoiceEntry *programChoiceEntry) { + addDependentEntry(programChoiceEntry); + myProgramChoiceEntry = programChoiceEntry; +} + +void EnableIntegrationEntry::onStateChanged(bool state) { + ZLToggleBooleanOptionEntry::onStateChanged(state); + if (myProgramChoiceEntry != 0) { + myProgramChoiceEntry->updateDependentEntries(state); + } +} + +void AbstractOptionsDialog::createIntegrationTab(shared_ptr<ProgramCollection> collection, const ZLResourceKey &key, std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> > &additionalOptions) { + if (!collection.isNull()) { + const std::vector<std::string> &programNames = collection->names(); + if (!programNames.empty()) { + ZLDialogContent &tab = myDialog->createTab(key); + std::string optionName; + if (programNames.size() == 1) { + optionName = ZLStringUtil::printf(tab.value(ZLResourceKey("enableIntegration")), programNames[0]); + } else { + optionName = tab.value(ZLResourceKey("defaultText")); + } + EnableIntegrationEntry *enableIntegrationEntry = + new EnableIntegrationEntry(collection->EnableCollectionOption); + tab.addOption(optionName, "", enableIntegrationEntry); + + ProgramChoiceEntry *programChoiceEntry = 0; + if (programNames.size() > 1) { + programChoiceEntry = new ProgramChoiceEntry(*collection); + tab.addOption(ZLResourceKey("choice"), programChoiceEntry); + enableIntegrationEntry->setProgramChoiceEntry(programChoiceEntry); + } + + for (std::vector<std::string>::const_iterator it = programNames.begin(); it != programNames.end(); ++it) { + const std::vector<Program::OptionDescription> &options = collection->program(*it)->options(); + for (std::vector<Program::OptionDescription>::const_iterator jt = options.begin(); jt != options.end(); ++jt) { + ZLStringOption *parameterOption = new ZLStringOption(FBCategoryKey::EXTERNAL, *it, jt->OptionName, jt->DefaultValue); + storeTemporaryOption(parameterOption); + ZLOptionEntry *parameterEntry = new ZLSimpleStringOptionEntry(*parameterOption); + if (programChoiceEntry != 0) { + programChoiceEntry->addDependentEntry(*it, parameterEntry); + } else { + enableIntegrationEntry->addDependentEntry(parameterEntry); + } + tab.addOption(ZLResourceKey(jt->OptionName), parameterEntry); + } + } + for (std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> >::const_iterator it = additionalOptions.begin(); it != additionalOptions.end(); ++it) { + enableIntegrationEntry->addDependentEntry(it->second); + tab.addOption(it->first, it->second); + } + enableIntegrationEntry->onStateChanged(enableIntegrationEntry->initialState()); + return; + } + } + + for (std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> >::const_iterator it = additionalOptions.begin(); it != additionalOptions.end(); ++it) { + delete it->second; + } +} diff --git a/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp b/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp new file mode 100644 index 0000000..197bd98 --- /dev/null +++ b/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> +#include <ZLFile.h> +#include <ZLLanguageList.h> +#include <ZLStringUtil.h> + +#include <ZLStringInfoEntry.h> +#include <ZLSimpleOptionEntry.h> +#include <ZLLanguageOptionEntry.h> + +#include "BookInfoDialog.h" + +#include "../../library/Library.h" +#include "../../encodingOption/EncodingOptionEntry.h" +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../../library/Author.h" + +static const std::size_t AUTHOR_ENTRIES_POOL_SIZE = 64; +static const std::size_t TAG_ENTRIES_POOL_SIZE = 64; + +class AuthorDisplayNameEntry : public ZLComboOptionEntry { + +public: + AuthorDisplayNameEntry(BookInfoDialog &dialog, shared_ptr<Author> initialAuthor, bool &visible); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + void onValueChanged(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; + mutable std::vector<std::string> myValues; + shared_ptr<Author> myCurrentAuthor; + + std::string myInitialValue; + bool myEmpty; + +friend class SeriesTitleEntry; +friend class BookInfoApplyAction; +}; + + +class SeriesTitleEntry : public ZLComboOptionEntry { + +public: + SeriesTitleEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + BookInfoDialog &myInfoDialog; + std::set<std::string> myOriginalValuesSet; + mutable std::vector<std::string> myValues; +}; + + +class BookIndexEntry : public ZLStringOptionEntry { + +public: + BookIndexEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + + + + +AuthorDisplayNameEntry::AuthorDisplayNameEntry(BookInfoDialog &dialog, shared_ptr<Author> initialAuthor, bool &visible) : + ZLComboOptionEntry(true), myInfoDialog(dialog), myCurrentAuthor(initialAuthor) { + + if (myCurrentAuthor.isNull()) { + myInitialValue = ""; + myEmpty = true; + } else { + myInitialValue = myCurrentAuthor->name(); + myEmpty = myInitialValue.empty(); + } + setVisible(visible || !myEmpty); + if (visible && myEmpty) { + visible = false; + } +} + +const std::string &AuthorDisplayNameEntry::initialValue() const { + return myInitialValue; +} + +const std::vector<std::string> &AuthorDisplayNameEntry::values() const { + if (myValues.empty()) { + const std::string &initial = initialValue(); + bool addInitial = true; + const AuthorList &authors = Library::Instance().authors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (it->isNull()) { + continue; + } + const std::string name = (*it)->name(); + if (addInitial && (name == initial)) { + addInitial = false; + } + myValues.push_back(name); + } + if (addInitial) { + myValues.push_back(initial); + } + } + return myValues; +} + +void AuthorDisplayNameEntry::onAccept(const std::string &value) { + if (!isVisible() || value.empty()) { + myCurrentAuthor = 0; + return; + } + if (!myCurrentAuthor.isNull() && value == myCurrentAuthor->name()) { + //myCurrentAuthor = myCurrentAuthor; + return; + } + myCurrentAuthor = Author::getAuthor(value); +} + + +bool AuthorDisplayNameEntry::useOnValueEdited() const { + return true; +} + +void AuthorDisplayNameEntry::onValueEdited(const std::string &value) { + onValueChanged(value); +} + +void AuthorDisplayNameEntry::onValueSelected(int index) { + const AuthorList &authors = Library::Instance().authors(); + myCurrentAuthor = (((std::size_t)index) < authors.size()) ? authors[index] : 0; + myInfoDialog.mySeriesTitleEntry->resetView(); + onValueChanged(myValues[index]); +} + +void AuthorDisplayNameEntry::onValueChanged(const std::string &value) { + if (!myInfoDialog.myAuthorsDone || !isVisible()) { + return; + } + + myEmpty = value.empty(); + if (myEmpty) { + for (std::size_t i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[i]; + if (entry.myEmpty && entry.isVisible() && this != &entry) { + entry.setVisible(false); + } + } + } else { + std::size_t i, lastvisible = (std::size_t) -1; + for (i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[i]; + if (entry.isVisible()) { + lastvisible = i; + if (entry.myEmpty) { + break; + } + } + } + if (i == myInfoDialog.myAuthorEntries.size()) { + if (lastvisible + 1 < i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[lastvisible + 1]; + entry.setVisible(true); + } + // else pool is over + } + } +} + + + + +SeriesTitleEntry::SeriesTitleEntry(BookInfoDialog &dialog) : ZLComboOptionEntry(true), myInfoDialog(dialog) { + const AuthorList &authors = myInfoDialog.myBook->authors(); + myOriginalValuesSet.insert(initialValue()); + myOriginalValuesSet.insert(""); + const Library &library = Library::Instance(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + library.collectSeriesTitles(*it, myOriginalValuesSet); + } +} + +const std::string &SeriesTitleEntry::initialValue() const { + return myInfoDialog.myBook->seriesTitle(); +} + +const std::vector<std::string> &SeriesTitleEntry::values() const { + std::set<std::string> valuesSet(myOriginalValuesSet); + + const Library &library = Library::Instance(); + const AuthorList &authors = myInfoDialog.myBook->authors(); + for (std::vector<AuthorDisplayNameEntry*>::const_iterator it = myInfoDialog.myAuthorEntries.begin(); it != myInfoDialog.myAuthorEntries.end(); ++it) { + shared_ptr<Author> currentAuthor = (*it)->myCurrentAuthor; + if (!currentAuthor.isNull() && std::find(authors.begin(), authors.end(), currentAuthor) == authors.end()) { + library.collectSeriesTitles(currentAuthor, valuesSet); + } + } + + /*myValues.clear(); + for (std::set<std::string>::const_iterator it = valuesSet.begin(); it != valuesSet.end(); ++it) { + myValues.push_back(*it); + }*/ + myValues.assign(valuesSet.begin(), valuesSet.end()); + return myValues; +} + +void SeriesTitleEntry::onAccept(const std::string &value) { + Book &book = *myInfoDialog.myBook; + book.setSeries(value, book.indexInSeries()); +} + +void SeriesTitleEntry::onValueSelected(int index) { + myInfoDialog.myBookIndexEntry->setVisible(index != 0); +} + +bool SeriesTitleEntry::useOnValueEdited() const { + return true; +} + +void SeriesTitleEntry::onValueEdited(const std::string &value) { + myInfoDialog.myBookIndexEntry->setVisible(!value.empty()); +} + +BookIndexEntry::BookIndexEntry(BookInfoDialog &dialog) : myInfoDialog(dialog) { +} + +const std::string &BookIndexEntry::initialValue() const { + return myInfoDialog.myBook->indexInSeries().value(); +} + +void BookIndexEntry::onAccept(const std::string &value) { + Book &book = *myInfoDialog.myBook; + //TODO implement validation + book.setSeries(book.seriesTitle(), Number(value)); +} + +class BookTitleEntry : public ZLStringOptionEntry { + +public: + BookTitleEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookTitleEntry::BookTitleEntry(BookInfoDialog &dialog) : myInfoDialog(dialog) { +} + +const std::string &BookTitleEntry::initialValue() const { + return myInfoDialog.myBook->title(); +} + +void BookTitleEntry::onAccept(const std::string &value) { + myInfoDialog.myBook->setTitle(value); +} + + + + + + +class BookEncodingEntry : public AbstractEncodingEntry { + +public: + BookEncodingEntry(BookInfoDialog &dialog); + + void onAcceptValue(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookEncodingEntry::BookEncodingEntry(BookInfoDialog &dialog) : + AbstractEncodingEntry(dialog.myBook->encoding()), + myInfoDialog(dialog) { +} + +void BookEncodingEntry::onAcceptValue(const std::string &value) { + myInfoDialog.myBook->setEncoding(value); +} + + + +class BookLanguageEntry : public ZLAbstractLanguageOptionEntry { + +public: + BookLanguageEntry(BookInfoDialog &dialog, const std::vector<std::string> &languageCodes); + + void onAcceptCode(const std::string &code); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookLanguageEntry::BookLanguageEntry(BookInfoDialog &dialog, const std::vector<std::string> &languageCodes) : + ZLAbstractLanguageOptionEntry(dialog.myBook->language(), languageCodes), + myInfoDialog(dialog) { +} + +void BookLanguageEntry::onAcceptCode(const std::string &code) { + myInfoDialog.myBook->setLanguage(code); +} + + + + + +class BookTagEntry : public ZLComboOptionEntry { + +public: + BookTagEntry(BookInfoDialog &dialog, std::string initialTag, bool &visible); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + void onValueChanged(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; + std::string myInitialValue; + bool myEmpty; + + mutable std::vector<std::string> myValues; +}; + +BookTagEntry::BookTagEntry(BookInfoDialog &dialog, std::string initialTag, bool &visible) : + ZLComboOptionEntry(true), myInfoDialog(dialog), myInitialValue(initialTag) { + + myEmpty = myInitialValue.empty(); + setVisible(visible || !myEmpty); + if (visible && myEmpty) { + visible = false; + } +} + +const std::string &BookTagEntry::initialValue() const { + return myInitialValue; +} + +const std::vector<std::string> &BookTagEntry::values() const { + if (myValues.empty()) { + myValues.push_back(""); + Tag::collectTagNames(myValues); + } + return myValues; +} + +void BookTagEntry::onAccept(const std::string &value) { + if (isVisible() && !value.empty()) { + myInfoDialog.myNewTags.push_back(value); + } +} + +bool BookTagEntry::useOnValueEdited() const { + return true; +} + +void BookTagEntry::onValueEdited(const std::string &value) { + onValueChanged(value); +} + +void BookTagEntry::onValueSelected(int index) { + onValueChanged(myValues[index]); +} + +void BookTagEntry::onValueChanged(const std::string &value) { + if (!myInfoDialog.myTagsDone || !isVisible()) { + return; + } + + myEmpty = value.empty(); + if (myEmpty) { + for (std::size_t i = 0; i < myInfoDialog.myTagEntries.size(); ++i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[i]; + if (entry.myEmpty && entry.isVisible() && this != &entry) { + entry.setVisible(false); + } + } + } else { + std::size_t i, lastvisible = (std::size_t) -1; + for (i = 0; i < myInfoDialog.myTagEntries.size(); ++i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[i]; + if (entry.isVisible()) { + lastvisible = i; + if (entry.myEmpty) { + break; + } + } + } + if (i == myInfoDialog.myTagEntries.size()) { + if (lastvisible + 1 < i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[lastvisible + 1]; + entry.setVisible(true); + } + } + } +} + +class BookInfoApplyAction : public ZLRunnable { + +public: + BookInfoApplyAction(BookInfoDialog &dialog); + void run(); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookInfoApplyAction::BookInfoApplyAction(BookInfoDialog &dialog) : myInfoDialog(dialog) {} + +void BookInfoApplyAction::run() { + Book &book = *myInfoDialog.myBook; + + AuthorList authors; + for (std::size_t i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + shared_ptr<Author> a = myInfoDialog.myAuthorEntries[i]->myCurrentAuthor; + if (!a.isNull() && + std::find(authors.begin(), authors.end(), a) == authors.end()) { + authors.push_back(a); + } + } + + book.removeAllAuthors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + book.addAuthor(*it); + } + + book.removeAllTags(); + for (std::size_t i = 0; i < myInfoDialog.myNewTags.size(); ++i) { + book.addTag(myInfoDialog.myNewTags[i]); + } + + Library::Instance().updateBook(myInfoDialog.myBook); +} + +BookInfoDialog::BookInfoDialog(shared_ptr<Book> book) : myBook(book) { + myDialog = ZLDialogManager::Instance().createOptionsDialog(ZLResourceKey("InfoDialog"), new BookInfoApplyAction(*this)); + + ZLDialogContent &commonTab = myDialog->createTab(ZLResourceKey("Common")); + commonTab.addOption(ZLResourceKey("file"), + new ZLStringInfoEntry(ZLFile::fileNameToUtf8(book->file().path())) + ); + commonTab.addOption(ZLResourceKey("title"), new BookTitleEntry(*this)); + + myEncodingEntry = new BookEncodingEntry(*this); + myEncodingSetEntry = + (myEncodingEntry->initialValue() != Book::AutoEncoding) ? + new EncodingSetEntry(*(EncodingEntry*)myEncodingEntry) : 0; + std::vector<std::string> languageCodes = ZLLanguageList::languageCodes(); + languageCodes.push_back("de-traditional"); + myLanguageEntry = new BookLanguageEntry(*this, languageCodes); + mySeriesTitleEntry = new SeriesTitleEntry(*this); + myBookIndexEntry = new BookIndexEntry(*this); + + commonTab.addOption(ZLResourceKey("language"), myLanguageEntry); + if (myEncodingSetEntry != 0) { + commonTab.addOption(ZLResourceKey("encodingSet"), myEncodingSetEntry); + } + commonTab.addOption(ZLResourceKey("encoding"), myEncodingEntry); + + initAuthorEntries(); + + ZLDialogContent &seriesTab = myDialog->createTab(ZLResourceKey("Series")); + seriesTab.addOption(ZLResourceKey("seriesTitle"), mySeriesTitleEntry); + seriesTab.addOption(ZLResourceKey("bookIndex"), myBookIndexEntry); + + mySeriesTitleEntry->onValueEdited(mySeriesTitleEntry->initialValue()); + /* + ZLOrderOptionEntry *orderEntry = new ZLOrderOptionEntry(); + orderEntry->values().push_back("First"); + orderEntry->values().push_back("Second"); + orderEntry->values().push_back("Third"); + orderEntry->values().push_back("Fourth"); + orderEntry->values().push_back("Fifth"); + seriesTab.addOption(orderEntry); + */ + + initTagEntries(); + + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(*book); + if (!plugin.isNull()) { + myFormatInfoPage = plugin->createInfoPage(*myDialog, book->file()); + } +} + +void BookInfoDialog::initTagEntries() { + bool visible = true; + const TagList &tags = myBook->tags(); + myTagsDone = false; + myTagsTab = &myDialog->createTab(ZLResourceKey("Tags")); + for (std::size_t i = 0; i < TAG_ENTRIES_POOL_SIZE; ++i) { + std::string tag = (i < tags.size()) ? tags[i]->fullName() : ""; + BookTagEntry *entry = new BookTagEntry(*this, tag, visible); + myTagEntries.push_back(entry); + myTagsTab->addOption(ZLResourceKey("tags"), entry); + } + myTagsDone = true; +} + +void BookInfoDialog::initAuthorEntries() { + bool visible = true; + const AuthorList &authors = myBook->authors(); + myAuthorsDone = false; + myAuthorsTab = &myDialog->createTab(ZLResourceKey("Authors")); + for (std::size_t i = 0; i < AUTHOR_ENTRIES_POOL_SIZE; ++i) { + shared_ptr<Author> author = (i < authors.size()) ? authors[i] : 0; + AuthorDisplayNameEntry *entry = new AuthorDisplayNameEntry(*this, author, visible); + myAuthorEntries.push_back(entry); + myAuthorsTab->addOption(ZLResourceKey("authorDisplayName"), entry); + } + myAuthorsDone = true; +} + diff --git a/reader/src/optionsDialog/bookInfo/BookInfoDialog.h b/reader/src/optionsDialog/bookInfo/BookInfoDialog.h new file mode 100644 index 0000000..a5bb75d --- /dev/null +++ b/reader/src/optionsDialog/bookInfo/BookInfoDialog.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKINFODIALOG_H__ +#define __BOOKINFODIALOG_H__ + +#include <string> + +#include <ZLOptionEntry.h> + +#include "../../formats/FormatPlugin.h" + +class ZLOptionsDialog; +class ZLDialogContent; +class AuthorDisplayNameEntry; +class SeriesTitleEntry; +class BookIndexEntry; +class BookTagEntry; + +class BookInfoDialog { + +public: + BookInfoDialog(shared_ptr<Book> book); + + ZLOptionsDialog &dialog(); + +private: + void initAuthorEntries(); + void initTagEntries(); + +private: + shared_ptr<ZLOptionsDialog> myDialog; + shared_ptr<Book> myBook; + shared_ptr<FormatInfoPage> myFormatInfoPage; + + ZLComboOptionEntry *myEncodingSetEntry; + ZLComboOptionEntry *myEncodingEntry; + ZLComboOptionEntry *myLanguageEntry; + SeriesTitleEntry *mySeriesTitleEntry; + BookIndexEntry *myBookIndexEntry; + + ZLDialogContent *myTagsTab; + std::vector<BookTagEntry *> myTagEntries; + bool myTagsDone; + + std::vector<std::string> myNewTags; + + ZLDialogContent *myAuthorsTab; + std::vector<AuthorDisplayNameEntry *> myAuthorEntries; + bool myAuthorsDone; + +friend class AuthorDisplayNameEntry; +friend class SeriesTitleEntry; +friend class BookIndexEntry; +friend class BookTitleEntry; +friend class BookEncodingEntry; +friend class BookLanguageEntry; +friend class BookTagEntry; +friend class BookInfoApplyAction; +}; + +inline ZLOptionsDialog &BookInfoDialog::dialog() { return *myDialog; } + +#endif /* __BOOKINFODIALOG_H__ */ diff --git a/reader/src/optionsDialog/library/LibraryOptionsDialog.cpp b/reader/src/optionsDialog/library/LibraryOptionsDialog.cpp new file mode 100644 index 0000000..b2168d3 --- /dev/null +++ b/reader/src/optionsDialog/library/LibraryOptionsDialog.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "LibraryOptionsDialog.h" + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> + +#include "../../reader/Reader.h" + +#include "../../network/NetworkLinkCollection.h" + + +LibraryOptionsDialog::LibraryOptionsDialog() : AbstractOptionsDialog(ZLResourceKey("LibraryOptionsDialog"), true) { + + ZLDialogContent &libraryTab = dialog().createTab(ZLResourceKey("Library")); + + Library &library = Library::Instance(); + libraryTab.addOption(ZLResourceKey("bookPath"), library.PathOption); + libraryTab.addOption(ZLResourceKey("lookInSubdirectories"), library.ScanSubdirsOption); + libraryTab.addOption(ZLResourceKey("collectBooksWithoutMetaInfo"), library.CollectAllBooksOption); + libraryTab.addOption(ZLResourceKey("downloadDirectory"), NetworkLinkCollection::Instance().DirectoryOption); +} diff --git a/reader/src/optionsDialog/library/LibraryOptionsDialog.h b/reader/src/optionsDialog/library/LibraryOptionsDialog.h new file mode 100644 index 0000000..da217f6 --- /dev/null +++ b/reader/src/optionsDialog/library/LibraryOptionsDialog.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LIBRARYOPTIONSDIALOG_H__ +#define __LIBRARYOPTIONSDIALOG_H__ + +#include "../AbstractOptionsDialog.h" + + +class LibraryOptionsDialog : public AbstractOptionsDialog { + +public: + LibraryOptionsDialog(); +}; + +#endif /* __LIBRARYOPTIONSDIALOG_H__ */ diff --git a/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.cpp b/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.cpp new file mode 100644 index 0000000..0b77548 --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> + +#include <ZLSimpleOptionEntry.h> + +#include <ZLTextStyle.h> +#include <ZLTextStyleCollection.h> +#include <ZLTextStyleOptions.h> + +#include "FormatOptionsPage.h" + +#include "../../options/FBTextStyle.h" +#include "../../bookmodel/FBTextKind.h" + +static const ZLResourceKey KEY_STYLE("style"); +static const ZLResourceKey KEY_BASE("Base"); + +static const ZLResourceKey KEY_DUMMY(""); +static const ZLResourceKey KEY_LINESPACING("lineSpacing"); +static const ZLResourceKey KEY_FIRSTLINEINDENT("firstLineIndent"); +static const ZLResourceKey KEY_ALIGNMENT("alignment"); +static const ZLResourceKey KEY_SPACEBEFORE("spaceBefore"); +static const ZLResourceKey KEY_SPACEAFTER("spaceAfter"); +static const ZLResourceKey KEY_STARTINDENT("startIndent"); +static const ZLResourceKey KEY_ENDINDENT("endIndent"); + +FormatOptionsPage::FormatOptionsPage(ZLDialogContent &dialogTab) { + const ZLResource &styleResource = ZLResource::resource(KEY_STYLE); + + myComboEntry = new ComboOptionEntry(*this, styleResource[KEY_BASE].value()); + myComboEntry->addValue(myComboEntry->initialValue()); + + ZLTextStyleCollection &collection = ZLTextStyleCollection::Instance(); + ZLTextKind styles[] = { REGULAR, TITLE, SECTION_TITLE, SUBTITLE, H1, H2, H3, H4, H5, H6, ANNOTATION, EPIGRAPH, PREFORMATTED, AUTHOR, DATEKIND, POEM_TITLE, STANZA, VERSE }; + const int STYLES_NUMBER = sizeof(styles) / sizeof(ZLTextKind); + for (int i = 0; i < STYLES_NUMBER; ++i) { + const ZLTextStyleDecoration *decoration = collection.decoration(styles[i]); + if (decoration != 0) { + myComboEntry->addValue(styleResource[decoration->name()].value()); + } + } + dialogTab.addOption(ZLResourceKey("optionsFor"), myComboEntry); + + { + const std::string &name = myComboEntry->initialValue(); + FBTextStyle &baseStyle = FBTextStyle::Instance(); + + registerEntries(dialogTab, + KEY_LINESPACING, new ZLTextLineSpaceOptionEntry(baseStyle.LineSpacePercentOption, dialogTab.resource(KEY_LINESPACING), false), + KEY_DUMMY, 0,//new ZLSimpleSpinOptionEntry("First Line Indent", baseStyle.firstLineIndentDeltaOption(), -300, 300, 1), + name + ); + + registerEntries(dialogTab, + KEY_ALIGNMENT, new ZLTextAlignmentOptionEntry(baseStyle.AlignmentOption, dialogTab.resource(KEY_ALIGNMENT), false), + KEY_DUMMY, 0, + name + ); + } + + for (int i = 0; i < STYLES_NUMBER; ++i) { + ZLTextStyleDecoration *d = collection.decoration(styles[i]); + if ((d != 0) && (d->isFullDecoration())) { + ZLTextFullStyleDecoration *decoration = (ZLTextFullStyleDecoration*)d; + const std::string &name = styleResource[decoration->name()].value(); + + registerEntries(dialogTab, + KEY_SPACEBEFORE, new ZLSimpleSpinOptionEntry(decoration->SpaceBeforeOption, 1), + KEY_STARTINDENT, new ZLSimpleSpinOptionEntry(decoration->LineStartIndentOption, 1), + name + ); + + registerEntries(dialogTab, + KEY_SPACEAFTER, new ZLSimpleSpinOptionEntry(decoration->SpaceAfterOption, 1), + KEY_ENDINDENT, new ZLSimpleSpinOptionEntry(decoration->LineEndIndentOption, 1), + name + ); + + registerEntries(dialogTab, + KEY_LINESPACING, new ZLTextLineSpaceOptionEntry(decoration->LineSpacePercentOption, dialogTab.resource(KEY_LINESPACING), true), + KEY_FIRSTLINEINDENT, new ZLSimpleSpinOptionEntry(decoration->FirstLineIndentDeltaOption, 1), + name + ); + + registerEntries(dialogTab, + KEY_ALIGNMENT, new ZLTextAlignmentOptionEntry(decoration->AlignmentOption, dialogTab.resource(KEY_ALIGNMENT), true), + KEY_DUMMY, 0, + name + ); + } + } + + myComboEntry->onValueSelected(0); +} diff --git a/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.h b/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.h new file mode 100644 index 0000000..81aa33a --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/FormatOptionsPage.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FORMATOPTIONSPAGE_H__ +#define __FORMATOPTIONSPAGE_H__ + +#include "OptionsPage.h" + +class ZLDialogContent; + +class FormatOptionsPage : public OptionsPage { + +public: + FormatOptionsPage(ZLDialogContent &dialogTab); +}; + +#endif /* __FORMATOPTIONSPAGE_H__ */ diff --git a/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.cpp b/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.cpp new file mode 100644 index 0000000..ca740c6 --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLPaintContext.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLColorOptionBuilder.h> + +#include <ZLTextStyleCollection.h> + +#include "LookAndFeelOptionsDialog.h" + +#include "FormatOptionsPage.h" +#include "StyleOptionsPage.h" + +#include "../../reader/Reader.h" +#include "../../reader/FBView.h" +#include "../../options/FBOptions.h" + + +LookAndFeelOptionsDialog::LookAndFeelOptionsDialog() : AbstractOptionsDialog(ZLResourceKey("LookAndFeelOptionsDialog"), true) { + Reader &reader = Reader::Instance(); + FBOptions &options = FBOptions::Instance(); + + ZLOptionsDialog &dialog = this->dialog(); + + ZLDialogContent &cssTab = dialog.createTab(ZLResourceKey("CSS")); + cssTab.addOption(ZLResourceKey("overrideSpecifiedFonts"), ZLTextStyleCollection::Instance().OverrideSpecifiedFontsOption); + + ZLDialogContent &marginTab = dialog.createTab(ZLResourceKey("Margins")); + marginTab.addOptions( + ZLResourceKey("left"), new ZLSimpleSpinOptionEntry(options.LeftMarginOption, 1), + ZLResourceKey("right"), new ZLSimpleSpinOptionEntry(options.RightMarginOption, 1) + ); + marginTab.addOptions( + ZLResourceKey("top"), new ZLSimpleSpinOptionEntry(options.TopMarginOption, 1), + ZLResourceKey("bottom"), new ZLSimpleSpinOptionEntry(options.BottomMarginOption, 1) + ); + + myFormatPage = new FormatOptionsPage(dialog.createTab(ZLResourceKey("Format"))); + myStylePage = new StyleOptionsPage(dialog.createTab(ZLResourceKey("Styles")), *reader.context()); + + ZLDialogContent &colorsTab = dialog.createTab(ZLResourceKey("Colors")); + ZLResourceKey colorKey("colorFor"); + const ZLResource &resource = colorsTab.resource(colorKey); + ZLColorOptionBuilder builder; + const std::string BACKGROUND = resource["background"].value(); + builder.addOption(BACKGROUND, options.BackgroundColorOption); + builder.addOption(resource["selectionBackground"].value(), options.colorOption(ZLTextStyle::SELECTION_BACKGROUND)); + builder.addOption(resource["text"].value(), options.RegularTextColorOption); + builder.addOption(resource["internalLink"].value(), options.colorOption("internal")); + builder.addOption(resource["externalLink"].value(), options.colorOption("external")); + builder.addOption(resource["bookLink"].value(), options.colorOption("book")); + builder.addOption(resource["highlighted"].value(), options.colorOption(ZLTextStyle::HIGHLIGHTED_TEXT)); + builder.addOption(resource["treeLines"].value(), options.colorOption(ZLTextStyle::TREE_LINES)); + builder.addOption(resource["indicator"].value(), (FBView::commonIndicatorInfo().ColorOption)); + builder.setInitial(BACKGROUND); + colorsTab.addOption(colorKey, builder.comboEntry()); + colorsTab.addOption("", "", builder.colorEntry()); +} diff --git a/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.h b/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.h new file mode 100644 index 0000000..b908285 --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __LOOKANDFEELOPTIONSDIALOG_H__ +#define __LOOKANDFEELOPTIONSDIALOG_H__ + +#include "../AbstractOptionsDialog.h" + +class OptionsPage; + + +class LookAndFeelOptionsDialog : public AbstractOptionsDialog { + +public: + LookAndFeelOptionsDialog(); + +private: + shared_ptr<OptionsPage> myFormatPage; + shared_ptr<OptionsPage> myStylePage; +}; + +#endif /* __LOOKANDFEELOPTIONSDIALOG_H__ */ diff --git a/reader/src/optionsDialog/lookAndFeel/OptionsPage.cpp b/reader/src/optionsDialog/lookAndFeel/OptionsPage.cpp new file mode 100644 index 0000000..55a6970 --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/OptionsPage.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> + +#include "OptionsPage.h" + +void ComboOptionEntry::onValueSelected(int index) { + const std::string &selectedValue = values()[index]; + const std::map<ZLOptionEntry*,std::string> &entries = myPage.myEntries; + int count = 0; + for (std::map<ZLOptionEntry*,std::string>::const_iterator it = entries.begin(); it != entries.end(); ++it, ++count) { + it->first->setVisible(it->second == selectedValue); + } +} + +void OptionsPage::registerEntry(ZLDialogContent &tab, const ZLResourceKey &entryKey, ZLOptionEntry *entry, const std::string &name) { + if (entry != 0) { + entry->setVisible(false); + myEntries[entry] = name; + } + tab.addOption(entryKey, entry); +} + +void OptionsPage::registerEntries(ZLDialogContent &tab, const ZLResourceKey &entry0Key, ZLOptionEntry *entry0, const ZLResourceKey &entry1Key, ZLOptionEntry *entry1, const std::string &name) { + if (entry0 != 0) { + entry0->setVisible(false); + myEntries[entry0] = name; + } + if (entry1 != 0) { + entry1->setVisible(false); + myEntries[entry1] = name; + } + tab.addOptions(entry0Key, entry0, entry1Key, entry1); +} diff --git a/reader/src/optionsDialog/lookAndFeel/OptionsPage.h b/reader/src/optionsDialog/lookAndFeel/OptionsPage.h new file mode 100644 index 0000000..a175c2b --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/OptionsPage.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __OPTIONSPAGE_H__ +#define __OPTIONSPAGE_H__ + +#include <map> + +#include <ZLOptionEntry.h> + +class ZLDialogContent; + +class OptionsPage; + +class ComboOptionEntry : public ZLComboOptionEntry { + +public: + ComboOptionEntry(OptionsPage &page, const std::string &initialValue); + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string&); + void onValueSelected(int index); + void addValue(const std::string &value); + +protected: + OptionsPage &myPage; + std::vector<std::string> myValues; + std::string myInitialValue; +}; + +class OptionsPage { + +public: + virtual ~OptionsPage(); + +protected: + OptionsPage(); + + void registerEntry(ZLDialogContent &tab, const ZLResourceKey &entryKey, ZLOptionEntry *entry, const std::string &name); + void registerEntries(ZLDialogContent &tab, const ZLResourceKey &entry0Key, ZLOptionEntry *entry0, const ZLResourceKey &entry1Key, ZLOptionEntry *entry1, const std::string &name); + +protected: + ComboOptionEntry *myComboEntry; + +private: + std::map<ZLOptionEntry*,std::string> myEntries; + +friend class ComboOptionEntry; +}; + +inline ComboOptionEntry::ComboOptionEntry(OptionsPage &page, const std::string &initialValue) : myPage(page), myInitialValue(initialValue) {} +inline const std::string &ComboOptionEntry::initialValue() const { return myInitialValue; } +inline const std::vector<std::string> &ComboOptionEntry::values() const { return myValues; } +inline void ComboOptionEntry::onAccept(const std::string&) {} +inline void ComboOptionEntry::addValue(const std::string &value) { myValues.push_back(value); } + +inline OptionsPage::OptionsPage() {} +inline OptionsPage::~OptionsPage() {} + +#endif /* __OPTIONSPAGE_H__ */ diff --git a/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.cpp b/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.cpp new file mode 100644 index 0000000..c2086d1 --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> +#include <ZLPaintContext.h> + +#include <ZLSimpleOptionEntry.h> + +#include <ZLTextView.h> +#include <ZLTextStyle.h> +#include <ZLTextStyleCollection.h> +#include <ZLTextStyleOptions.h> + +#include "StyleOptionsPage.h" + +#include "../../options/FBTextStyle.h" +#include "../../bookmodel/FBTextKind.h" + +static const ZLResourceKey KEY_STYLE("style"); +static const ZLResourceKey KEY_BASE("Base"); + +static const ZLResourceKey KEY_BOLD("bold"); +static const ZLResourceKey KEY_ITALIC("italic"); +static const ZLResourceKey KEY_FONTFAMILY("fontFamily"); +static const ZLResourceKey KEY_FONTSIZE("fontSize"); +static const ZLResourceKey KEY_FONTSIZEDIFFERENCE("fontSizeDifference"); +static const ZLResourceKey KEY_ALLOWHYPHENATIONS("allowHyphenations"); +static const ZLResourceKey KEY_AUTOHYPHENATIONS("autoHyphenations"); +static const ZLResourceKey KEY_DUMMY(""); + +StyleOptionsPage::StyleOptionsPage(ZLDialogContent &dialogTab, ZLPaintContext &context) { + const ZLResource &styleResource = ZLResource::resource(KEY_STYLE); + + myComboEntry = new ComboOptionEntry(*this, styleResource[KEY_BASE].value()); + myComboEntry->addValue(myComboEntry->initialValue()); + + ZLTextStyleCollection &collection = ZLTextStyleCollection::Instance(); + ZLTextKind styles[] = { REGULAR, TITLE, SECTION_TITLE, SUBTITLE, H1, H2, H3, H4, H5, H6, CONTENTS_TABLE_ENTRY, LIBRARY_ENTRY, ANNOTATION, EPIGRAPH, AUTHOR, DATEKIND, POEM_TITLE, STANZA, VERSE, CITE, INTERNAL_HYPERLINK, EXTERNAL_HYPERLINK, BOOK_HYPERLINK, FOOTNOTE, ITALIC, EMPHASIS, BOLD, STRONG, DEFINITION, DEFINITION_DESCRIPTION, PREFORMATTED, CODE }; + const int STYLES_NUMBER = sizeof(styles) / sizeof(ZLTextKind); + for (int i = 0; i < STYLES_NUMBER; ++i) { + const ZLTextStyleDecoration *decoration = collection.decoration(styles[i]); + if (decoration != 0) { + myComboEntry->addValue(styleResource[decoration->name()].value()); + } + } + dialogTab.addOption(ZLResourceKey("optionsFor"), myComboEntry); + + { + const std::string &name = myComboEntry->initialValue(); + FBTextStyle &baseStyle = FBTextStyle::Instance(); + + registerEntry(dialogTab, + KEY_FONTFAMILY, new ZLFontFamilyOptionEntry(baseStyle.FontFamilyOption, context), + name + ); + + registerEntry(dialogTab, + KEY_FONTSIZE, new ZLSimpleSpinOptionEntry(baseStyle.FontSizeOption, 2), + name + ); + + registerEntry(dialogTab, + KEY_BOLD, new ZLSimpleBooleanOptionEntry(baseStyle.BoldOption), + name + ); + + registerEntry(dialogTab, + KEY_ITALIC, new ZLSimpleBooleanOptionEntry(baseStyle.ItalicOption), + name + ); + + registerEntry(dialogTab, + KEY_AUTOHYPHENATIONS, new ZLSimpleBooleanOptionEntry(collection.AutoHyphenationOption), + name + ); + } + + for (int i = 0; i < STYLES_NUMBER; ++i) { + ZLTextStyleDecoration *decoration = collection.decoration(styles[i]); + if (decoration != 0) { + const std::string &name = styleResource[decoration->name()].value(); + + registerEntry(dialogTab, + KEY_FONTFAMILY, new ZLTextFontFamilyWithBaseOptionEntry(decoration->FontFamilyOption, dialogTab.resource(KEY_FONTFAMILY), context), + name + ); + + registerEntry(dialogTab, + KEY_FONTSIZEDIFFERENCE, new ZLSimpleSpinOptionEntry(decoration->FontSizeDeltaOption, 2), + name + ); + + registerEntry(dialogTab, + KEY_BOLD, new ZLSimpleBoolean3OptionEntry(decoration->BoldOption), + name + ); + + registerEntry(dialogTab, + KEY_ITALIC, new ZLSimpleBoolean3OptionEntry(decoration->ItalicOption), + name + ); + + registerEntry(dialogTab, + KEY_ALLOWHYPHENATIONS, new ZLSimpleBoolean3OptionEntry(decoration->AllowHyphenationsOption), + name + ); + } + } + + myComboEntry->onValueSelected(0); +} diff --git a/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.h b/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.h new file mode 100644 index 0000000..c61709d --- /dev/null +++ b/reader/src/optionsDialog/lookAndFeel/StyleOptionsPage.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __STYLEOPTIONSPAGE_H__ +#define __STYLEOPTIONSPAGE_H__ + +#include "OptionsPage.h" + +class ZLDialogContent; +class ZLPaintContext; + +class StyleOptionsPage : public OptionsPage { + +public: + StyleOptionsPage(ZLDialogContent &dialogTab, ZLPaintContext &context); +}; + +#endif /* __STYLEOPTIONSPAGE_H__ */ diff --git a/reader/src/optionsDialog/network/NetworkOptionsDialog.cpp b/reader/src/optionsDialog/network/NetworkOptionsDialog.cpp new file mode 100644 index 0000000..5c39131 --- /dev/null +++ b/reader/src/optionsDialog/network/NetworkOptionsDialog.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "NetworkOptionsDialog.h" + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLStringUtil.h> + +#include <ZLOptionEntry.h> +#include <ZLOptionsDialog.h> +#include <ZLNetworkManager.h> +#include <ZLSimpleOptionEntry.h> +#include <ZLToggleBooleanOptionEntry.h> + +#include "../../reader/Reader.h" + +//#include "../../network/NetworkLinkCollection.h" +//#include "../../network/NetworkLink.h" +#include "../../network/UserList.h" + + +class NetworkLinkBooleanOptionEntry : public ZLBooleanOptionEntry { + +public: + NetworkLinkBooleanOptionEntry(ZLBooleanOption &option); + bool initialState() const; + void onAccept(bool state); + +private: + ZLBooleanOption &myOption; +}; + +NetworkLinkBooleanOptionEntry::NetworkLinkBooleanOptionEntry(ZLBooleanOption &option) : myOption(option) { +} + +bool NetworkLinkBooleanOptionEntry::initialState() const { + return myOption.value(); +} + +void NetworkLinkBooleanOptionEntry::onAccept(bool state) { + bool oldState = myOption.value(); + myOption.setValue(state); + if (state != oldState) { +// Reader::Instance().invalidateNetworkView(); + } +} + + + +NetworkOptionsDialog::NetworkOptionsDialog() : AbstractOptionsDialog(ZLResourceKey("NetworkOptionsDialog"), true) { + Reader &reader = Reader::Instance(); + + ZLDialogContent &connectionTab = dialog().createTab(ZLResourceKey("Connection")); + + ZLNetworkManager &networkManager = ZLNetworkManager::Instance(); + connectionTab.addOption(ZLResourceKey("timeout"), new ZLSimpleSpinOptionEntry(networkManager.TimeoutOption(), 5)); + if (!networkManager.providesProxyInfo()) { + ZLToggleBooleanOptionEntry *useProxyEntry = new ZLToggleBooleanOptionEntry(networkManager.UseProxyOption()); + connectionTab.addOption(ZLResourceKey("useProxy"), useProxyEntry); + ZLSimpleStringOptionEntry *proxyHostEntry = new ZLSimpleStringOptionEntry(networkManager.ProxyHostOption()); + connectionTab.addOption(ZLResourceKey("proxyHost"), proxyHostEntry); + ZLSimpleStringOptionEntry *proxyPortEntry = new ZLSimpleStringOptionEntry(networkManager.ProxyPortOption()); + connectionTab.addOption(ZLResourceKey("proxyPort"), proxyPortEntry); + useProxyEntry->addDependentEntry(proxyHostEntry); + useProxyEntry->addDependentEntry(proxyPortEntry); + useProxyEntry->onStateChanged(useProxyEntry->initialState()); + } + +// ZLDialogContent &libraryTab = dialog().createTab(ZLResourceKey("NetworkLibrary")); + +// NetworkLinkCollection &linkCollection = NetworkLinkCollection::Instance(); +// const std::size_t linkCollectionSize = linkCollection.size(); +// const std::size_t linkCollectionSizeMinusOne = linkCollectionSize - 1; +// for (std::size_t i = 0; i < linkCollectionSize; ++i) { +// NetworkLink &link = linkCollection.link(i); +// if (i < linkCollectionSizeMinusOne) { +// NetworkLink &link2 = linkCollection.link(++i); +// libraryTab.addOptions(link.SiteName, "", new NetworkLinkBooleanOptionEntry(link.OnOption), +// link2.SiteName, "", new NetworkLinkBooleanOptionEntry(link2.OnOption)); +// } else { +// libraryTab.addOption(link.SiteName, "", new NetworkLinkBooleanOptionEntry(link.OnOption)); +// } +// } + + std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> > additional; + createIntegrationTab(reader.webBrowserCollection(), ZLResourceKey("Web"), additional); +} diff --git a/reader/src/optionsDialog/network/NetworkOptionsDialog.h b/reader/src/optionsDialog/network/NetworkOptionsDialog.h new file mode 100644 index 0000000..3c6ca32 --- /dev/null +++ b/reader/src/optionsDialog/network/NetworkOptionsDialog.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __NETWORKOPTIONSDIALOG_H__ +#define __NETWORKOPTIONSDIALOG_H__ + +#include "../AbstractOptionsDialog.h" + + +class NetworkOptionsDialog : public AbstractOptionsDialog { + +public: + NetworkOptionsDialog(); +}; + +#endif /* __NETWORKOPTIONSDIALOG_H__ */ diff --git a/reader/src/optionsDialog/reading/IndicatorTab.cpp b/reader/src/optionsDialog/reading/IndicatorTab.cpp new file mode 100644 index 0000000..6d288c6 --- /dev/null +++ b/reader/src/optionsDialog/reading/IndicatorTab.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> + +#include <ZLToggleBooleanOptionEntry.h> + +#include <ZLTextStyleOptions.h> + +#include "ReadingOptionsDialog.h" + +#include "../../reader/Reader.h" +#include "../../reader/FBView.h" +#include "../../reader/BookTextView.h" + +class StateOptionEntry : public ZLToggleBooleanOptionEntry { + +public: + StateOptionEntry(ZLBooleanOption &option); + void onStateChanged(bool state); + +private: + bool myState; + +friend class SpecialFontSizeEntry; +}; + +class SpecialFontSizeEntry : public ZLSimpleSpinOptionEntry { + +public: + SpecialFontSizeEntry(ZLIntegerRangeOption &option, int step, StateOptionEntry &first, StateOptionEntry &second); + void setVisible(bool state); + +private: + StateOptionEntry &myFirst; + StateOptionEntry &mySecond; +}; + +StateOptionEntry::StateOptionEntry(ZLBooleanOption &option) : ZLToggleBooleanOptionEntry(option) { + myState = option.value(); +} + +void StateOptionEntry::onStateChanged(bool state) { + myState = state; + ZLToggleBooleanOptionEntry::onStateChanged(state); +} + +SpecialFontSizeEntry::SpecialFontSizeEntry(ZLIntegerRangeOption &option, int step, StateOptionEntry &first, StateOptionEntry &second) : ZLSimpleSpinOptionEntry(option, step), myFirst(first), mySecond(second) { +} + +void SpecialFontSizeEntry::setVisible(bool) { + ZLSimpleSpinOptionEntry::setVisible( + (myFirst.isVisible() && myFirst.myState) || + (mySecond.isVisible() && mySecond.myState) + ); +} + +class IndicatorTypeEntry : public ZLComboOptionEntry { + +public: + IndicatorTypeEntry(const ZLResource &resource, ZLIntegerRangeOption &typeOption); + void addDependentEntry(ZLOptionEntry *entry); + const std::string &initialValue() const; + +private: + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + void onValueSelected(int index); + +private: + ZLIntegerRangeOption &myOption; + std::vector<std::string> myValues; + std::vector<ZLOptionEntry*> myDependentEntries; +}; + +IndicatorTypeEntry::IndicatorTypeEntry(const ZLResource &resource, ZLIntegerRangeOption &typeOption) : myOption(typeOption) { + myValues.push_back(resource["osScrollbar"].value()); + myValues.push_back(resource["fbIndicator"].value()); + myValues.push_back(resource["none"].value()); +} + +const std::string &IndicatorTypeEntry::initialValue() const { + return myValues[myOption.value()]; +} + +const std::vector<std::string> &IndicatorTypeEntry::values() const { + return myValues; +} + +void IndicatorTypeEntry::addDependentEntry(ZLOptionEntry *entry) { + myDependentEntries.push_back(entry); +} + +void IndicatorTypeEntry::onAccept(const std::string &value) { + for (std::size_t index = 0; index != myValues.size(); ++index) { + if (myValues[index] == value) { + myOption.setValue(index); + break; + } + } +} + +void IndicatorTypeEntry::onValueSelected(int index) { + for (std::vector<ZLOptionEntry*>::iterator it = myDependentEntries.begin(); it != myDependentEntries.end(); ++it) { + (*it)->setVisible(index == FBIndicatorStyle::FB_INDICATOR); + } +} + +void ReadingOptionsDialog::createIndicatorTab() { + ZLDialogContent &indicatorTab = dialog().createTab(ZLResourceKey("Indicator")); + FBIndicatorStyle &indicatorInfo = FBView::commonIndicatorInfo(); + static ZLResourceKey typeKey("type"); + IndicatorTypeEntry *indicatorTypeEntry = + new IndicatorTypeEntry(indicatorTab.resource(typeKey), indicatorInfo.TypeOption); + indicatorTab.addOption(typeKey, indicatorTypeEntry); + + ZLOptionEntry *heightEntry = + new ZLSimpleSpinOptionEntry(indicatorInfo.HeightOption, 1); + ZLOptionEntry *offsetEntry = + new ZLSimpleSpinOptionEntry(indicatorInfo.OffsetOption, 1); + indicatorTab.addOptions(ZLResourceKey("height"), heightEntry, ZLResourceKey("offset"), offsetEntry); + indicatorTypeEntry->addDependentEntry(heightEntry); + indicatorTypeEntry->addDependentEntry(offsetEntry); + + StateOptionEntry *showTextPositionEntry = + new StateOptionEntry(indicatorInfo.ShowTextPositionOption); + indicatorTab.addOption(ZLResourceKey("pageNumber"), showTextPositionEntry); + indicatorTypeEntry->addDependentEntry(showTextPositionEntry); + + StateOptionEntry *showTimeEntry = + new StateOptionEntry(indicatorInfo.ShowTimeOption); + indicatorTab.addOption(ZLResourceKey("time"), showTimeEntry); + indicatorTypeEntry->addDependentEntry(showTimeEntry); + + SpecialFontSizeEntry *fontSizeEntry = + new SpecialFontSizeEntry(indicatorInfo.FontSizeOption, 2, *showTextPositionEntry, *showTimeEntry); + indicatorTab.addOption(ZLResourceKey("fontSize"), fontSizeEntry); + indicatorTypeEntry->addDependentEntry(fontSizeEntry); + showTextPositionEntry->addDependentEntry(fontSizeEntry); + showTimeEntry->addDependentEntry(fontSizeEntry); + + ZLOptionEntry *tocMarksEntry = + new ZLSimpleBooleanOptionEntry(Reader::Instance().bookTextView().ShowTOCMarksOption); + indicatorTab.addOption(ZLResourceKey("tocMarks"), tocMarksEntry); + indicatorTypeEntry->addDependentEntry(tocMarksEntry); + + ZLOptionEntry *navigationEntry = + new ZLSimpleBooleanOptionEntry(indicatorInfo.IsSensitiveOption); + indicatorTab.addOption(ZLResourceKey("navigation"), navigationEntry); + indicatorTypeEntry->addDependentEntry(navigationEntry); + + indicatorTypeEntry->onStringValueSelected(indicatorTypeEntry->initialValue()); + showTextPositionEntry->onStateChanged(showTextPositionEntry->initialState()); + showTimeEntry->onStateChanged(showTimeEntry->initialState()); +} diff --git a/reader/src/optionsDialog/reading/KeyBindingsTab.cpp b/reader/src/optionsDialog/reading/KeyBindingsTab.cpp new file mode 100644 index 0000000..f72023b --- /dev/null +++ b/reader/src/optionsDialog/reading/KeyBindingsTab.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptionsDialog.h> +#include <ZLApplication.h> +#include <ZLOptionEntry.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLSimpleKeyOptionEntry.h> + +#include "ReadingOptionsDialog.h" + +#include "../../reader/Reader.h" +#include "../../reader/ReaderActions.h" + +class KeyboardControlEntry : public ZLSimpleBooleanOptionEntry { + +public: + KeyboardControlEntry(); + void onStateChanged(bool state); +}; + +KeyboardControlEntry::KeyboardControlEntry() : ZLSimpleBooleanOptionEntry(Reader::Instance().KeyboardControlOption) { +} + +void KeyboardControlEntry::onStateChanged(bool state) { + ZLSimpleBooleanOptionEntry::onStateChanged(state); + Reader::Instance().grabAllKeys(state); +} + +class SingleKeyOptionEntry : public ZLSimpleKeyOptionEntry { + +public: + SingleKeyOptionEntry(const CodeIndexBimap &bimap, ZLKeyBindings &bindings); + const CodeIndexBimap &codeIndexBimap() const; + +private: + const CodeIndexBimap &myBimap; +}; + +SingleKeyOptionEntry::SingleKeyOptionEntry(const CodeIndexBimap &bimap, ZLKeyBindings &bindings) : ZLSimpleKeyOptionEntry(bindings), myBimap(bimap) { +} + +const ZLSimpleKeyOptionEntry::CodeIndexBimap &SingleKeyOptionEntry::codeIndexBimap() const { + return myBimap; +} + +class MultiKeyOptionEntry : public ZLKeyOptionEntry { + +public: + MultiKeyOptionEntry(const ZLResource &resource); + void onAccept(); + int actionIndex(const std::string &key); + void onValueChanged(const std::string &key, int index); + void onKeySelected(const std::string &key); + + void setOrientation(ZLView::Angle); + void setExitOnCancelEntry(ZLOptionEntry *exitOnCancelEntry); + +private: + void addAction(const std::string &actionId); + +private: + const ZLResource &myResource; + ZLSimpleKeyOptionEntry::CodeIndexBimap myBimap; + + SingleKeyOptionEntry myEntry0; + SingleKeyOptionEntry myEntry90; + SingleKeyOptionEntry myEntry180; + SingleKeyOptionEntry myEntry270; + SingleKeyOptionEntry *myCurrentEntry; + ZLOptionEntry *myExitOnCancelEntry; +}; + +void MultiKeyOptionEntry::addAction(const std::string &actionId) { + myBimap.insert(actionId); + addActionName(myResource[ZLResourceKey(actionId)].value()); +} + +MultiKeyOptionEntry::MultiKeyOptionEntry(const ZLResource &resource) : + ZLKeyOptionEntry(), + myResource(resource), + myEntry0(myBimap, *Reader::Instance().keyBindings(ZLView::DEGREES0)), + myEntry90(myBimap, *Reader::Instance().keyBindings(ZLView::DEGREES90)), + myEntry180(myBimap, *Reader::Instance().keyBindings(ZLView::DEGREES180)), + myEntry270(myBimap, *Reader::Instance().keyBindings(ZLView::DEGREES270)), + myCurrentEntry(&myEntry0), + myExitOnCancelEntry(0) { + addAction(ZLApplication::NoAction); + + // switch view + addAction(ActionCode::SHOW_LIBRARY); + addAction(ActionCode::OPEN_PREVIOUS_BOOK); + addAction(ActionCode::SHOW_TOC); + + // navigation + addAction(ActionCode::SCROLL_TO_HOME); + addAction(ActionCode::SCROLL_TO_START_OF_TEXT); + addAction(ActionCode::SCROLL_TO_END_OF_TEXT); + addAction(ActionCode::GOTO_NEXT_TOC_SECTION); + addAction(ActionCode::GOTO_PREVIOUS_TOC_SECTION); + addAction(ActionCode::PAGE_SCROLL_FORWARD); + addAction(ActionCode::PAGE_SCROLL_BACKWARD); + addAction(ActionCode::LINE_SCROLL_FORWARD); + addAction(ActionCode::LINE_SCROLL_BACKWARD); + addAction(ActionCode::UNDO); + addAction(ActionCode::REDO); + + // selection + addAction(ActionCode::COPY_SELECTED_TEXT_TO_CLIPBOARD); + addAction(ActionCode::OPEN_SELECTED_TEXT_IN_DICTIONARY); + addAction(ActionCode::CLEAR_SELECTION); + + // search + addAction(ActionCode::SEARCH); + addAction(ActionCode::FIND_PREVIOUS); + addAction(ActionCode::FIND_NEXT); + + // look + addAction(ActionCode::INCREASE_FONT); + addAction(ActionCode::DECREASE_FONT); + addAction(ActionCode::SHOW_HIDE_POSITION_INDICATOR); + addAction(ActionCode::TOGGLE_FULLSCREEN); + addAction(ActionCode::ROTATE_SCREEN); + + // dialogs + addAction(ActionCode::SHOW_OPTIONS_DIALOG); + addAction(ActionCode::SHOW_BOOK_INFO_DIALOG); + addAction(ActionCode::ADD_BOOK); + + // quit + addAction(ActionCode::CANCEL); + addAction(ActionCode::QUIT); +} + +void MultiKeyOptionEntry::setOrientation(ZLView::Angle angle) { + switch (angle) { + case ZLView::DEGREES0: + myCurrentEntry = &myEntry0; + break; + case ZLView::DEGREES90: + myCurrentEntry = &myEntry90; + break; + case ZLView::DEGREES180: + myCurrentEntry = &myEntry180; + break; + case ZLView::DEGREES270: + myCurrentEntry = &myEntry270; + break; + } + resetView(); +} + +void MultiKeyOptionEntry::onAccept() { + myEntry0.onAccept(); + myEntry90.onAccept(); + myEntry180.onAccept(); + myEntry270.onAccept(); +} + +int MultiKeyOptionEntry::actionIndex(const std::string &key) { + return myCurrentEntry->actionIndex(key); +} + +void MultiKeyOptionEntry::onValueChanged(const std::string &key, int index) { + myCurrentEntry->onValueChanged(key, index); + if (myExitOnCancelEntry != 0) { + myExitOnCancelEntry->setVisible(myBimap.codeByIndex(index) == ActionCode::CANCEL); + } +} + +void MultiKeyOptionEntry::setExitOnCancelEntry(ZLOptionEntry *exitOnCancelEntry) { + myExitOnCancelEntry = exitOnCancelEntry; +} + +void MultiKeyOptionEntry::onKeySelected(const std::string &key) { + if (myExitOnCancelEntry != 0) { + myExitOnCancelEntry->setVisible(myBimap.codeByIndex(myCurrentEntry->actionIndex(key)) == ActionCode::CANCEL); + } +} + +class OrientationEntry : public ZLComboOptionEntry { + +public: + OrientationEntry(MultiKeyOptionEntry &keyEntry, const ZLResource &resource); + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onValueSelected(int index); + void onAccept(const std::string &value); + +private: + MultiKeyOptionEntry &myKeyEntry; + const ZLResource &myResource; +}; + +OrientationEntry::OrientationEntry(MultiKeyOptionEntry &keyEntry, const ZLResource &resource) : myKeyEntry(keyEntry), myResource(resource) { +} + +const std::string &OrientationEntry::initialValue() const { + return values()[0]; +} + +const std::vector<std::string> &OrientationEntry::values() const { + static std::vector<std::string> _values; + if (_values.empty()) { + _values.push_back(myResource["degrees0"].value()); + _values.push_back(myResource["degrees90ccw"].value()); + _values.push_back(myResource["degrees180"].value()); + _values.push_back(myResource["degrees90cw"].value()); + } + return _values; +} + +void OrientationEntry::onValueSelected(int index) { + static ZLView::Angle angles[] = { + ZLView::DEGREES0, + ZLView::DEGREES90, + ZLView::DEGREES180, + ZLView::DEGREES270 + }; + myKeyEntry.setOrientation(angles[index]); +} + +void OrientationEntry::onAccept(const std::string&) { +} + +class UseSeparateOptionsEntry : public ZLSimpleBooleanOptionEntry { + +public: + UseSeparateOptionsEntry(ZLOptionEntry &keyEntry, OrientationEntry &orientationEntry); + void onStateChanged(bool state); + +private: + ZLOptionEntry &myKeyEntry; + OrientationEntry &myOrientationEntry; +}; + +UseSeparateOptionsEntry::UseSeparateOptionsEntry(ZLOptionEntry &keyEntry, OrientationEntry &orientationEntry) : ZLSimpleBooleanOptionEntry(Reader::Instance().UseSeparateBindingsOption), myKeyEntry(keyEntry), myOrientationEntry(orientationEntry) { +} + +void UseSeparateOptionsEntry::onStateChanged(bool state) { + ZLSimpleBooleanOptionEntry::onStateChanged(state); + myOrientationEntry.setVisible(state); + myKeyEntry.resetView(); +} + + +void ReadingOptionsDialog::createKeyBindingsTab() { + ZLDialogContent &dialogTab = dialog().createTab(ZLResourceKey("Keys")); + Reader &reader = Reader::Instance(); + if (ZLBooleanOption(ZLCategoryKey::EMPTY, ZLOption::PLATFORM_GROUP, ZLOption::FULL_KEYBOARD_CONTROL, false).value()) { + dialogTab.addOption(ZLResourceKey("grabSystemKeys"), new KeyboardControlEntry()); + } + ZLResourceKey actionKey("action"); + ZLResourceKey separateKey("separate"); + ZLResourceKey orientationKey("orientation"); + MultiKeyOptionEntry *keyEntry = new MultiKeyOptionEntry(dialogTab.resource(actionKey)); + OrientationEntry *orientationEntry = new OrientationEntry(*keyEntry, dialogTab.resource(orientationKey)); + ZLBooleanOptionEntry *useSeparateBindingsEntry = new UseSeparateOptionsEntry(*keyEntry, *orientationEntry); + dialogTab.addOption(separateKey, useSeparateBindingsEntry); + dialogTab.addOption(orientationKey, orientationEntry); + dialogTab.addOption("", "", keyEntry); + ZLOptionEntry *exitOnCancelEntry = new ZLSimpleBooleanOptionEntry(reader.QuitOnCancelOption); + keyEntry->setExitOnCancelEntry(exitOnCancelEntry); + dialogTab.addOption(ZLResourceKey("quitOnCancel"), exitOnCancelEntry); + exitOnCancelEntry->setVisible(false); + useSeparateBindingsEntry->onStateChanged(useSeparateBindingsEntry->initialState()); + dialogTab.addOption(ZLResourceKey("keyDelay"), new ZLSimpleSpinOptionEntry(reader.KeyDelayOption, 50)); +} diff --git a/reader/src/optionsDialog/reading/ReadingOptionsDialog.cpp b/reader/src/optionsDialog/reading/ReadingOptionsDialog.cpp new file mode 100644 index 0000000..29528c6 --- /dev/null +++ b/reader/src/optionsDialog/reading/ReadingOptionsDialog.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLToggleBooleanOptionEntry.h> + +#include "ReadingOptionsDialog.h" + +#include "../../reader/Reader.h" +#include "../../reader/FBView.h" + + +class RotationTypeEntry : public ZLComboOptionEntry { + +public: + RotationTypeEntry(const ZLResource &resource, ZLIntegerOption &angleOption); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + +private: + ZLIntegerOption &myAngleOption; + std::vector<std::string> myValues; +}; + +RotationTypeEntry::RotationTypeEntry(const ZLResource &resource, ZLIntegerOption &angleOption) : myAngleOption(angleOption) { + myValues.push_back(resource["disabled"].value()); + myValues.push_back(resource["counterclockwise"].value()); + myValues.push_back(resource["180"].value()); + myValues.push_back(resource["clockwise"].value()); + myValues.push_back(resource["cycle"].value()); +} + +const std::string &RotationTypeEntry::initialValue() const { + switch (myAngleOption.value()) { + default: + return myValues[0]; + case ZLView::DEGREES90: + return myValues[1]; + case ZLView::DEGREES180: + return myValues[2]; + case ZLView::DEGREES270: + return myValues[3]; + case -1: + return myValues[4]; + } +} + +const std::vector<std::string> &RotationTypeEntry::values() const { + return myValues; +} + +void RotationTypeEntry::onAccept(const std::string &value) { + int angle = ZLView::DEGREES0; + if (value == myValues[1]) { + angle = ZLView::DEGREES90; + } else if (value == myValues[2]) { + angle = ZLView::DEGREES180; + } else if (value == myValues[3]) { + angle = ZLView::DEGREES270; + } else if (value == myValues[4]) { + angle = -1; + } + myAngleOption.setValue(angle); +} + + + +ReadingOptionsDialog::ReadingOptionsDialog() : AbstractOptionsDialog(ZLResourceKey("ReadingOptionsDialog"), true) { + Reader &reader = Reader::Instance(); + + ZLOptionsDialog &dialog = this->dialog(); + + ZLDialogContent &scrollingTab = dialog.createTab(ZLResourceKey("Scrolling")); + scrollingTab.addOption(ZLResourceKey("keyLinesToScroll"), new ZLSimpleSpinOptionEntry(reader.LinesToScrollOption, 1)); + scrollingTab.addOption(ZLResourceKey("keyLinesToKeep"), new ZLSimpleSpinOptionEntry(reader.LinesToKeepOption, 1)); + scrollingTab.addOption(ZLResourceKey("keyScrollDelay"), new ZLSimpleSpinOptionEntry(reader.KeyScrollingDelayOption, 50)); + const bool hasTouchScreen = + ZLBooleanOption(ZLCategoryKey::EMPTY, ZLOption::PLATFORM_GROUP, ZLOption::TOUCHSCREEN_PRESENTED, false).value(); + if (hasTouchScreen) { + ZLToggleBooleanOptionEntry *enableTapScrollingEntry = + new ZLToggleBooleanOptionEntry(reader.EnableTapScrollingOption); + scrollingTab.addOption(ZLResourceKey("enableTapScrolling"), enableTapScrollingEntry); + const bool isFingerTapDetectionSupported = + ZLBooleanOption(ZLCategoryKey::EMPTY, ZLOption::PLATFORM_GROUP, ZLOption::FINGER_TAP_DETECTABLE, false).value(); + if (isFingerTapDetectionSupported) { + ZLOptionEntry *fingerOnlyEntry = + new ZLSimpleBooleanOptionEntry(reader.TapScrollingOnFingerOnlyOption); + scrollingTab.addOption(ZLResourceKey("fingerOnly"), fingerOnlyEntry); + enableTapScrollingEntry->addDependentEntry(fingerOnlyEntry); + enableTapScrollingEntry->onStateChanged(enableTapScrollingEntry->initialState()); + } + } + + ZLDialogContent &selectionTab = dialog.createTab(ZLResourceKey("Selection")); + selectionTab.addOption(ZLResourceKey("enableSelection"), FBView::selectionOption()); + + createIndicatorTab(); + + ZLDialogContent &rotationTab = dialog.createTab(ZLResourceKey("Rotation")); + ZLResourceKey directionKey("direction"); + rotationTab.addOption(directionKey, new RotationTypeEntry(rotationTab.resource(directionKey), reader.RotationAngleOption)); + + createKeyBindingsTab(); +} diff --git a/reader/src/optionsDialog/reading/ReadingOptionsDialog.h b/reader/src/optionsDialog/reading/ReadingOptionsDialog.h new file mode 100644 index 0000000..83a101a --- /dev/null +++ b/reader/src/optionsDialog/reading/ReadingOptionsDialog.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __READINGOPTIONSDIALOG_H__ +#define __READINGOPTIONSDIALOG_H__ + +#include "../AbstractOptionsDialog.h" + + +class ReadingOptionsDialog : public AbstractOptionsDialog { + +private: + void createIndicatorTab(); + void createKeyBindingsTab(); + +public: + ReadingOptionsDialog(); +}; + +#endif /* __READINGOPTIONSDIALOG_H__ */ diff --git a/reader/src/optionsDialog/system/SystemOptionsDialog.cpp b/reader/src/optionsDialog/system/SystemOptionsDialog.cpp new file mode 100644 index 0000000..1c649df --- /dev/null +++ b/reader/src/optionsDialog/system/SystemOptionsDialog.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLLanguageList.h> +#include <ZLOptionEntry.h> + +#include <ZLSimpleOptionEntry.h> +#include <ZLLanguageOptionEntry.h> +#include <ZLToggleBooleanOptionEntry.h> + +#include "SystemOptionsDialog.h" + +#include "../../reader/Reader.h" +#include "../../formats/FormatPlugin.h" +#include "../../encodingOption/EncodingOptionEntry.h" + + +class TimeoutEntry : public ZLSimpleSpinOptionEntry { + +public: + TimeoutEntry(ZLIntegerRangeOption &option); + void onAccept(int value); +}; + +TimeoutEntry::TimeoutEntry(ZLIntegerRangeOption &option) : ZLSimpleSpinOptionEntry(option, 5) { +} + +void TimeoutEntry::onAccept(int value) { + ZLOption::startAutoSave(isVisible() ? value : 0); + ZLSimpleSpinOptionEntry::onAccept(value); +} + + +SystemOptionsDialog::SystemOptionsDialog() : AbstractOptionsDialog(ZLResourceKey("SystemOptionsDialog"), true) { + ZLOptionsDialog &dialog = this->dialog(); + + ZLDialogContent &encodingTab = dialog.createTab(ZLResourceKey("Language")); + encodingTab.addOption(ZLResourceKey("autoDetect"), new ZLSimpleBooleanOptionEntry(PluginCollection::Instance().LanguageAutoDetectOption)); + encodingTab.addOption(ZLResourceKey("defaultLanguage"), new ZLLanguageOptionEntry(PluginCollection::Instance().DefaultLanguageOption, ZLLanguageList::languageCodes())); + EncodingEntry *encodingEntry = new EncodingEntry(PluginCollection::Instance().DefaultEncodingOption); + EncodingSetEntry *encodingSetEntry = new EncodingSetEntry(*encodingEntry); + encodingTab.addOption(ZLResourceKey("defaultEncodingSet"), encodingSetEntry); + encodingTab.addOption(ZLResourceKey("defaultEncoding"), encodingEntry); + + if (ZLOption::isAutoSavingSupported()) { + ZLDialogContent &configTab = dialog.createTab(ZLResourceKey("Config")); + Reader &reader = Reader::Instance(); + ZLToggleBooleanOptionEntry *enableEntry = + new ZLToggleBooleanOptionEntry(reader.ConfigAutoSavingOption); + configTab.addOption(ZLResourceKey("autoSave"), enableEntry); + + ZLOptionEntry *timeoutEntry = new TimeoutEntry(reader.ConfigAutoSaveTimeoutOption); + enableEntry->addDependentEntry(timeoutEntry); + configTab.addOption(ZLResourceKey("timeout"), timeoutEntry); + + enableEntry->onStateChanged(enableEntry->initialState()); + } + + Reader &reader = Reader::Instance(); + + std::vector<std::pair<ZLResourceKey,ZLOptionEntry*> > additional; + ZLOptionEntry *entry = + new ZLSimpleBooleanOptionEntry(reader.EnableSingleClickDictionaryOption); + additional.push_back(std::make_pair(ZLResourceKey("singleClickOpen"), entry)); + createIntegrationTab(reader.dictionaryCollection(), ZLResourceKey("Dictionary"), additional); + + dialog.createPlatformDependentTabs(); +} diff --git a/reader/src/optionsDialog/system/SystemOptionsDialog.h b/reader/src/optionsDialog/system/SystemOptionsDialog.h new file mode 100644 index 0000000..171b6ba --- /dev/null +++ b/reader/src/optionsDialog/system/SystemOptionsDialog.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __SYSTEMOPTIONSDIALOG_H__ +#define __SYSTEMOPTIONSDIALOG_H__ + +#include "../AbstractOptionsDialog.h" + + +class SystemOptionsDialog: public AbstractOptionsDialog { + +public: + SystemOptionsDialog(); +}; + +#endif /* __SYSTEMOPTIONSDIALOG_H__ */ diff --git a/reader/src/reader/AddBookAction.cpp b/reader/src/reader/AddBookAction.cpp new file mode 100644 index 0000000..a37af1e --- /dev/null +++ b/reader/src/reader/AddBookAction.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLFile.h> + +#include "ReaderActions.h" +#include "Reader.h" +#include "../library/Book.h" +#include "../formats/FormatPlugin.h" + +class AddBookAction::FileFilter : public ZLOpenFileDialog::Filter { + +private: + bool accepts(const ZLFile &file) const; +}; + +bool AddBookAction::FileFilter::accepts(const ZLFile &file) const { + return file.isArchive() || !PluginCollection::Instance().plugin(file, false).isNull(); +} + +static const std::string GROUP_NAME = "OpenFileDialog"; + +AddBookAction::AddBookAction(int visibleInModes) : + ModeDependentAction(visibleInModes), + DirectoryOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP_NAME, "Directory", ZLFile("~").path()), + FileOption(ZLCategoryKey::LOOK_AND_FEEL, GROUP_NAME, "File", std::string()) { +} + +void AddBookAction::run() { + const ZLResourceKey dialogKey("addFileDialog"); + + FileFilter filter; + shared_ptr<ZLOpenFileDialog> dialog = ZLDialogManager::Instance().createOpenFileDialog(dialogKey, DirectoryOption.value(), FileOption.value(), filter); + bool code = dialog->run(); + DirectoryOption.setValue(dialog->directoryPath()); + FileOption.setValue(dialog->filePath()); + if (code) { + Reader::Instance().openFile(ZLFile(dialog->filePath())); + } +} diff --git a/reader/src/reader/BookTextView.cpp b/reader/src/reader/BookTextView.cpp new file mode 100644 index 0000000..c506a85 --- /dev/null +++ b/reader/src/reader/BookTextView.cpp @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLOptions.h> +#include <ZLDialogManager.h> +#include <ZLStringUtil.h> + +#include <ZLTextModel.h> +#include <ZLTextParagraph.h> +#include <ZLTextParagraphCursor.h> +#include <ZLTextWord.h> +#include <ZLTextPositionIndicator.h> + +#include "BookTextView.h" +#include "Reader.h" + +#include "../bookmodel/FBTextKind.h" +#include "../bookmodel/BookModel.h" +#include "../external/ProgramCollection.h" + +#include "../database/booksdb/BooksDB.h" +#include "../library/Book.h" + +class BookTextView::PositionIndicatorWithLabels : public PositionIndicator { + +public: + PositionIndicatorWithLabels(BookTextView &bookTextView, const ZLTextPositionIndicatorInfo &info); + +private: + void draw(); +}; + +static const std::string LAST_STATE_GROUP = "LastState"; + +static const std::string PARAGRAPH_OPTION_NAME = "Paragraph"; +static const std::string WORD_OPTION_NAME = "Word"; +static const std::string CHAR_OPTION_NAME = "Char"; +static const std::string POSITION_IN_BUFFER = "PositionInBuffer"; +static const std::string STATE_VALID = "Valid"; + +BookTextView::BookTextView(ZLPaintContext &context) : + FBView(context), + ShowTOCMarksOption(ZLCategoryKey::LOOK_AND_FEEL, "Indicator", "ShowTOCMarks", false) { + myCurrentPointInStack = 0; + myMaxStackSize = 20; + myLockUndoStackChanges = false; + myStackChanged = false; +} + +BookTextView::~BookTextView() { + saveState(); + setModel(0, 0); +} + +void BookTextView::readBookState(const Book &book) { + ReadingState state; + if (ZLBooleanOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, STATE_VALID, false).value()) { + state.Paragraph = ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, PARAGRAPH_OPTION_NAME, 0).value(); + state.Word = ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, WORD_OPTION_NAME, 0).value(); + state.Character = ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, CHAR_OPTION_NAME, 0).value(); + } else { + BooksDB::Instance().loadBookState(book, state); + } + gotoPosition(state.Paragraph, state.Word, state.Character); +} + +int BookTextView::readStackPos(const Book &book) { + if (ZLBooleanOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, STATE_VALID, false).value()) { + return ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, POSITION_IN_BUFFER, 0).value(); + } else { + return BooksDB::Instance().loadStackPos(book); + } +} + +void BookTextView::saveBookState(const Book &book) { + const ReadingState state( + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, PARAGRAPH_OPTION_NAME, 0).value(), + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, WORD_OPTION_NAME, 0).value(), + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, CHAR_OPTION_NAME, 0).value() + ); + const int stackPos = ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, POSITION_IN_BUFFER, 0).value(); + + BooksDB::Instance().setBookState(book, state); + BooksDB::Instance().setStackPos(book, stackPos); + + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, PARAGRAPH_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, WORD_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, CHAR_OPTION_NAME, 0).setValue(0); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, POSITION_IN_BUFFER, 0).setValue(0); + ZLBooleanOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, STATE_VALID, false).setValue(false); +} + +void BookTextView::setModel(shared_ptr<ZLTextModel> model, shared_ptr<Book> book) { + FBView::setModel(model); + if (!myBook.isNull()) { + saveBookState(*myBook); + } + myBook = book; + if (book.isNull()) { + return; + } + readBookState(*book); + myPositionStack.clear(); + myCurrentPointInStack = 0; + BooksDB::Instance().loadBookStateStack(*book, myPositionStack); + myStackChanged = false; + if (myPositionStack.size() > 0) { + int stackPos = readStackPos(*book); + if ((stackPos < 0) || (stackPos > (int) myPositionStack.size())) { + stackPos = myPositionStack.size(); + } + myCurrentPointInStack = stackPos; + while (myPositionStack.size() > myMaxStackSize) { + myPositionStack.erase(myPositionStack.begin()); + if (myCurrentPointInStack > 0) { + --myCurrentPointInStack; + } + myStackChanged = true; + } + } +} + +void BookTextView::setContentsModel(shared_ptr<ZLTextModel> contentsModel) { + myContentsModel = contentsModel; +} + +void BookTextView::saveState() { + const ZLTextWordCursor &cursor = textArea().startCursor(); + + if (myBook.isNull()) { + return; + } + + if (!cursor.isNull()) { + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, PARAGRAPH_OPTION_NAME, 0).setValue(cursor.paragraphCursor().index()); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, WORD_OPTION_NAME, 0).setValue(cursor.elementIndex()); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, CHAR_OPTION_NAME, 0).setValue(cursor.charIndex()); + ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, POSITION_IN_BUFFER, 0).setValue(myCurrentPointInStack); + ZLBooleanOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, STATE_VALID, false).setValue(true); + + if (myStackChanged) { + BooksDB::Instance().saveBookStateStack(*myBook, myPositionStack); + myStackChanged = false; + } + } +} + +BookTextView::Position BookTextView::cursorPosition(const ZLTextWordCursor &cursor) const { + return Position(cursor.paragraphCursor().index(), cursor.elementIndex(), cursor.charIndex()); +} + +bool BookTextView::pushCurrentPositionIntoStack(bool doPushSamePosition) { + const ZLTextWordCursor &cursor = textArea().startCursor(); + if (cursor.isNull()) { + return false; + } + + Position pos = cursorPosition(cursor); + if (!doPushSamePosition && !myPositionStack.empty() && (myPositionStack.back() == pos)) { + return false; + } + + myPositionStack.push_back(pos); + myStackChanged = true; + while (myPositionStack.size() > myMaxStackSize) { + myPositionStack.erase(myPositionStack.begin()); + if (myCurrentPointInStack > 0) { + --myCurrentPointInStack; + } + } + return true; +} + +void BookTextView::replaceCurrentPositionInStack() { + const ZLTextWordCursor &cursor = textArea().startCursor(); + if (!cursor.isNull()) { + myPositionStack[myCurrentPointInStack] = cursorPosition(cursor); + myStackChanged = true; + } +} + +void BookTextView::gotoParagraph(int num, bool end) { + if (textArea().isEmpty()) { + return; + } + + if (!myLockUndoStackChanges) { + if (myPositionStack.size() > myCurrentPointInStack) { + myPositionStack.erase(myPositionStack.begin() + myCurrentPointInStack, myPositionStack.end()); + myStackChanged = true; + } + pushCurrentPositionIntoStack(false); + myCurrentPointInStack = myPositionStack.size(); + } + + FBView::gotoParagraph(num, end); +} + +bool BookTextView::canUndoPageMove() { + if (textArea().isEmpty()) { + return false; + } + + if (myCurrentPointInStack == 0) { + return false; + } + if ((myCurrentPointInStack == 1) && (myPositionStack.size() == 1)) { + const ZLTextWordCursor &cursor = textArea().startCursor(); + if (!cursor.isNull()) { + return myPositionStack.back() != cursorPosition(cursor); + } + } + return true; +} + +void BookTextView::undoPageMove() { + if (canUndoPageMove()) { + if (myCurrentPointInStack == myPositionStack.size()) { + if (!pushCurrentPositionIntoStack(false)) { + -- myCurrentPointInStack; + } + } else { + replaceCurrentPositionInStack(); + } + + --myCurrentPointInStack; + Position &pos = myPositionStack[myCurrentPointInStack]; + myLockUndoStackChanges = true; + gotoPosition(pos.Paragraph, pos.Word, pos.Character); + myLockUndoStackChanges = false; + + Reader::Instance().refreshWindow(); + } +} + +bool BookTextView::canRedoPageMove() { + return !textArea().isEmpty() && + myCurrentPointInStack + 1 < myPositionStack.size(); +} + +void BookTextView::redoPageMove() { + if (canRedoPageMove()) { + replaceCurrentPositionInStack(); + ++myCurrentPointInStack; + Position &pos = myPositionStack[myCurrentPointInStack]; + myLockUndoStackChanges = true; + gotoPosition(pos.Paragraph, pos.Word, pos.Character); + myLockUndoStackChanges = false; + + if (myCurrentPointInStack + 1 == myPositionStack.size()) { + myPositionStack.pop_back(); + myStackChanged = true; + } + + Reader::Instance().refreshWindow(); + } +} + +bool BookTextView::getHyperlinkInfo(const ZLTextElementRectangle &rectangle, std::string &id, ZLHyperlinkType &type) const { + if ((rectangle.Kind != ZLTextElement::WORD_ELEMENT) && + (rectangle.Kind != ZLTextElement::IMAGE_ELEMENT)) { + return false; + } + ZLTextWordCursor cursor = textArea().startCursor(); + cursor.moveToParagraph(rectangle.ParagraphIndex); + cursor.moveToParagraphStart(); + ZLTextKind hyperlinkKind = REGULAR; + for (int i = 0; i < rectangle.ElementIndex; ++i) { + const ZLTextElement &element = cursor.element(); + if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { + const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); + if (control.isHyperlink()) { + hyperlinkKind = control.kind(); + id = ((const ZLTextHyperlinkControlEntry&)control).label(); + type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType(); + } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { + hyperlinkKind = REGULAR; + } + } + cursor.nextWord(); + } + + return hyperlinkKind != REGULAR; +} + +bool BookTextView::_onStylusPress(int x, int y) { + return false; +} + +bool BookTextView::onStylusClick(int x, int y, int count) { + Reader &reader = Reader::Instance(); + const ZLTextElementRectangle *rectangle = textArea().elementByCoordinates(x, y); + if (rectangle != 0) { + std::string id; + ZLHyperlinkType type; + if (getHyperlinkInfo(*rectangle, id, type)) { + reader.tryShowFootnoteView(id, type); + return true; + } + + if (reader.isDictionarySupported() && + reader.EnableSingleClickDictionaryOption.value()) { + const std::string txt = word(*rectangle); + if (!txt.empty()) { + reader.openInDictionary(txt); + return true; + } + } + } + + return FBView::onStylusClick(x, y, count); +} + +bool BookTextView::_onStylusRelease(int x, int y) { + Reader &reader = Reader::Instance(); + if (!isReleasedWithoutMotion()) { + return false; + } + + const ZLTextElementRectangle *rectangle = textArea().elementByCoordinates(x, y); + if (rectangle != 0) { + std::string id; + ZLHyperlinkType type; + if (getHyperlinkInfo(*rectangle, id, type)) { + reader.tryShowFootnoteView(id, type); + return true; + } + + if (reader.isDictionarySupported() && + reader.EnableSingleClickDictionaryOption.value()) { + const std::string txt = word(*rectangle); + if (!txt.empty()) { + reader.openInDictionary(txt); + return true; + } + } + } + + return false; +} + +bool BookTextView::_onStylusMove(int x, int y) { + const ZLTextElementRectangle *rectangle = textArea().elementByCoordinates(x, y); + std::string id; + ZLHyperlinkType type; + Reader::Instance().setHyperlinkCursor((rectangle != 0) && getHyperlinkInfo(*rectangle, id, type)); + return true; +} + +shared_ptr<ZLTextView::PositionIndicator> BookTextView::createPositionIndicator(const ZLTextPositionIndicatorInfo &info) { + return new PositionIndicatorWithLabels(*this, info); +} + +BookTextView::PositionIndicatorWithLabels::PositionIndicatorWithLabels(BookTextView &bookTextView, const ZLTextPositionIndicatorInfo &info) : PositionIndicator(bookTextView, info) { +} + +void BookTextView::PositionIndicatorWithLabels::draw() { + PositionIndicator::draw(); + + const BookTextView& bookTextView = (const BookTextView&)textView(); + + if (bookTextView.ShowTOCMarksOption.value()) { + shared_ptr<ZLTextModel> contentsModelPtr = bookTextView.myContentsModel; + if (!contentsModelPtr.isNull()) { + ContentsModel &contentsModel = (ContentsModel&)*contentsModelPtr; + const int marksNumber = contentsModel.paragraphsNumber(); + const std::size_t startIndex = startTextIndex(); + const std::size_t endIndex = endTextIndex(); + const std::vector<std::size_t> &textSizeVector = textSize(); + const int fullWidth = right() - left() - 1; + const std::size_t startPosition = textSizeVector[startIndex]; + const std::size_t fullTextSize = textSizeVector[endIndex] - startPosition; + const int bottom = this->bottom(); + const int top = this->top(); + for (int i = 0; i < marksNumber; ++i) { + std::size_t reference = contentsModel.reference((ZLTextTreeParagraph*)contentsModel[i]); + if ((startIndex < reference) && (reference < endIndex)) { + int position = left() + 2 + (int) + (1.0 * fullWidth * (textSizeVector[reference] - startPosition) / fullTextSize); + context().drawLine(position, bottom, position, top); + } + } + } + } +} + +void BookTextView::scrollToHome() { + if (!textArea().startCursor().isNull() && + textArea().startCursor().isStartOfParagraph() && + textArea().startCursor().paragraphCursor().index() == 0) { + return; + } + + gotoParagraph(0, false); + Reader::Instance().refreshWindow(); +} + +void BookTextView::paint() { + FBView::paint(); + std::string pn; + ZLStringUtil::appendNumber(pn, pageIndex()); + Reader::Instance().setVisualParameter(Reader::PageIndexParameter, pn); +} diff --git a/reader/src/reader/BookTextView.h b/reader/src/reader/BookTextView.h new file mode 100644 index 0000000..c98aa93 --- /dev/null +++ b/reader/src/reader/BookTextView.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __BOOKTEXTVIEW_H__ +#define __BOOKTEXTVIEW_H__ + +#include <deque> + +#include "ReadingState.h" + +#include <ZLOptions.h> + +#include "FBView.h" + +class Book; + +class BookTextView : public FBView { + +public: + ZLBooleanOption ShowTOCMarksOption; + +public: + BookTextView(ZLPaintContext &context); + ~BookTextView(); + + void setModel(shared_ptr<ZLTextModel> model, shared_ptr<Book> book); + void setContentsModel(shared_ptr<ZLTextModel> contentsModel); + void saveState(); + + void gotoParagraph(int num, bool end = false); + bool canUndoPageMove(); + void undoPageMove(); + bool canRedoPageMove(); + void redoPageMove(); + + void scrollToHome(); + + bool _onStylusPress(int x, int y); + bool _onStylusMove(int x, int y); + bool _onStylusRelease(int x, int y); + bool onStylusClick(int x, int y, int count); + +private: + typedef ReadingState Position; + Position cursorPosition(const ZLTextWordCursor &cursor) const; + bool pushCurrentPositionIntoStack(bool doPushSamePosition = true); + void replaceCurrentPositionInStack(); + + void preparePaintInfo(); + + bool getHyperlinkInfo(const ZLTextElementRectangle &rectangle, std::string &id, ZLHyperlinkType &type) const; + + shared_ptr<PositionIndicator> createPositionIndicator(const ZLTextPositionIndicatorInfo &info); + + void paint(); + +private: + class PositionIndicatorWithLabels; + +private: + void readBookState(const Book &book); + int readStackPos(const Book &book); + void saveBookState(const Book &book); + +private: + shared_ptr<ZLTextModel> myContentsModel; + + shared_ptr<Book> myBook; + + typedef std::deque<Position> PositionStack; + PositionStack myPositionStack; + unsigned int myCurrentPointInStack; + unsigned int myMaxStackSize; + + bool myLockUndoStackChanges; + bool myStackChanged; +}; + +inline void BookTextView::preparePaintInfo() { + ZLTextView::preparePaintInfo(); + saveState(); +} + +#endif /* __BOOKTEXTVIEW_H__ */ diff --git a/reader/src/reader/BooksOrderAction.cpp b/reader/src/reader/BooksOrderAction.cpp new file mode 100644 index 0000000..45193ea --- /dev/null +++ b/reader/src/reader/BooksOrderAction.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "Reader.h" +#include "ReaderActions.h" + +BooksOrderAction::BooksOrderAction() : ModeDependentAction(Reader::LIBRARY_MODE) { +} + +void BooksOrderAction::run() { + Reader::Instance().showLibraryView(); +} diff --git a/reader/src/reader/ContentsView.cpp b/reader/src/reader/ContentsView.cpp new file mode 100644 index 0000000..bb42aec --- /dev/null +++ b/reader/src/reader/ContentsView.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLTextParagraph.h> + +#include "ContentsView.h" +#include "BookTextView.h" +#include "Reader.h" + +#include "../bookmodel/BookModel.h" + +ContentsView::ContentsView(ZLPaintContext &context) : FBView(context) { +} + +ContentsView::~ContentsView() { +} + +bool ContentsView::_onStylusMove(int x, int y) { + Reader &reader = Reader::Instance(); + + int index = textArea().paragraphIndexByCoordinates(x, y); + if ((index < 0) || ((int)textArea().model()->paragraphsNumber() <= index)) { + reader.setHyperlinkCursor(false); + return true; + } + + const ContentsModel &contentsModel = (const ContentsModel&)*textArea().model(); + const ZLTextTreeParagraph *paragraph = (const ZLTextTreeParagraph*)contentsModel[index]; + + reader.setHyperlinkCursor(contentsModel.reference(paragraph) >= 0); + return true; +} + +bool ContentsView::_onStylusPress(int x, int y) { + Reader &reader = Reader::Instance(); + + const ContentsModel &contentsModel = (const ContentsModel&)*textArea().model(); + int index = textArea().paragraphIndexByCoordinates(x, y); + if ((index < 0) || ((int)contentsModel.paragraphsNumber() <= index)) { + return false; + } + + const ZLTextTreeParagraph *paragraph = (const ZLTextTreeParagraph*)contentsModel[index]; + + int reference = contentsModel.reference(paragraph); + + if (reference >= 0) { + reader.bookTextView().gotoParagraph(reference); + reader.showBookTextView(); + } + + return true; +} + +bool ContentsView::isEmpty() const { + shared_ptr<ZLTextModel> model = textArea().model(); + return model.isNull() || model->paragraphsNumber() == 0; +} + +std::size_t ContentsView::currentTextViewParagraph(bool includeStart) const { + const ZLTextWordCursor &cursor = Reader::Instance().bookTextView().textArea().startCursor(); + if (!cursor.isNull()) { + long reference = cursor.paragraphCursor().index(); + bool startOfParagraph = cursor.elementIndex() == 0; + if (cursor.isEndOfParagraph()) { + ++reference; + startOfParagraph = true; + } + shared_ptr<ZLTextModel> model = textArea().model(); + std::size_t length = model->paragraphsNumber(); + const ContentsModel &contentsModel = (const ContentsModel&)*model; + for (std::size_t i = 1; i < length; ++i) { + long contentsReference = + contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[i])); + if ((contentsReference > reference) || + (!includeStart && startOfParagraph && (contentsReference == reference))) { + return i - 1; + } + } + return length - 1; + } + return (std::size_t)-1; +} + +void ContentsView::gotoReference() { + textArea().model()->removeAllMarks(); + const std::size_t selected = currentTextViewParagraph(); + highlightParagraph(selected); + preparePaintInfo(); + gotoParagraph(selected); + scrollPage(false, ZLTextAreaController::SCROLL_PERCENTAGE, 40); +} diff --git a/reader/src/reader/ContentsView.h b/reader/src/reader/ContentsView.h new file mode 100644 index 0000000..f6cec1a --- /dev/null +++ b/reader/src/reader/ContentsView.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __CONTENTSVIEW_H__ +#define __CONTENTSVIEW_H__ + +#include "FBView.h" + +class ContentsView : public FBView { + +public: + ContentsView(ZLPaintContext &context); + ~ContentsView(); + + bool isEmpty() const; + std::size_t currentTextViewParagraph(bool includeStart = true) const; + void gotoReference(); + +private: + bool _onStylusPress(int x, int y); + bool _onStylusMove(int x, int y); +}; + +#endif /* __CONTENTSVIEW_H__ */ diff --git a/reader/src/reader/FootnoteView.h b/reader/src/reader/FootnoteView.h new file mode 100644 index 0000000..76a6b77 --- /dev/null +++ b/reader/src/reader/FootnoteView.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FOOTNOTEVIEW_H__ +#define __FOOTNOTEVIEW_H__ + +#include "FBView.h" + +class FootnoteView : public FBView { + +public: + FootnoteView(ZLPaintContext &context); +}; + +inline FootnoteView::FootnoteView(ZLPaintContext &context) : FBView(context) {} + +#endif /* __FOOTNOTEVIEW_H__ */ diff --git a/reader/src/reader/PreferencesPopupData.cpp b/reader/src/reader/PreferencesPopupData.cpp new file mode 100644 index 0000000..ccc1edb --- /dev/null +++ b/reader/src/reader/PreferencesPopupData.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "PreferencesPopupData.h" + +#include <ZLResource.h> + +#include "ReaderActions.h" + +PreferencesPopupData::PreferencesPopupData() { + myActionIds.push_back(ActionCode::SHOW_BOOK_INFO_DIALOG); + myActionIds.push_back(ActionCode::SHOW_READING_OPTIONS_DIALOG); + myActionIds.push_back(ActionCode::SHOW_LOOKANDFEEL_OPTIONS_DIALOG); + myActionIds.push_back(ActionCode::SHOW_LIBRARY_OPTIONS_DIALOG); + myActionIds.push_back(ActionCode::SHOW_NETWORK_OPTIONS_DIALOG); + myActionIds.push_back(ActionCode::SHOW_SYSTEM_OPTIONS_DIALOG); +} + +std::size_t PreferencesPopupData::id() const { + return myId; +} + +void PreferencesPopupData::updateId() { + ++myId; + myInvalidated = true; +} + +std::size_t PreferencesPopupData::count() const { + if (myInvalidated) { + myInvalidated = false; + myVisibleActionIds.clear(); + const Reader& reader = Reader::Instance(); + const std::size_t size = myActionIds.size(); + for (std::size_t i = 0; i < size; ++i) { + const std::string &actionId = myActionIds[i]; + if (reader.action(actionId)->isVisible()) { + myVisibleActionIds.push_back(actionId); + } + } + } + return myVisibleActionIds.size(); +} + +const std::string PreferencesPopupData::text(std::size_t index) { + if (index >= myVisibleActionIds.size()) { + return ""; + } + const std::string &actionId = myVisibleActionIds[index]; + return resource(actionId)["label"].value(); +} + +void PreferencesPopupData::run(std::size_t index) { + if (index >= myVisibleActionIds.size()) { + return; + } + Reader::Instance().doAction(myVisibleActionIds[index]); +} diff --git a/reader/src/reader/PreferencesPopupData.h b/reader/src/reader/PreferencesPopupData.h new file mode 100644 index 0000000..a3227d7 --- /dev/null +++ b/reader/src/reader/PreferencesPopupData.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __PREFERENCESPOPUPDATA_H__ +#define __PREFERENCESPOPUPDATA_H__ + +#include <string> +#include <vector> + +#include <ZLPopupData.h> + +class PreferencesPopupData: public ZLPopupData { +public: + PreferencesPopupData(); + void updateId(); + +private: + std::size_t id() const; + std::size_t count() const; + const std::string text(std::size_t index); + void run(std::size_t index); + +private: + std::size_t myId; + std::vector<std::string> myActionIds; + mutable bool myInvalidated; + mutable std::vector<std::string> myVisibleActionIds; +}; + +#endif /* __PREFERENCESPOPUPDATA_H__ */ diff --git a/reader/src/reader/Reader.cpp b/reader/src/reader/Reader.cpp new file mode 100644 index 0000000..7f42623 --- /dev/null +++ b/reader/src/reader/Reader.cpp @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <queue> + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLDir.h> +#include <ZLStringUtil.h> +#include <ZLResource.h> +#include <ZLMessage.h> +#include <ZLTimeManager.h> +#include <ZLLogger.h> +#include <ZLNetworkManager.h> + +#include <ZLTextStyleCollection.h> +#include <ZLTextHyphenator.h> + +#include "Reader.h" +#include "ReaderActions.h" +#include "ScrollingAction.h" +#include "BookTextView.h" +#include "FootnoteView.h" +#include "ContentsView.h" +#include "RecentBooksPopupData.h" +#include "PreferencesPopupData.h" +#include "TimeUpdater.h" + +#include "../libraryTree/LibraryView.h" +#include "../network/NetworkLinkCollection.h" +#include "../networkActions/NetworkOperationRunnable.h" + +#include "../migration/migrate.h" + +#include "../options/FBCategoryKey.h" +#include "../bookmodel/BookModel.h" +#include "../bookmodel/FBHyperlinkType.h" +#include "../formats/FormatPlugin.h" + +#include "../database/booksdb/BooksDB.h" +#include "../database/booksdb/BooksDBUtil.h" +#include "../library/Book.h" +#include "../networkActions/AuthenticationDialog.h" +#include "../network/NetworkErrors.h" + +static const std::string OPTIONS = "Options"; + +const std::string Reader::PageIndexParameter = "pageIndex"; + +class OpenFileHandler : public ZLMessageHandler { + +public: + void onMessageReceived(const std::vector<std::string> &arguments) { + if (arguments.size() == 1) { + Reader &reader = Reader::Instance(); + reader.myBookAlreadyOpen = true; + reader.presentWindow(); + reader.openFile(ZLFile(arguments[0])); + } + } +}; + +Reader &Reader::Instance() { + return (Reader&)ZLApplication::Instance(); +} + +Reader::Reader(const std::string &bookToOpen) : + ZLApplication("Reader"), + QuitOnCancelOption(ZLCategoryKey::CONFIG, OPTIONS, "QuitOnCancel", false), + KeyScrollingDelayOption(ZLCategoryKey::CONFIG, "Scrollings", "Delay", 0, 2000, 100), + LinesToScrollOption(ZLCategoryKey::CONFIG, "SmallScrolling", "LinesToScroll", 1, 20, 1), + LinesToKeepOption(ZLCategoryKey::CONFIG, "LargeScrolling", "LinesToKeepOption", 0, 20, 0), + EnableTapScrollingOption(ZLCategoryKey::CONFIG, "TapScrolling", "Enabled", true), + TapScrollingOnFingerOnlyOption(ZLCategoryKey::CONFIG, "TapScrolling", "FingerOnly", true), + UseSeparateBindingsOption(ZLCategoryKey::CONFIG, "KeysOptions", "UseSeparateBindings", false), + EnableSingleClickDictionaryOption(ZLCategoryKey::CONFIG, "Dictionary", "SingleClick", false), + LastOpenedPreferencesDialog(ZLCategoryKey::CONFIG, "PreferencesDialog", "LastOpened", ""), + myBindings0(new ZLKeyBindings("Keys")), + myBindings90(new ZLKeyBindings("Keys90")), + myBindings180(new ZLKeyBindings("Keys180")), + myBindings270(new ZLKeyBindings("Keys270")), + myBookToOpen(bookToOpen), + myBookAlreadyOpen(false), + myActionOnCancel(UNFULLSCREEN) { + + myBookTextView = new BookTextView(*context()); + myFootnoteView = new FootnoteView(*context()); + myContentsView = new ContentsView(*context()); + + myLibraryByAuthorView = new LibraryByAuthorView(*context()); + myLibraryByTagView = new LibraryByTagView(*context()); + myRecentBooksPopupData = new RecentBooksPopupData(); + myPreferencesPopupData = new PreferencesPopupData(); + myMode = UNDEFINED_MODE; + myPreviousMode = BOOK_TEXT_MODE; + setMode(BOOK_TEXT_MODE); + + addAction(ActionCode::SHOW_READING, new UndoAction(Reader::ALL_MODES & ~Reader::BOOK_TEXT_MODE)); + addAction(ActionCode::SHOW_LIBRARY, new SetModeAction(Reader::LIBRARY_MODE, Reader::BOOK_TEXT_MODE | Reader::CONTENTS_MODE)); + addAction(ActionCode::SHOW_NETWORK_LIBRARY, new ShowNetworkTreeLibraryAction()); + registerPopupData(ActionCode::SHOW_LIBRARY, myRecentBooksPopupData); + addAction(ActionCode::SHOW_OPTIONS_DIALOG, new ShowOptionsDialogAction()); + addAction(ActionCode::SHOW_TOC, new ShowContentsAction()); + addAction(ActionCode::SHOW_BOOK_INFO_DIALOG, new ShowBookInfoAction()); + addAction(ActionCode::SHOW_LIBRARY_OPTIONS_DIALOG, new ShowLibraryOptionsDialogAction()); + addAction(ActionCode::SHOW_NETWORK_OPTIONS_DIALOG, new ShowNetworkOptionsDialogAction()); + addAction(ActionCode::SHOW_SYSTEM_OPTIONS_DIALOG, new ShowSystemOptionsDialogAction()); + addAction(ActionCode::SHOW_READING_OPTIONS_DIALOG, new ShowReadingOptionsDialogAction()); + addAction(ActionCode::SHOW_LOOKANDFEEL_OPTIONS_DIALOG, new ShowLookAndFeelOptionsDialogAction()); + addAction(ActionCode::ADD_BOOK, new AddBookAction(Reader::BOOK_TEXT_MODE | Reader::LIBRARY_MODE | Reader::CONTENTS_MODE)); + addAction(ActionCode::UNDO, new UndoAction(Reader::BOOK_TEXT_MODE)); + addAction(ActionCode::REDO, new RedoAction()); + addAction(ActionCode::SEARCH, new SearchPatternAction()); + addAction(ActionCode::FIND_NEXT, new FindNextAction()); + addAction(ActionCode::FIND_PREVIOUS, new FindPreviousAction()); + addAction(ActionCode::SCROLL_TO_HOME, new ScrollToHomeAction()); + addAction(ActionCode::SCROLL_TO_START_OF_TEXT, new ScrollToStartOfTextAction()); + addAction(ActionCode::SCROLL_TO_END_OF_TEXT, new ScrollToEndOfTextAction()); + addAction(ActionCode::PAGE_SCROLL_FORWARD, new PageScrollingAction(true)); + addAction(ActionCode::PAGE_SCROLL_BACKWARD, new PageScrollingAction(false)); + addAction(ActionCode::LINE_SCROLL_FORWARD, new LineScrollingAction(true)); + addAction(ActionCode::LINE_SCROLL_BACKWARD, new LineScrollingAction(false)); + addAction(ActionCode::MOUSE_SCROLL_FORWARD, new MouseWheelScrollingAction(true)); + addAction(ActionCode::MOUSE_SCROLL_BACKWARD, new MouseWheelScrollingAction(false)); + addAction(ActionCode::TAP_SCROLL_FORWARD, new TapScrollingAction(true)); + addAction(ActionCode::TAP_SCROLL_BACKWARD, new TapScrollingAction(false)); + addAction(ActionCode::INCREASE_FONT, new ChangeFontSizeAction(2)); + addAction(ActionCode::DECREASE_FONT, new ChangeFontSizeAction(-2)); + addAction(ActionCode::ROTATE_SCREEN, new RotationAction()); + addAction(ActionCode::TOGGLE_FULLSCREEN, new FBFullscreenAction()); + addAction(ActionCode::FULLSCREEN_ON, new FBFullscreenAction()); + addAction(ActionCode::CANCEL, new CancelAction()); + addAction(ActionCode::SHOW_HIDE_POSITION_INDICATOR, new ToggleIndicatorAction()); + addAction(ActionCode::QUIT, new QuitAction()); + addAction(ActionCode::FORCE_QUIT, new ForceQuitAction()); + addAction(ActionCode::OPEN_PREVIOUS_BOOK, new OpenPreviousBookAction()); + addAction(ActionCode::SHOW_HELP, new ShowHelpAction()); + addAction(ActionCode::GOTO_NEXT_TOC_SECTION, new GotoNextTOCSectionAction()); + addAction(ActionCode::GOTO_PREVIOUS_TOC_SECTION, new GotoPreviousTOCSectionAction()); + addAction(ActionCode::COPY_SELECTED_TEXT_TO_CLIPBOARD, new CopySelectedTextAction()); + addAction(ActionCode::OPEN_SELECTED_TEXT_IN_DICTIONARY, new OpenSelectedTextInDictionaryAction()); + addAction(ActionCode::CLEAR_SELECTION, new ClearSelectionAction()); + addAction(ActionCode::GOTO_PAGE_NUMBER, new GotoPageNumberAction(std::string())); + addAction(ActionCode::GOTO_PAGE_NUMBER_WITH_PARAMETER, new GotoPageNumberAction(PageIndexParameter)); + shared_ptr<Action> booksOrderAction = new BooksOrderAction(); + addAction(ActionCode::ORGANIZE_BOOKS_BY_AUTHOR, booksOrderAction); + addAction(ActionCode::ORGANIZE_BOOKS_BY_TAG, booksOrderAction); + addAction(ActionCode::FILTER_LIBRARY, new FilterLibraryAction()); + + registerPopupData(ActionCode::SHOW_OPTIONS_DIALOG, myPreferencesPopupData); + + myOpenFileHandler = new OpenFileHandler(); + ZLCommunicationManager::Instance().registerHandler("openFile", myOpenFileHandler); + + ZLNetworkManager::Instance().setUserAgent(std::string("Reader/") + VERSION); +} + +Reader::~Reader() { + ZLTextStyleCollection::deleteInstance(); + PluginCollection::deleteInstance(); + ZLTextHyphenator::deleteInstance(); +} + +void Reader::initWindow() { + ZLApplication::initWindow(); + trackStylus(true); + + MigrationRunnable migration; + if (migration.shouldMigrate()) { + ZLDialogManager::Instance().wait(ZLResourceKey("migrate"), migration); + } + + if (!myBookAlreadyOpen) { + shared_ptr<Book> book; + if (!myBookToOpen.empty()) { + createBook(ZLFile(myBookToOpen), book); + } + if (book.isNull()) { + const BookList &books = Library::Instance().recentBooks(); + if (!books.empty()) { + book = books[0]; + } + } + if (book.isNull()) { + book = BooksDBUtil::getBook(helpFileName(ZLibrary::Language())); + } + if (book.isNull()) { + book = BooksDBUtil::getBook(helpFileName("en")); + } + openBook(book); + } + refreshWindow(); + + ZLTimeManager::Instance().addTask(new TimeUpdater(), 1000); +} + +void Reader::refreshWindow() { + ZLApplication::refreshWindow(); + ((RecentBooksPopupData&)*myRecentBooksPopupData).updateId(); + ((PreferencesPopupData&)*myPreferencesPopupData).updateId(); +} + +bool Reader::createBook(const ZLFile &bookFile, shared_ptr<Book> &book) { + shared_ptr<FormatPlugin> plugin = + PluginCollection::Instance().plugin(bookFile, false); + if (!plugin.isNull()) { + std::string error = plugin->tryOpen(bookFile); + if (!error.empty()) { + ZLResourceKey boxKey("openBookErrorBox"); + ZLDialogManager::Instance().errorBox( + boxKey, + ZLStringUtil::printf(ZLDialogManager::dialogMessage(boxKey), error) + ); + } else { + book = BooksDBUtil::getBook(bookFile.path()); + if (!book.isNull()) { + BooksDB::Instance().insertIntoBookList(*book); + } + } + return true; + } + + if (!bookFile.isArchive()) { + return false; + } + + std::queue<std::string> archiveNames; + archiveNames.push(bookFile.path()); + + std::vector<std::string> items; + + while (!archiveNames.empty()) { + shared_ptr<ZLDir> archiveDir = ZLFile(archiveNames.front()).directory(); + archiveNames.pop(); + if (archiveDir.isNull()) { + continue; + } + archiveDir->collectFiles(items, true); + for (std::vector<std::string>::const_iterator it = items.begin(); it != items.end(); ++it) { + const std::string itemName = archiveDir->itemPath(*it); + ZLFile subFile(itemName); + if (subFile.isArchive()) { + archiveNames.push(itemName); + } else if (createBook(subFile, book)) { + return true; + } + } + items.clear(); + } + + return false; +} + +class OpenBookRunnable : public ZLRunnable { + +public: + OpenBookRunnable(shared_ptr<Book> book) : myBook(book) {} + void run() { Reader::Instance().openBookInternal(myBook); } + +private: + shared_ptr<Book> myBook; +}; + +void Reader::openBook(shared_ptr<Book> book) { + OpenBookRunnable runnable(book); + ZLDialogManager::Instance().wait(ZLResourceKey("loadingBook"), runnable); + if (!book.isNull()) { + showBookTextView(); + } + resetWindowCaption(); +} + +void Reader::openBookInternal(shared_ptr<Book> book) { + if (!book.isNull()) { + BookTextView &bookTextView = (BookTextView&)*myBookTextView; + ContentsView &contentsView = (ContentsView&)*myContentsView; + FootnoteView &footnoteView = (FootnoteView&)*myFootnoteView; + + bookTextView.saveState(); + bookTextView.setModel(0, 0); + bookTextView.setContentsModel(0); + contentsView.setModel(0); + myModel.reset(); + myModel = new BookModel(book); + ZLTextHyphenator::Instance().load(book->language()); + bookTextView.setModel(myModel->bookTextModel(), book); + bookTextView.setCaption(book->title()); + bookTextView.setContentsModel(myModel->contentsModel()); + footnoteView.setModel(0); + footnoteView.setCaption(book->title()); + contentsView.setModel(myModel->contentsModel()); + contentsView.setCaption(book->title()); + + Library::Instance().addBook(book); + Library::Instance().addBookToRecentList(book); + ((RecentBooksPopupData&)*myRecentBooksPopupData).updateId(); + } +} + +void Reader::openLinkInBrowser(const std::string &url) const { + if (url.empty()) { + return; + } + shared_ptr<ProgramCollection> collection = webBrowserCollection(); + if (collection.isNull()) { + return; + } + shared_ptr<Program> program = collection->currentProgram(); + if (program.isNull()) { + return; + } + std::string copy = url; + NetworkLinkCollection::Instance().rewriteUrl(copy, true); + ZLLogger::Instance().println("URL", copy); + program->run("openLink", copy); +} + +void Reader::tryShowFootnoteView(const std::string &id, ZLHyperlinkType type) { + switch (type) { + case HYPERLINK_EXTERNAL: + openLinkInBrowser(id); + break; + case HYPERLINK_INTERNAL: + if (myMode == BOOK_TEXT_MODE && !myModel.isNull()) { + BookModel::Label label = myModel->label(id); + if (!label.Model.isNull()) { + if (label.Model == myModel->bookTextModel()) { + bookTextView().gotoParagraph(label.ParagraphNumber); + } else { + FootnoteView &view = ((FootnoteView&)*myFootnoteView); + view.setModel(label.Model); + setMode(FOOTNOTE_MODE); + view.gotoParagraph(label.ParagraphNumber); + } + setHyperlinkCursor(false); + refreshWindow(); + } + } + break; + case HYPERLINK_BOOK: +// DownloadBookRunnable downloader(id); +// downloader.executeWithUI(); +// if (downloader.hasErrors()) { +// downloader.showErrorMessage(); +// } else { +// shared_ptr<Book> book; +// createBook(ZLFile(downloader.fileName()), book); +// if (!book.isNull()) { +// Library::Instance().addBook(book); +// openBook(book); +// refreshWindow(); +// } +// } + break; + } +} + +Reader::ViewMode Reader::mode() const { + return myMode; +} + +bool Reader::isViewFinal() const { + return myMode == BOOK_TEXT_MODE; +} + +void Reader::showLibraryView() { + if (ZLStringOption(ZLCategoryKey::LOOK_AND_FEEL, "ToggleButtonGroup", "booksOrder", "").value() == ActionCode::ORGANIZE_BOOKS_BY_TAG) { + setView(myLibraryByTagView); + } else { + setView(myLibraryByAuthorView); + } +} + +void Reader::setMode(ViewMode mode) { + //TODO remove code for old network library view + if (mode == myMode) { + return; + } + + if (mode != BOOK_TEXT_MODE) { + myActionOnCancel = RETURN_TO_TEXT_MODE; + } + + myPreviousMode = myMode; + myMode = mode; + + switch (myMode) { + case BOOK_TEXT_MODE: + setHyperlinkCursor(false); + ((ZLTextView&)*myBookTextView).forceScrollbarUpdate(); + setView(myBookTextView); + break; + case CONTENTS_MODE: + ((ContentsView&)*myContentsView).gotoReference(); + setView(myContentsView); + break; + case FOOTNOTE_MODE: + setView(myFootnoteView); + break; + case LIBRARY_MODE: + { + shared_ptr<Book> currentBook = myModel->book(); + ((LibraryView&)*myLibraryByAuthorView).showBook(currentBook); + ((LibraryView&)*myLibraryByTagView).showBook(currentBook); + showLibraryView(); + break; + } + case BOOKMARKS_MODE: + break; + case UNDEFINED_MODE: + case ALL_MODES: + break; + } + refreshWindow(); +} + +BookTextView &Reader::bookTextView() const { + return (BookTextView&)*myBookTextView; +} + +void Reader::showBookTextView() { + setMode(BOOK_TEXT_MODE); +} + +void Reader::restorePreviousMode() { + setMode(myPreviousMode); + myPreviousMode = BOOK_TEXT_MODE; +} + +bool Reader::closeView() { + if (myMode == BOOK_TEXT_MODE) { + quit(); + return true; + } else { + restorePreviousMode(); + return false; + } +} + +std::string Reader::helpFileName(const std::string &language) const { + return ZLibrary::ApplicationDirectory() + ZLibrary::FileNameDelimiter + "help" + ZLibrary::FileNameDelimiter + "MiniHelp." + language + ".fb2"; +} + +void Reader::openFile(const ZLFile &file) { + shared_ptr<Book> book; + createBook(file, book); + if (!book.isNull()) { + openBook(book); + refreshWindow(); + } +} + +bool Reader::canDragFiles(const std::vector<std::string> &filePaths) const { + switch (myMode) { + case BOOK_TEXT_MODE: + case FOOTNOTE_MODE: + case CONTENTS_MODE: + case LIBRARY_MODE: + return filePaths.size() > 0; + default: + return false; + } +} + +void Reader::dragFiles(const std::vector<std::string> &filePaths) { + switch (myMode) { + case BOOK_TEXT_MODE: + case FOOTNOTE_MODE: + case CONTENTS_MODE: + if (filePaths.size() > 0) { + openFile(ZLFile(filePaths[0])); + } + break; + case LIBRARY_MODE: + if (filePaths.size() > 0) { + openFile(ZLFile(filePaths[0])); + } + break; + default: + break; + } +} + +void Reader::clearTextCaches() { + ((ZLTextView&)*myBookTextView).clearCaches(); + ((ZLTextView&)*myFootnoteView).clearCaches(); + ((ZLTextView&)*myContentsView).clearCaches(); +} + +shared_ptr<ZLKeyBindings> Reader::keyBindings() { + return UseSeparateBindingsOption.value() ? + keyBindings(rotation()) : myBindings0; +} + +shared_ptr<ZLKeyBindings> Reader::keyBindings(ZLView::Angle angle) { + switch (angle) { + case ZLView::DEGREES0: + return myBindings0; + case ZLView::DEGREES90: + return myBindings90; + case ZLView::DEGREES180: + return myBindings180; + case ZLView::DEGREES270: + return myBindings270; + } + return 0; +} + +shared_ptr<ProgramCollection> Reader::dictionaryCollection() const { + return myProgramCollectionMap.collection("Dictionary"); +} + +bool Reader::isDictionarySupported() const { + shared_ptr<ProgramCollection> collection = dictionaryCollection(); + return !collection.isNull() && !collection->currentProgram().isNull(); +} + +void Reader::openInDictionary(const std::string &word) { + shared_ptr<Program> dictionary = dictionaryCollection()->currentProgram(); + dictionary->run("present", ZLibrary::ApplicationName()); + dictionary->run("showWord", word); +} + +shared_ptr<ProgramCollection> Reader::webBrowserCollection() const { + return myProgramCollectionMap.collection("Web Browser"); +} + +shared_ptr<Book> Reader::currentBook() const { + return myModel->book(); +} + +bool Reader::showAuthDialog(const std::string &siteName, std::string &userName, std::string &password, const ZLResourceKey &errorKey) { + std::string message = errorKey.Name.empty() ? std::string() : NetworkErrors::errorMessage(errorKey.Name); + return AuthenticationDialog::run(siteName, userName, password, message); +} + +void Reader::saveUserName(const std::string &siteName, std::string &userName) { + UserList userList(siteName); + userList.saveUser(userName); +} diff --git a/reader/src/reader/Reader.h b/reader/src/reader/Reader.h new file mode 100644 index 0000000..7d9668b --- /dev/null +++ b/reader/src/reader/Reader.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __READER_H__ +#define __READER_H__ + +#include <string> +#include <map> + +#include <ZLOptions.h> +#include <ZLTime.h> +#include <ZLView.h> +#include <ZLApplication.h> +#include <ZLKeyBindings.h> +#include <ZLHyperlinkType.h> + +#include "../library/Library.h" +#include "../external/ProgramCollection.h" + +class ZLFile; +class ZLMessageHandler; + +class Book; +class BookModel; +class BookTextView; + +class Reader : public ZLApplication { + +public: + static Reader &Instance(); + +public: + // returns true if description was found or error message was shown + static bool createBook(const ZLFile &bookFile, shared_ptr<Book> &book); + + static const std::string PageIndexParameter; + +public: + enum ViewMode { + UNDEFINED_MODE = 0, + BOOK_TEXT_MODE = 1 << 0, + FOOTNOTE_MODE = 1 << 1, + CONTENTS_MODE = 1 << 2, + BOOKMARKS_MODE = 1 << 3, + LIBRARY_MODE = 1 << 4, + ALL_MODES = 0xFF + }; + +public: + ZLBooleanOption QuitOnCancelOption; + + ZLIntegerRangeOption KeyScrollingDelayOption; + ZLIntegerRangeOption LinesToScrollOption; + ZLIntegerRangeOption LinesToKeepOption; + ZLBooleanOption EnableTapScrollingOption; + ZLBooleanOption TapScrollingOnFingerOnlyOption; + + ZLBooleanOption UseSeparateBindingsOption; + + ZLBooleanOption EnableSingleClickDictionaryOption; + + ZLStringOption LastOpenedPreferencesDialog; + +public: + Reader(const std::string &bookToOpen); + ~Reader(); + + void setMode(ViewMode mode); + ViewMode mode() const; + + shared_ptr<Book> currentBook() const; + + void refreshWindow(); + +private: + void initWindow(); + + void clearTextCaches(); + + void restorePreviousMode(); + + bool closeView(); + std::string helpFileName(const std::string &language) const; + + void openFile(const ZLFile &file); + bool canDragFiles(const std::vector<std::string> &filePaths) const; + void dragFiles(const std::vector<std::string> &filePaths); + + bool isViewFinal() const; + + void showLibraryView(); + +public: + shared_ptr<ZLKeyBindings> keyBindings(); + shared_ptr<ZLKeyBindings> keyBindings(ZLView::Angle angle); + + bool isDictionarySupported() const; + void openInDictionary(const std::string &word); + + shared_ptr<ProgramCollection> webBrowserCollection() const; + void openLinkInBrowser(const std::string &url) const; + + void tryShowFootnoteView(const std::string &id, ZLHyperlinkType type); + BookTextView &bookTextView() const; + void showBookTextView(); + void openBook(shared_ptr<Book> book); + + bool showAuthDialog(const std::string &siteName, std::string &userName, std::string &password, const ZLResourceKey &errorKey); + void saveUserName(const std::string &siteName, std::string &userName); + +private: + shared_ptr<ProgramCollection> dictionaryCollection() const; + + void openBookInternal(shared_ptr<Book> book); + friend class OpenBookRunnable; + void rebuildCollectionInternal(); + friend class RebuildCollectionRunnable; + friend class OptionsApplyRunnable; + +private: + ViewMode myMode; + ViewMode myPreviousMode; + + shared_ptr<ZLView> myFootnoteView; + shared_ptr<ZLView> myBookTextView; + shared_ptr<ZLView> myContentsView; + + shared_ptr<ZLView> myLibraryByAuthorView; + shared_ptr<ZLView> myLibraryByTagView; + shared_ptr<ZLPopupData> myRecentBooksPopupData; + shared_ptr<ZLPopupData> myPreferencesPopupData; + + ZLTime myLastScrollingTime; + + shared_ptr<BookModel> myModel; + + shared_ptr<ZLKeyBindings> myBindings0; + shared_ptr<ZLKeyBindings> myBindings90; + shared_ptr<ZLKeyBindings> myBindings180; + shared_ptr<ZLKeyBindings> myBindings270; + + std::string myBookToOpen; + bool myBookAlreadyOpen; + + ProgramCollectionMap myProgramCollectionMap; + + shared_ptr<ZLMessageHandler> myOpenFileHandler; + + enum { + RETURN_TO_TEXT_MODE, + UNFULLSCREEN + } myActionOnCancel; + +friend class OpenFileHandler; + +friend class OptionsDialog; +friend class SystemOptionsDialog; +friend class FBView; + +//friend class ShowCollectionAction; +friend class ShowHelpAction; +//friend class ShowOptionsDialogAction; +friend class ShowContentsAction; +friend class AddBookAction; +friend class ShowBookInfoAction; +//friend class ScrollToHomeAction; +//friend class ScrollToStartOfTextAction; +//friend class ScrollToEndOfTextAction; +friend class UndoAction; +//friend class RedoAction; +friend class SearchAction; +friend class SearchPatternAction; +friend class FindNextAction; +friend class FindPreviousAction; +friend class ScrollingAction; +friend class ScrollingAction2; +friend class ChangeFontSizeAction; +friend class CancelAction; +//friend class ToggleIndicatorAction; +friend class QuitAction; +friend class OpenPreviousBookAction; +friend class GotoNextTOCSectionAction; +friend class GotoPreviousTOCSectionAction; +//friend class GotoPageNumber; +friend class SelectionAction; +friend class FBFullscreenAction; +friend class BooksOrderAction; +friend class LogOutAction; +}; + +#endif /* __READER_H__ */ diff --git a/reader/src/reader/ReaderActionCode.cpp b/reader/src/reader/ReaderActionCode.cpp new file mode 100644 index 0000000..3e88e76 --- /dev/null +++ b/reader/src/reader/ReaderActionCode.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "ReaderActions.h" + +const std::string ActionCode::SHOW_READING = "showReading"; +const std::string ActionCode::SHOW_LIBRARY = "showLibrary"; +const std::string ActionCode::SHOW_NETWORK_LIBRARY = "showNetworkLibrary"; +const std::string ActionCode::SHOW_TOC = "toc"; +const std::string ActionCode::SHOW_HELP = "showHelp"; +const std::string ActionCode::SHOW_BOOK_INFO_DIALOG = "bookInfo"; +const std::string ActionCode::SHOW_OPTIONS_DIALOG = "preferences"; +const std::string ActionCode::SHOW_LIBRARY_OPTIONS_DIALOG = "libraryOptions"; +const std::string ActionCode::SHOW_NETWORK_OPTIONS_DIALOG = "networkOptions"; +const std::string ActionCode::SHOW_SYSTEM_OPTIONS_DIALOG = "systemOptions"; +const std::string ActionCode::SHOW_READING_OPTIONS_DIALOG = "readingOptions"; +const std::string ActionCode::SHOW_LOOKANDFEEL_OPTIONS_DIALOG = "lookAndFeelOptions"; +const std::string ActionCode::UNDO = "undo"; +const std::string ActionCode::REDO = "redo"; +const std::string ActionCode::SEARCH = "search"; +const std::string ActionCode::FIND_PREVIOUS = "findPrevious"; +const std::string ActionCode::FIND_NEXT = "findNext"; +const std::string ActionCode::PAGE_SCROLL_FORWARD = "pageForward"; +const std::string ActionCode::PAGE_SCROLL_BACKWARD = "pageBackward"; +const std::string ActionCode::LINE_SCROLL_FORWARD = "lineForward"; +const std::string ActionCode::LINE_SCROLL_BACKWARD = "lineBackward"; +const std::string ActionCode::MOUSE_SCROLL_FORWARD = "mouseScrollForward"; +const std::string ActionCode::MOUSE_SCROLL_BACKWARD = "mouseScrollBackward"; +const std::string ActionCode::TAP_SCROLL_FORWARD = "tapScrollForward"; +const std::string ActionCode::TAP_SCROLL_BACKWARD = "tapScrollBackward"; +const std::string ActionCode::SCROLL_TO_HOME = "gotoHome"; +const std::string ActionCode::SCROLL_TO_START_OF_TEXT = "gotoSectionStart"; +const std::string ActionCode::SCROLL_TO_END_OF_TEXT = "gotoSectionEnd"; +const std::string ActionCode::CANCEL = "cancel"; +const std::string ActionCode::INCREASE_FONT = "increaseFont"; +const std::string ActionCode::DECREASE_FONT = "decreaseFont"; +const std::string ActionCode::SHOW_HIDE_POSITION_INDICATOR = "toggleIndicator"; +const std::string ActionCode::TOGGLE_FULLSCREEN = "toggleFullscreen"; +const std::string ActionCode::FULLSCREEN_ON = "onFullscreen"; +const std::string ActionCode::ADD_BOOK = "addBook"; +const std::string ActionCode::ROTATE_SCREEN = "rotate"; +const std::string ActionCode::QUIT = "quit"; +const std::string ActionCode::FORCE_QUIT = "forceQuit"; +const std::string ActionCode::OPEN_PREVIOUS_BOOK = "previousBook"; +const std::string ActionCode::GOTO_NEXT_TOC_SECTION = "nextTOCSection"; +const std::string ActionCode::GOTO_PREVIOUS_TOC_SECTION = "previousTOCSection"; +const std::string ActionCode::COPY_SELECTED_TEXT_TO_CLIPBOARD = "copyToClipboard"; +const std::string ActionCode::CLEAR_SELECTION = "clearSelection"; +const std::string ActionCode::OPEN_SELECTED_TEXT_IN_DICTIONARY = "openInDictionary"; +const std::string ActionCode::GOTO_PAGE_NUMBER = "gotoPageNumber"; +const std::string ActionCode::GOTO_PAGE_NUMBER_WITH_PARAMETER = "gotoPageNumberWithParameter"; +const std::string ActionCode::ORGANIZE_BOOKS_BY_AUTHOR = "byAuthor"; +const std::string ActionCode::ORGANIZE_BOOKS_BY_TAG = "byTag"; +const std::string ActionCode::FILTER_LIBRARY = "filterLibrary"; diff --git a/reader/src/reader/ReaderActions.cpp b/reader/src/reader/ReaderActions.cpp new file mode 100644 index 0000000..d7cd843 --- /dev/null +++ b/reader/src/reader/ReaderActions.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLDialogManager.h> +#include <ZLDialog.h> +#include <ZLOptionsDialog.h> +#include <ZLSimpleOptionEntry.h> +#include <ZLibrary.h> + +#include <ZLBlockTreeView.h> +#include <ZLTextView.h> +#include <ZLTextSelectionModel.h> + +#include "Reader.h" +#include "ReaderActions.h" +#include "BookTextView.h" +#include "ContentsView.h" +#include "../optionsDialog/bookInfo/BookInfoDialog.h" +#include "../optionsDialog/library/LibraryOptionsDialog.h" +#include "../optionsDialog/network/NetworkOptionsDialog.h" +#include "../optionsDialog/system/SystemOptionsDialog.h" +#include "../optionsDialog/reading/ReadingOptionsDialog.h" +#include "../optionsDialog/lookAndFeel/OptionsPage.h" +#include "../optionsDialog/lookAndFeel/LookAndFeelOptionsDialog.h" + +#include "../bookmodel/BookModel.h" +#include "../options/FBTextStyle.h" + +#include "../database/booksdb/BooksDBUtil.h" +#include "../database/booksdb/BooksDB.h" +#include "../library/Library.h" +#include "../library/Book.h" + +ModeDependentAction::ModeDependentAction(int visibleInModes) : myVisibleInModes(visibleInModes) { +} + +bool ModeDependentAction::isVisible() const { + return (Reader::Instance().mode() & myVisibleInModes) != 0; +} + +SetModeAction::SetModeAction(Reader::ViewMode modeToSet, int visibleInModes) : ModeDependentAction(visibleInModes), myModeToSet(modeToSet) { +} + +void SetModeAction::run() { + Reader::Instance().setMode(myModeToSet); +} + +void ShowHelpAction::run() { + Reader &reader = Reader::Instance(); + shared_ptr<Book> book = BooksDBUtil::getBook(reader.helpFileName(ZLibrary::Language())); + if (book.isNull()) { + book = BooksDBUtil::getBook(reader.helpFileName("en")); + } + if (!book.isNull()) { + reader.openBook(book); + reader.setMode(Reader::BOOK_TEXT_MODE); + reader.refreshWindow(); + } else { + ZLDialogManager::Instance().errorBox(ZLResourceKey("noHelpBox")); + } +} + +void ShowOptionsDialogAction::run() { + std::string actionId = Reader::Instance().LastOpenedPreferencesDialog.value(); + if (actionId.empty()) { + return; + } + Reader::Instance().doAction(actionId); +} + +void ShowLibraryOptionsDialogAction::run() { + Reader::Instance().LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_LIBRARY_OPTIONS_DIALOG); + LibraryOptionsDialog().dialog().run(); +} + +void ShowNetworkOptionsDialogAction::run() { + Reader::Instance().LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_NETWORK_OPTIONS_DIALOG); + NetworkOptionsDialog().dialog().run(); +} + +void ShowSystemOptionsDialogAction::run() { + Reader::Instance().LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_SYSTEM_OPTIONS_DIALOG); + SystemOptionsDialog().dialog().run(); +} + +void ShowReadingOptionsDialogAction::run() { + Reader::Instance().LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_READING_OPTIONS_DIALOG); + ReadingOptionsDialog().dialog().run(); +} + +void ShowLookAndFeelOptionsDialogAction::run() { + Reader::Instance().LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_LOOKANDFEEL_OPTIONS_DIALOG); + LookAndFeelOptionsDialog().dialog().run(); +} + +ShowContentsAction::ShowContentsAction() : SetModeAction(Reader::CONTENTS_MODE, Reader::BOOK_TEXT_MODE) { +} + +bool ShowContentsAction::isVisible() const { + return ModeDependentAction::isVisible() && !((ContentsView&)*Reader::Instance().myContentsView).isEmpty(); +} + +ScrollToHomeAction::ScrollToHomeAction() : ModeDependentAction(Reader::BOOK_TEXT_MODE) { +} + +bool ScrollToHomeAction::isEnabled() const { + if (!isVisible()) { + return false; + } + ZLTextWordCursor cursor = Reader::Instance().bookTextView().textArea().startCursor(); + return cursor.isNull() || !cursor.isStartOfParagraph() || !cursor.paragraphCursor().isFirst(); +} + +void ScrollToHomeAction::run() { + Reader::Instance().bookTextView().scrollToHome(); +} + +ScrollToStartOfTextAction::ScrollToStartOfTextAction() : ModeDependentAction(Reader::BOOK_TEXT_MODE) { +} + +bool ScrollToStartOfTextAction::isEnabled() const { + if (!isVisible()) { + return false; + } + ZLTextWordCursor cursor = Reader::Instance().bookTextView().textArea().startCursor(); + return cursor.isNull() || !cursor.isStartOfParagraph() || !cursor.paragraphCursor().isFirst(); +} + +void ScrollToStartOfTextAction::run() { + Reader::Instance().bookTextView().scrollToStartOfText(); +} + +ScrollToEndOfTextAction::ScrollToEndOfTextAction() : ModeDependentAction(Reader::BOOK_TEXT_MODE) { +} + +bool ScrollToEndOfTextAction::isEnabled() const { + if (!isVisible()) { + return false; + } + ZLTextWordCursor cursor = Reader::Instance().bookTextView().textArea().endCursor(); + return cursor.isNull() || !cursor.isEndOfParagraph() || !cursor.paragraphCursor().isLast(); +} + +void ScrollToEndOfTextAction::run() { + Reader::Instance().bookTextView().scrollToEndOfText(); +} + +ShowBookInfoAction::ShowBookInfoAction() : ModeDependentAction(Reader::BOOK_TEXT_MODE | Reader::CONTENTS_MODE | Reader::FOOTNOTE_MODE) { +} + +void ShowBookInfoAction::run() { + Reader &reader = Reader::Instance(); + reader.LastOpenedPreferencesDialog.setValue(ActionCode::SHOW_BOOK_INFO_DIALOG); + shared_ptr<Book> book = reader.myModel->book(); + if (BookInfoDialog(book).dialog().run()) { + reader.openBook(book); + reader.refreshWindow(); + } +} + +UndoAction::UndoAction(int visibleInModes) : ModeDependentAction(visibleInModes) { +} + +bool UndoAction::isEnabled() const { + Reader &reader = Reader::Instance(); + return (reader.mode() != Reader::BOOK_TEXT_MODE) || + reader.bookTextView().canUndoPageMove(); +} + +void UndoAction::run() { + Reader &reader = Reader::Instance(); + if (reader.mode() == Reader::BOOK_TEXT_MODE) { + reader.bookTextView().undoPageMove(); + } else { + reader.restorePreviousMode(); + } +} + +RedoAction::RedoAction() : ModeDependentAction(Reader::BOOK_TEXT_MODE) { +} + +bool RedoAction::isEnabled() const { + return isVisible() && Reader::Instance().bookTextView().canRedoPageMove(); +} + +void RedoAction::run() { + Reader::Instance().bookTextView().redoPageMove(); +} + +ChangeFontSizeAction::ChangeFontSizeAction(int delta) : myDelta(delta) { +} + +bool ChangeFontSizeAction::isEnabled() const { + ZLIntegerRangeOption &option = FBTextStyle::Instance().FontSizeOption; + if (myDelta < 0) { + return option.value() > option.minValue(); + } else { + return option.value() < option.maxValue(); + } +} + +void ChangeFontSizeAction::run() { + Reader &reader = Reader::Instance(); + ZLIntegerRangeOption &option = FBTextStyle::Instance().FontSizeOption; + option.setValue(option.value() + myDelta); + reader.clearTextCaches(); + reader.refreshWindow(); +} + +bool OpenPreviousBookAction::isVisible() const { + const Reader &reader = Reader::Instance(); + if ((reader.mode() != Reader::BOOK_TEXT_MODE) && + (reader.mode() != Reader::CONTENTS_MODE)) { + return false; + } + return Library::Instance().recentBooks().size() > 1; +} + +void OpenPreviousBookAction::run() { + Reader &reader = Reader::Instance(); + const BookList &books = Library::Instance().recentBooks(); + reader.openBook(books[1]); + reader.refreshWindow(); + reader.resetWindowCaption(); +} + +void CancelAction::run() { + Reader &reader = Reader::Instance(); + switch (reader.myActionOnCancel) { + case Reader::UNFULLSCREEN: + if (reader.isFullscreen()) { + reader.setFullscreen(false); + return; + } else if (reader.mode() != Reader::BOOK_TEXT_MODE) { + reader.restorePreviousMode(); + return; + } + break; + case Reader::RETURN_TO_TEXT_MODE: + if (reader.mode() != Reader::BOOK_TEXT_MODE) { + reader.restorePreviousMode(); + return; + } else if (reader.isFullscreen()) { + reader.setFullscreen(false); + return; + } + break; + } + if (reader.QuitOnCancelOption.value()) { + reader.quit(); + } +} + +bool ToggleIndicatorAction::isVisible() const { + ZLIntegerRangeOption &option = FBView::commonIndicatorInfo().TypeOption; + switch (option.value()) { + case FBIndicatorStyle::FB_INDICATOR: + case FBIndicatorStyle::NONE: + return true; + } + return false; +} + +void ToggleIndicatorAction::run() { + ZLIntegerRangeOption &option = FBView::commonIndicatorInfo().TypeOption; + switch (option.value()) { + case FBIndicatorStyle::OS_SCROLLBAR: + break; + case FBIndicatorStyle::FB_INDICATOR: + option.setValue(FBIndicatorStyle::NONE); + Reader::Instance().refreshWindow(); + break; + case FBIndicatorStyle::NONE: + option.setValue(FBIndicatorStyle::FB_INDICATOR); + Reader::Instance().refreshWindow(); + break; + } +} + +void QuitAction::run() { + Reader::Instance().closeView(); +} + +void ForceQuitAction::run() { + Reader::Instance().quit(); +} + +bool GotoNextTOCSectionAction::isVisible() const { + Reader &reader = Reader::Instance(); + if (reader.mode() != Reader::BOOK_TEXT_MODE) { + return false; + } + const ContentsView &contentsView = (const ContentsView&)*reader.myContentsView; + shared_ptr<ZLTextModel> model = contentsView.textArea().model(); + return !model.isNull() && (model->paragraphsNumber() > 1); +} + +bool GotoNextTOCSectionAction::isEnabled() const { + Reader &reader = Reader::Instance(); + const ContentsView &contentsView = (const ContentsView&)*reader.myContentsView; + shared_ptr<ZLTextModel> model = contentsView.textArea().model(); + return !model.isNull() && ((int)contentsView.currentTextViewParagraph() < (int)model->paragraphsNumber() - 1); +} + +void GotoNextTOCSectionAction::run() { + Reader &reader = Reader::Instance(); + ContentsView &contentsView = (ContentsView&)*reader.myContentsView; + std::size_t current = contentsView.currentTextViewParagraph(); + const ContentsModel &contentsModel = (const ContentsModel&)*contentsView.textArea().model(); + int reference = contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[current + 1])); + if (reference != -1) { + ((ZLTextView&)*reader.myBookTextView).gotoParagraph(reference); + reader.refreshWindow(); + } +} + +bool GotoPreviousTOCSectionAction::isVisible() const { + const Reader &reader = Reader::Instance(); + if (reader.mode() != Reader::BOOK_TEXT_MODE) { + return false; + } + const ContentsView &contentsView = (const ContentsView&)*reader.myContentsView; + shared_ptr<ZLTextModel> model = contentsView.textArea().model(); + return !model.isNull() && (model->paragraphsNumber() > 1); +} + +bool GotoPreviousTOCSectionAction::isEnabled() const { + const Reader &reader = Reader::Instance(); + const ContentsView &contentsView = (const ContentsView&)*reader.myContentsView; + shared_ptr<ZLTextModel> model = contentsView.textArea().model(); + if (model.isNull()) { + return false; + } + const ContentsModel &contentsModel = (const ContentsModel&)*model; + int tocIndex = contentsView.currentTextViewParagraph(false); + if (tocIndex > 0) { + return true; + } + if (tocIndex == 0) { + const ZLTextWordCursor &cursor = reader.bookTextView().textArea().startCursor(); + if (cursor.isNull()) { + return false; + } + if (cursor.elementIndex() > 0) { + return true; + } + return + contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[0])) > + (int)cursor.paragraphCursor().index(); + } + return false; +} + +void GotoPreviousTOCSectionAction::run() { + Reader &reader = Reader::Instance(); + ContentsView &contentsView = (ContentsView&)*reader.myContentsView; + std::size_t current = contentsView.currentTextViewParagraph(false); + const ContentsModel &contentsModel = (const ContentsModel&)*contentsView.textArea().model(); + + int reference = contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[current])); + const ZLTextWordCursor &cursor = reader.bookTextView().textArea().startCursor(); + if (!cursor.isNull() && + (cursor.elementIndex() == 0)) { + int paragraphIndex = cursor.paragraphCursor().index(); + if (reference == paragraphIndex) { + reference = contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[current - 1])); + } else if (reference == paragraphIndex - 1) { + const ZLTextModel &textModel = *reader.bookTextView().textArea().model(); + const ZLTextParagraph *para = textModel[paragraphIndex]; + if ((para != 0) && (para->kind() == ZLTextParagraph::END_OF_SECTION_PARAGRAPH)) { + reference = contentsModel.reference(((const ZLTextTreeParagraph*)contentsModel[current - 1])); + } + } + } + if (reference != -1) { + ((ZLTextView&)*reader.myBookTextView).gotoParagraph(reference); + reader.refreshWindow(); + } +} + +GotoPageNumberAction::GotoPageNumberAction(const std::string ¶meter) : ModeDependentAction(Reader::BOOK_TEXT_MODE), myParameter(parameter) { +} + +bool GotoPageNumberAction::isVisible() const { + return + ModeDependentAction::isVisible() && + !Reader::Instance().bookTextView().hasMultiSectionModel(); +} + +bool GotoPageNumberAction::isEnabled() const { + return ModeDependentAction::isEnabled() && (Reader::Instance().bookTextView().pageNumber() > 1); +} + +void GotoPageNumberAction::run() { + Reader &reader = Reader::Instance(); + int pageIndex = 0; + const int pageNumber = reader.bookTextView().pageNumber(); + + if (!myParameter.empty()) { + const std::string value = reader.visualParameter(myParameter); + if (value.empty()) { + return; + } + pageIndex = std::atoi(value.c_str()); + } else { + shared_ptr<ZLDialog> gotoPageDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("gotoPageDialog")); + + ZLIntegerRangeOption pageIndexOption(ZLCategoryKey::CONFIG, "gotoPageDialog", "Index", 1, pageNumber, pageIndex); + gotoPageDialog->addOption(ZLResourceKey("pageNumber"), new ZLSimpleSpinOptionEntry(pageIndexOption, 1)); + gotoPageDialog->addButton(ZLDialogManager::OK_BUTTON, true); + gotoPageDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); + if (gotoPageDialog->run()) { + gotoPageDialog->acceptValues(); + pageIndex = pageIndexOption.value(); + } else { + return; + } + } + + reader.bookTextView().gotoPage(std::max(1, std::min(pageIndex, pageNumber))); + reader.refreshWindow(); +} + +bool SelectionAction::isVisible() const { + shared_ptr<ZLView> view = Reader::Instance().currentView(); + return !view.isNull() && view->isInstanceOf(ZLTextView::TYPE_ID); +} + +bool SelectionAction::isEnabled() const { + if (!isVisible()) { + return false; + } + const ZLTextSelectionModel &selectionModel = textView().selectionModel(); + return !selectionModel.text().empty() || !selectionModel.image().isNull(); +} + +ZLTextView &SelectionAction::textView() const { + return (ZLTextView&)*Reader::Instance().currentView(); +} + +bool CopySelectedTextAction::isVisible() const { + return SelectionAction::isVisible() && ZLDialogManager::Instance().isClipboardSupported(ZLDialogManager::CLIPBOARD_MAIN); +} + +void CopySelectedTextAction::run() { + textView().selectionModel().copySelectionToClipboard(ZLDialogManager::CLIPBOARD_MAIN); +} + +bool OpenSelectedTextInDictionaryAction::isVisible() const { + return SelectionAction::isVisible() && Reader::Instance().isDictionarySupported(); +} + +void OpenSelectedTextInDictionaryAction::run() { + Reader::Instance().openInDictionary(textView().selectionModel().text()); +} + +void ClearSelectionAction::run() { + textView().selectionModel().clear(); + Reader::Instance().refreshWindow(); +} + +void FBFullscreenAction::run() { + Reader &reader = Reader::Instance(); + if (!reader.isFullscreen()) { + reader.myActionOnCancel = Reader::UNFULLSCREEN; + } + FullscreenAction::run(); +} + +FilterLibraryAction::FilterLibraryAction() : ModeDependentAction(Reader::LIBRARY_MODE) { +} + +void FilterLibraryAction::run() { +} diff --git a/reader/src/reader/ReaderActions.h b/reader/src/reader/ReaderActions.h new file mode 100644 index 0000000..18407ac --- /dev/null +++ b/reader/src/reader/ReaderActions.h @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __READERACTIONS_H__ +#define __READERACTIONS_H__ + +#include <ZLApplication.h> + +#include "Reader.h" + +class ZLTextView; + +class ActionCode { + +public: + static const std::string SHOW_READING; + static const std::string SHOW_LIBRARY; + static const std::string SHOW_NETWORK_LIBRARY; + static const std::string SHOW_TOC; + static const std::string SHOW_HELP; + static const std::string SHOW_OPTIONS_DIALOG; + static const std::string SHOW_BOOK_INFO_DIALOG; + static const std::string SHOW_LIBRARY_OPTIONS_DIALOG; + static const std::string SHOW_NETWORK_OPTIONS_DIALOG; + static const std::string SHOW_SYSTEM_OPTIONS_DIALOG; + static const std::string SHOW_READING_OPTIONS_DIALOG; + static const std::string SHOW_LOOKANDFEEL_OPTIONS_DIALOG; + static const std::string UNDO; + static const std::string REDO; + static const std::string SEARCH; + static const std::string FIND_PREVIOUS; + static const std::string FIND_NEXT; + static const std::string PAGE_SCROLL_FORWARD; + static const std::string PAGE_SCROLL_BACKWARD; + static const std::string LINE_SCROLL_FORWARD; + static const std::string LINE_SCROLL_BACKWARD; + static const std::string MOUSE_SCROLL_FORWARD; + static const std::string MOUSE_SCROLL_BACKWARD; + static const std::string TAP_SCROLL_FORWARD; + static const std::string TAP_SCROLL_BACKWARD; + static const std::string SCROLL_TO_HOME; + static const std::string SCROLL_TO_START_OF_TEXT; + static const std::string SCROLL_TO_END_OF_TEXT; + static const std::string CANCEL; + static const std::string INCREASE_FONT; + static const std::string DECREASE_FONT; + static const std::string SHOW_HIDE_POSITION_INDICATOR; + static const std::string TOGGLE_FULLSCREEN; + static const std::string FULLSCREEN_ON; + static const std::string ADD_BOOK; + static const std::string ROTATE_SCREEN; + static const std::string QUIT; + static const std::string FORCE_QUIT; + static const std::string OPEN_PREVIOUS_BOOK; + static const std::string GOTO_NEXT_TOC_SECTION; + static const std::string GOTO_PREVIOUS_TOC_SECTION; + static const std::string COPY_SELECTED_TEXT_TO_CLIPBOARD; + static const std::string CLEAR_SELECTION; + static const std::string OPEN_SELECTED_TEXT_IN_DICTIONARY; + static const std::string GOTO_PAGE_NUMBER; + static const std::string GOTO_PAGE_NUMBER_WITH_PARAMETER; + static const std::string ORGANIZE_BOOKS_BY_AUTHOR; + static const std::string ORGANIZE_BOOKS_BY_TAG; + static const std::string FILTER_LIBRARY; + +private: + ActionCode(); +}; + +class ModeDependentAction : public ZLApplication::Action { + +protected: + ModeDependentAction(int visibleInModes); + +public: + bool isVisible() const; + +private: + int myVisibleInModes; +}; + +class SetModeAction : public ModeDependentAction { + +public: + SetModeAction(Reader::ViewMode modeToSet, int visibleInModes); + void run(); + +private: + Reader::ViewMode myModeToSet; +}; + +class ShowHelpAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowLibraryOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowNetworkOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowSystemOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowReadingOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowLookAndFeelOptionsDialogAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ShowContentsAction : public SetModeAction { + +public: + ShowContentsAction(); + bool isVisible() const; +}; + +class ShowNetworkTreeLibraryAction : public ZLApplication::Action { + +public: + ShowNetworkTreeLibraryAction(); + +protected: + void run(); +}; + +class AddBookAction : public ModeDependentAction { + +private: + class FileFilter; + +private: + ZLStringOption DirectoryOption; + ZLStringOption FileOption; + +public: + AddBookAction(int visibleInModes); + void run(); +}; + +class ShowBookInfoAction : public ModeDependentAction { + +public: + ShowBookInfoAction(); + void run(); +}; + +class ScrollToHomeAction : public ModeDependentAction { + +public: + ScrollToHomeAction(); + bool isEnabled() const; + void run(); +}; + +class ScrollToStartOfTextAction : public ModeDependentAction { + +public: + ScrollToStartOfTextAction(); + bool isEnabled() const; + void run(); +}; + +class ScrollToEndOfTextAction : public ModeDependentAction { + +public: + ScrollToEndOfTextAction(); + bool isEnabled() const; + void run(); +}; + +class UndoAction : public ModeDependentAction { + +public: + UndoAction(int visibleInModes); + bool isEnabled() const; + void run(); +}; + +class RedoAction : public ModeDependentAction { + +public: + RedoAction(); + bool isEnabled() const; + void run(); +}; + +class SearchAction : public ZLApplication::Action { + +public: + bool isVisible() const; +}; + +class SearchPatternAction : public SearchAction { + +public: + SearchPatternAction(); + void run(); + +private: + ZLBooleanOption SearchBackwardOption; + ZLBooleanOption SearchIgnoreCaseOption; + ZLBooleanOption SearchInWholeTextOption; + ZLBooleanOption SearchThisSectionOnlyOption; + ZLStringOption SearchPatternOption; + +friend class SearchPatternEntry; +}; + +class FindNextAction : public SearchAction { + +public: + bool isEnabled() const; + void run(); +}; + +class FindPreviousAction : public SearchAction { + +public: + bool isEnabled() const; + void run(); +}; + +class ChangeFontSizeAction : public ZLApplication::Action { + +public: + ChangeFontSizeAction(int delta); + bool isEnabled() const; + void run(); + +private: + const int myDelta; +}; + +class CancelAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ToggleIndicatorAction : public ZLApplication::Action { + +public: + bool isVisible() const; + void run(); +}; + +class QuitAction : public ZLApplication::Action { + +public: + void run(); +}; + +class ForceQuitAction : public ZLApplication::Action { + +public: + void run(); +}; + +class OpenPreviousBookAction : public ZLApplication::Action { + +public: + bool isVisible() const; + void run(); +}; + +class GotoNextTOCSectionAction : public ZLApplication::Action { + +public: + bool isVisible() const; + bool isEnabled() const; + void run(); +}; + +class GotoPreviousTOCSectionAction : public ZLApplication::Action { + +public: + bool isVisible() const; + bool isEnabled() const; + void run(); +}; + +class GotoPageNumberAction : public ModeDependentAction { + +public: + GotoPageNumberAction(const std::string ¶meter); + bool isVisible() const; + bool isEnabled() const; + void run(); + +private: + const std::string myParameter; +}; + +class SelectionAction : public ZLApplication::Action { + +public: + bool isVisible() const; + bool isEnabled() const; + +protected: + ZLTextView &textView() const; +}; + +class CopySelectedTextAction : public SelectionAction { + +public: + bool isVisible() const; + void run(); +}; + +class OpenSelectedTextInDictionaryAction : public SelectionAction { + +public: + bool isVisible() const; + void run(); +}; + +class ClearSelectionAction : public SelectionAction { + +public: + void run(); +}; + +class SearchOnNetworkAction : ZLApplication::Action { + +public: + SearchOnNetworkAction(); + void run(); + +private: + virtual void doSearch() = 0; +}; + +class SimpleSearchOnNetworkAction : public SearchOnNetworkAction { + +private: + void doSearch(); + std::string makeSummary(const std::string &pattern); +}; + +class AdvancedSearchOnNetworkAction : public SearchOnNetworkAction { + +private: + void doSearch(); + std::string makeSummary(const std::string &titleAndSeries, const std::string &author, const std::string &category, const std::string &description); + void appendQueryValue(std::string &query, const std::string &name, const std::string &value); +}; + +class FBFullscreenAction : public ZLApplication::FullscreenAction { + +public: + void run(); +}; + +class BooksOrderAction : public ModeDependentAction { + +public: + BooksOrderAction(); + void run(); +}; + +class FilterLibraryAction : public ModeDependentAction { + +public: + FilterLibraryAction(); + void run(); +}; + +#endif /* __READERACTIONS_H__ */ diff --git a/reader/src/reader/ReadingState.h b/reader/src/reader/ReadingState.h new file mode 100644 index 0000000..9724b92 --- /dev/null +++ b/reader/src/reader/ReadingState.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __READINGSTATE_H___ +#define __READINGSTATE_H___ + +struct ReadingState { + int Paragraph; + int Word; + int Character; + + ReadingState(); + ReadingState(int paragraph, int word, int character); + + bool operator == (const ReadingState &rs) const; + bool operator != (const ReadingState &rs) const; +}; + +inline ReadingState::ReadingState(): Paragraph(0), Word(0), Character(0) {} +inline ReadingState::ReadingState(int paragraph, int word, int character): Paragraph(paragraph), Word(word), Character(character) {} + +inline bool ReadingState::operator == (const ReadingState &rs) const { return Paragraph == rs.Paragraph && Word == rs.Word && Character == rs.Character; } +inline bool ReadingState::operator != (const ReadingState &rs) const { return Paragraph != rs.Paragraph || Word != rs.Word || Character != rs.Character; } + +#endif /* __READINGSTATE_H___ */ diff --git a/reader/src/reader/RecentBooksPopupData.cpp b/reader/src/reader/RecentBooksPopupData.cpp new file mode 100644 index 0000000..cc0dcc4 --- /dev/null +++ b/reader/src/reader/RecentBooksPopupData.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include "RecentBooksPopupData.h" +#include "Reader.h" + +#include "../library/Book.h" +#include "../library/Author.h" + +RecentBooksPopupData::RecentBooksPopupData() : myId(0) { +} + +void RecentBooksPopupData::updateId() { + ++myId; +} + +std::size_t RecentBooksPopupData::id() const { + return myId; +} + +std::size_t RecentBooksPopupData::count() const { + return Library::Instance().recentBooks().size(); +} + +const std::string RecentBooksPopupData::text(std::size_t index) { + const BookList &books = Library::Instance().recentBooks(); + if (index >= books.size()) { + return ""; + } + const Book &book = *books[index]; + const AuthorList authors = book.authors(); + if (authors.empty()) { + return book.title(); + } else { + return authors[0]->name() + ". " + book.title(); + } +} + +void RecentBooksPopupData::run(std::size_t index) { + Reader &reader = Reader::Instance(); + const BookList &books = Library::Instance().recentBooks(); + if (index >= books.size()) { + return; + } + reader.openBook(books[index]); + reader.showBookTextView(); + reader.refreshWindow(); +} diff --git a/reader/src/reader/RecentBooksPopupData.h b/reader/src/reader/RecentBooksPopupData.h new file mode 100644 index 0000000..2a6b132 --- /dev/null +++ b/reader/src/reader/RecentBooksPopupData.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __RECENTBOOKSPOPUPDATA_H__ +#define __RECENTBOOKSPOPUPDATA_H__ + +#include <ZLPopupData.h> + +class RecentBooksPopupData : public ZLPopupData { + +public: + RecentBooksPopupData(); + void updateId(); + +private: + std::size_t id() const; + std::size_t count() const; + const std::string text(std::size_t index); + void run(std::size_t index); + +private: + std::size_t myId; +}; + +#endif /* __RECENTBOOKSPOPUPDATA_H__ */ diff --git a/reader/src/reader/ScrollingAction.cpp b/reader/src/reader/ScrollingAction.cpp new file mode 100644 index 0000000..29c92e0 --- /dev/null +++ b/reader/src/reader/ScrollingAction.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLTextView.h> +#include <ZLBlockTreeView.h> + +#include "Reader.h" +#include "ScrollingAction.h" + +ScrollingAction::ScrollingAction( + ZLTextAreaController::ScrollingMode textScrollingMode, + ZLBlockTreeView::ScrollingMode blockScrollingMode, + bool forward +) : myTextScrollingMode(textScrollingMode), myBlockScrollingMode(blockScrollingMode), myForward(forward) { +} + +int ScrollingAction::scrollingDelay() const { + return 0; +} + +bool ScrollingAction::isEnabled() const { + return true; +} + +bool ScrollingAction::useKeyDelay() const { + return false; +} + +void ScrollingAction::run() { + Reader &reader = Reader::Instance(); + shared_ptr<ZLView> view = reader.currentView(); + int delay = reader.myLastScrollingTime.millisecondsTo(ZLTime()); + if (view.isNull() || + (delay >= 0 && delay < scrollingDelay())) { + return; + } + + if (view->isInstanceOf(ZLTextView::TYPE_ID)) { + ((ZLTextView&)*view).scrollPage(myForward, myTextScrollingMode, textOptionValue()); + Reader::Instance().refreshWindow(); + } else if (view->isInstanceOf(ZLBlockTreeView::TYPE_ID)) { + ((ZLBlockTreeView&)*view).scroll(myBlockScrollingMode, !myForward); + } + reader.myLastScrollingTime = ZLTime(); +} + +LineScrollingAction::LineScrollingAction(bool forward) : ScrollingAction(ZLTextAreaController::SCROLL_LINES, ZLBlockTreeView::ITEM, forward) { +} + +int LineScrollingAction::scrollingDelay() const { + return Reader::Instance().KeyScrollingDelayOption.value(); +} + +std::size_t LineScrollingAction::textOptionValue() const { + return Reader::Instance().LinesToScrollOption.value(); +} + +PageScrollingAction::PageScrollingAction(bool forward) : ScrollingAction(ZLTextAreaController::KEEP_LINES, ZLBlockTreeView::PAGE, forward) { +} + +int PageScrollingAction::scrollingDelay() const { + return Reader::Instance().KeyScrollingDelayOption.value(); +} + +std::size_t PageScrollingAction::textOptionValue() const { + return Reader::Instance().LinesToKeepOption.value(); +} + +MouseWheelScrollingAction::MouseWheelScrollingAction(bool forward) : ScrollingAction(ZLTextAreaController::SCROLL_LINES, ZLBlockTreeView::ITEM, forward) { +} + +std::size_t MouseWheelScrollingAction::textOptionValue() const { + return 1; +} + +TapScrollingAction::TapScrollingAction(bool forward) : ScrollingAction(ZLTextAreaController::KEEP_LINES, ZLBlockTreeView::NONE, forward) { +} + +std::size_t TapScrollingAction::textOptionValue() const { + return Reader::Instance().LinesToKeepOption.value(); +} + +bool TapScrollingAction::isEnabled() const { + return Reader::Instance().EnableTapScrollingOption.value(); +} diff --git a/reader/src/reader/ScrollingAction.h b/reader/src/reader/ScrollingAction.h new file mode 100644 index 0000000..d93df64 --- /dev/null +++ b/reader/src/reader/ScrollingAction.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __SCROLLINGACTION_H__ +#define __SCROLLINGACTION_H__ + +#include <ZLApplication.h> +#include <ZLTextAreaController.h> +#include <ZLBlockTreeView.h> + +class ScrollingAction : public ZLApplication::Action { + +protected: + ScrollingAction( + ZLTextAreaController::ScrollingMode textScrollingMode, + ZLBlockTreeView::ScrollingMode blockScrollingMode, + bool forward + ); + +public: + virtual std::size_t textOptionValue() const = 0; + virtual int scrollingDelay() const; + bool isEnabled() const; + bool useKeyDelay() const; + void run(); + +private: + const ZLTextAreaController::ScrollingMode myTextScrollingMode; + const ZLBlockTreeView::ScrollingMode myBlockScrollingMode; + const bool myForward; +}; + +class LineScrollingAction : public ScrollingAction { + +public: + LineScrollingAction(bool forward); + +private: + int scrollingDelay() const; + std::size_t textOptionValue() const; +}; + +class PageScrollingAction : public ScrollingAction { + +public: + PageScrollingAction(bool forward); + +private: + int scrollingDelay() const; + std::size_t textOptionValue() const; +}; + +class MouseWheelScrollingAction : public ScrollingAction { + +public: + MouseWheelScrollingAction(bool forward); + +private: + std::size_t textOptionValue() const; +}; + +class TapScrollingAction : public ScrollingAction { + +public: + TapScrollingAction(bool forward); + +private: + std::size_t textOptionValue() const; + bool isEnabled() const; +}; + +#endif /* __SCROLLINGACTION_H__ */ diff --git a/reader/src/reader/SearchActions.cpp b/reader/src/reader/SearchActions.cpp new file mode 100644 index 0000000..ab80705 --- /dev/null +++ b/reader/src/reader/SearchActions.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLDialogManager.h> +#include <ZLDialog.h> +#include <ZLStringUtil.h> +#include <ZLOptionEntry.h> + +#include <ZLTextView.h> + +#include "Reader.h" +#include "FBView.h" +#include "ReaderActions.h" +#include "../options/FBCategoryKey.h" + +#include <set> + +static const std::string SEARCH = "Search"; +static const std::string PATTERN = "Pattern"; + +class SearchPatternEntry : public ZLComboOptionEntry { + +public: + SearchPatternEntry(SearchPatternAction &action); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + +private: + SearchPatternAction &myAction; + mutable std::vector<std::string> myValues; +}; + +SearchPatternEntry::SearchPatternEntry(SearchPatternAction &action) : ZLComboOptionEntry(true), myAction(action) { +} + +const std::string &SearchPatternEntry::initialValue() const { + return values()[0]; +} + +const std::vector<std::string> &SearchPatternEntry::values() const { + if (myValues.empty()) { + myValues.push_back(myAction.SearchPatternOption.value()); + for (int i = 1; i < 6; ++i) { + std::string pattern = PATTERN; + ZLStringUtil::appendNumber(pattern, i); + std::string value = ZLStringOption(FBCategoryKey::SEARCH, SEARCH, pattern, "").value(); + if (!value.empty()) { + myValues.push_back(value); + } + } + } + return myValues; +} + +void SearchPatternEntry::onAccept(const std::string &value) { + std::string v = value; + ZLStringUtil::stripWhiteSpaces(v); + if (v != values()[0]) { + myAction.SearchPatternOption.setValue(v); + int index = 1; + for (std::vector<std::string>::const_iterator it = myValues.begin(); (index < 6) && (it != myValues.end()); ++it) { + if (*it != v) { + std::string pattern = PATTERN; + ZLStringUtil::appendNumber(pattern, index++); + ZLStringOption(FBCategoryKey::SEARCH, SEARCH, pattern, "").setValue(*it); + } + } + } +} + +bool SearchAction::isVisible() const { + shared_ptr<ZLView> view = Reader::Instance().currentView(); + return + !view.isNull() && + view->isInstanceOf(ZLTextView::TYPE_ID) && + ((FBView&)*view).hasContents(); +} + +SearchPatternAction::SearchPatternAction() : + SearchBackwardOption(FBCategoryKey::SEARCH, SEARCH, "Backward", false), + SearchIgnoreCaseOption(FBCategoryKey::SEARCH, SEARCH, "IgnoreCase", true), + SearchInWholeTextOption(FBCategoryKey::SEARCH, SEARCH, "WholeText", false), + SearchThisSectionOnlyOption(FBCategoryKey::SEARCH, SEARCH, "ThisSectionOnly", false), + SearchPatternOption(FBCategoryKey::SEARCH, SEARCH, PATTERN, "") { +} + +void SearchPatternAction::run() { + ZLTextView &textView = (ZLTextView&)*Reader::Instance().currentView(); + + shared_ptr<ZLDialog> searchDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("textSearchDialog")); + + searchDialog->addOption(ZLResourceKey("text"), new SearchPatternEntry(*this)); + searchDialog->addOption(ZLResourceKey("ignoreCase"), SearchIgnoreCaseOption); + searchDialog->addOption(ZLResourceKey("wholeText"), SearchInWholeTextOption); + searchDialog->addOption(ZLResourceKey("backward"), SearchBackwardOption); + if (textView.hasMultiSectionModel()) { + searchDialog->addOption(ZLResourceKey("currentSection"), SearchThisSectionOnlyOption); + } + searchDialog->addButton(ZLResourceKey("go"), true); + searchDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); + + if (searchDialog->run()) { + searchDialog->acceptValues(); + textView.search( + SearchPatternOption.value(), + SearchIgnoreCaseOption.value(), + SearchInWholeTextOption.value(), + SearchBackwardOption.value(), + SearchThisSectionOnlyOption.value() + ); + } +} + +bool FindNextAction::isEnabled() const { + shared_ptr<ZLView> view = Reader::Instance().currentView(); + return + !view.isNull() && + view->isInstanceOf(ZLTextView::TYPE_ID) && + ((ZLTextView&)*view).canFindNext(); + return false; +} + +void FindNextAction::run() { + ((ZLTextView&)*Reader::Instance().currentView()).findNext(); +} + +bool FindPreviousAction::isEnabled() const { + shared_ptr<ZLView> view = Reader::Instance().currentView(); + return + !view.isNull() && + view->isInstanceOf(ZLTextView::TYPE_ID) && + ((ZLTextView&)*view).canFindPrevious(); +} + +void FindPreviousAction::run() { + ((ZLTextView&)*Reader::Instance().currentView()).findPrevious(); +} diff --git a/reader/src/reader/SearchOnNetworkAction.cpp b/reader/src/reader/SearchOnNetworkAction.cpp new file mode 100644 index 0000000..2adda6f --- /dev/null +++ b/reader/src/reader/SearchOnNetworkAction.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLDialogManager.h> +#include <ZLDialog.h> +#include <ZLNetworkManager.h> + +#include "../options/FBCategoryKey.h" + +#include "ReaderActions.h" + +#include "../network/NetworkLink.h" +#include "../network/NetworkLinkCollection.h" +#include "../network/SearchResult.h" +#include "../network/authentication/NetworkAuthenticationManager.h" +#include "../networkActions/NetworkOperationRunnable.h" +#include "../network/tree/NetworkLibrary.h" + +static const std::string SEARCH_PARAMETER_ID = "networkSearchPattern"; + +ShowNetworkTreeLibraryAction::ShowNetworkTreeLibraryAction() { } + +void ShowNetworkTreeLibraryAction::run() { + NetworkLibrary::Instance().showDialog(); +} + +SearchOnNetworkAction::SearchOnNetworkAction() { +} + +void SearchOnNetworkAction::run() { +// NetworkLinkCollection &collection = NetworkLinkCollection::Instance(); +// for (std::size_t i = 0; i < collection.size(); ++i) { +// NetworkLink &link = collection.link(i); +// if (link.isEnabled()) { +// shared_ptr<NetworkAuthenticationManager> mgr = link.authenticationManager(); +// if (!mgr.isNull()) { +// IsAuthorisedRunnable checker(*mgr); +// checker.executeWithUI(); +// if (checker.result() == B3_TRUE && mgr->needsInitialization()) { +// InitializeAuthenticationManagerRunnable initializer(*mgr); +// initializer.executeWithUI(); +// if (initializer.hasErrors()) { +// LogOutRunnable logout(*mgr); +// logout.executeWithUI(); +// } +// } +// } +// } +// } + +// doSearch(); +} + + +void SimpleSearchOnNetworkAction::doSearch() { + Reader &reader = Reader::Instance(); + const std::string pattern = reader.visualParameter(SEARCH_PARAMETER_ID); + if (pattern.empty()) { + return; + } + + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + SimpleSearchRunnable runnable(pattern); + runnable.executeWithUI(); + runnable.showErrorMessage(); + shared_ptr<NetworkBookCollection> result = runnable.result(); + + if (!result.isNull()) { + std::string summary = makeSummary(pattern); + SearchResult::setLastSearchResult(summary, result); + } + + reader.refreshWindow(); +} + +void AdvancedSearchOnNetworkAction::doSearch() { + shared_ptr<ZLDialog> searchDialog = ZLDialogManager::Instance().createDialog(ZLResourceKey("networkSearchDialog")); + + ZLStringOption titleAndSeriesOption(FBCategoryKey::SEARCH, "network", "title", ""); + searchDialog->addOption(ZLResourceKey("titleAndSeries"), titleAndSeriesOption); + ZLStringOption authorOption(FBCategoryKey::SEARCH, "network", "author", ""); + searchDialog->addOption(ZLResourceKey("author"), authorOption); + //ZLStringOption seriesOption(FBCategoryKey::SEARCH, "network", "series", ""); + //searchDialog->addOption(ZLResourceKey("series"), seriesOption); + ZLStringOption categoryOption(FBCategoryKey::SEARCH, "network", "category", ""); + searchDialog->addOption(ZLResourceKey("category"), categoryOption); + ZLStringOption descriptionOption(FBCategoryKey::SEARCH, "network", "description", ""); + searchDialog->addOption(ZLResourceKey("description"), descriptionOption); + searchDialog->addButton(ZLResourceKey("go"), true); + searchDialog->addButton(ZLDialogManager::CANCEL_BUTTON, false); + + if (searchDialog->run()) { + searchDialog->acceptValues(); + searchDialog.reset(); + std::string titleAndSeriesPattern = titleAndSeriesOption.value(); + ZLUnicodeUtil::utf8Trim(titleAndSeriesPattern); + std::string authorPattern = authorOption.value(); + ZLUnicodeUtil::utf8Trim(authorPattern); + //std::string seriesPattern = seriesOption.value(); + //ZLUnicodeUtil::utf8Trim(seriesPattern); + std::string categoryPattern = categoryOption.value(); + ZLUnicodeUtil::utf8Trim(categoryPattern); + std::string descriptionPattern = descriptionOption.value(); + ZLUnicodeUtil::utf8Trim(descriptionPattern); + + if (!titleAndSeriesPattern.empty() || + !authorPattern.empty() || + //!seriesPattern.empty() || + !categoryPattern.empty() || + !descriptionPattern.empty()) { + + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + AdvancedSearchRunnable runnable(titleAndSeriesPattern, authorPattern, categoryPattern, descriptionPattern); + runnable.executeWithUI(); + runnable.showErrorMessage(); + shared_ptr<NetworkBookCollection> result = runnable.result(); + + if (!result.isNull()) { + std::string summary = makeSummary(titleAndSeriesPattern, authorPattern, categoryPattern, descriptionPattern); + SearchResult::setLastSearchResult(summary, result); + } + + Reader::Instance().refreshWindow(); + } + } +} + +std::string SimpleSearchOnNetworkAction::makeSummary(const std::string &pattern) { + const ZLResource &resource = ZLResource::resource("dialog")["networkSearchDialog"]; + return ZLStringUtil::printf(resource["annotation"].value(), pattern); +} + +std::string AdvancedSearchOnNetworkAction::makeSummary(const std::string &titleAndSeries, const std::string &author, const std::string &category, const std::string &description) { + const ZLResource &resource = ZLResource::resource("dialog")["networkSearchDialog"]; + + std::string query; + appendQueryValue(query, resource["titleAndSeries"].value(), titleAndSeries); + appendQueryValue(query, resource["author"].value(), author); + appendQueryValue(query, resource["category"].value(), category); + appendQueryValue(query, resource["description"].value(), description); + + return ZLStringUtil::printf(resource["annotation"].value(), query); +} + +void AdvancedSearchOnNetworkAction::appendQueryValue(std::string &query, const std::string &name, const std::string &value) { + if (value.empty()) { + return; + } + if (!query.empty()) { + query.append(", "); + } + query.append(name).append("=\"").append(value).append("\""); +} diff --git a/reader/src/reader/TimeUpdater.cpp b/reader/src/reader/TimeUpdater.cpp new file mode 100644 index 0000000..14952a2 --- /dev/null +++ b/reader/src/reader/TimeUpdater.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLTime.h> +#include <ZLApplication.h> + +#include <ZLTextStyle.h> + +#include "FBView.h" +#include "TimeUpdater.h" + +TimeUpdater::TimeUpdater() : myTime(-1) { +} + +void TimeUpdater::run() { + if (FBView::commonIndicatorInfo().ShowTimeOption.value()) { + ZLTime time; + short minutes = time.hours() * 60 + time.minutes(); + if (myTime != minutes) { + myTime = minutes; + ZLApplication::Instance().refreshWindow(); + } + } +} diff --git a/reader/src/reader/TimeUpdater.h b/reader/src/reader/TimeUpdater.h new file mode 100644 index 0000000..45166e7 --- /dev/null +++ b/reader/src/reader/TimeUpdater.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __TIMEUPDATER_H__ +#define __TIMEUPDATER_H__ + +#include <ZLRunnable.h> + +class TimeUpdater : public ZLRunnable { + +public: + TimeUpdater(); + +private: + void run(); + +private: + short myTime; +}; + +#endif /* __TIMEUPDATER_H__ */ diff --git a/reader/src/reader/View.cpp b/reader/src/reader/View.cpp new file mode 100644 index 0000000..8296a72 --- /dev/null +++ b/reader/src/reader/View.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <cmath> +#include <algorithm> + +#include <ZLUnicodeUtil.h> +#include <ZLTimeManager.h> +#include <ZLTextSelectionModel.h> + +#include "FBView.h" +#include "Reader.h" +#include "ReaderActions.h" +#include "../options/FBOptions.h" +#include "../options/FBTextStyle.h" + +static const std::string INDICATOR = "Indicator"; + +FBIndicatorStyle::FBIndicatorStyle() : + TypeOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "Type", 0, 2, ZLTextPositionIndicatorInfo::OS_SCROLLBAR), + IsSensitiveOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "TouchSensitive", true), + ShowTextPositionOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "PositionText", false), + ShowTimeOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "Time", false), + ColorOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "Color", ZLColor(127, 127, 127)), + HeightOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "Height", 1, 100, 16), + OffsetOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "Offset", 0, 100, 3), + FontSizeOption(ZLCategoryKey::LOOK_AND_FEEL, INDICATOR, "FontSize", 4, 72, 14) { +} + +ZLTextPositionIndicatorInfo::Type FBIndicatorStyle::type() const { + return (ZLTextPositionIndicatorInfo::Type)TypeOption.value(); +} + +bool FBIndicatorStyle::isSensitive() const { + return IsSensitiveOption.value(); +} + +bool FBIndicatorStyle::isTextPositionShown() const { + return ShowTextPositionOption.value(); +} + +bool FBIndicatorStyle::isTimeShown() const { + return ShowTimeOption.value(); +} + +ZLColor FBIndicatorStyle::color() const { + return ColorOption.value(); +} + +int FBIndicatorStyle::height() const { + return HeightOption.value(); +} + +int FBIndicatorStyle::offset() const { + return OffsetOption.value(); +} + +int FBIndicatorStyle::fontSize() const { + return FontSizeOption.value(); +} + +shared_ptr<ZLTextPositionIndicatorInfo> FBView::ourIndicatorInfo; +shared_ptr<ZLBooleanOption> FBView::ourSelectionOption; + +FBIndicatorStyle& FBView::commonIndicatorInfo() { + if (ourIndicatorInfo.isNull()) { + ourIndicatorInfo = new FBIndicatorStyle(); + } + return (FBIndicatorStyle&)*ourIndicatorInfo; +} + +FBView::FBView(ZLPaintContext &context) : ZLTextView(context) { +} + +shared_ptr<ZLTextPositionIndicatorInfo> FBView::indicatorInfo() const { + if (ourIndicatorInfo.isNull()) { + ourIndicatorInfo = new FBIndicatorStyle(); + } + return ourIndicatorInfo; +} + +void FBView::doTapScrolling(int y) { + if (2 * y < context().height()) { + Reader::Instance().doAction(ActionCode::TAP_SCROLL_BACKWARD); + } else { + Reader::Instance().doAction(ActionCode::TAP_SCROLL_FORWARD); + } +} + +bool FBView::onFingerTap(int, int y) { + doTapScrolling(y); + return true; +} + +const std::string &FBView::caption() const { + return myCaption; +} + +void FBView::setCaption(const std::string &caption) { + myCaption = caption; + std::replace(myCaption.begin(), myCaption.end(), '\n', ' '); + std::replace(myCaption.begin(), myCaption.end(), '\r', ' '); + ZLUnicodeUtil::cleanUtf8String(myCaption); +} + +bool FBView::onStylusPress(int x, int y) { + if (!myTapScroller.isNull()) { + ZLTimeManager::Instance().removeTask(myTapScroller); + myTapScroller.reset(); + } + + myPressedX = x; + myPressedY = y; + myIsReleasedWithoutMotion = false; + + if (ZLTextView::onStylusPress(x, y)) { + return true; + } + + myIsReleasedWithoutMotion = true; + + if (_onStylusPress(x, y)) { + return true; + } + + return true; +} + +bool FBView::_onStylusPress(int, int) { + return false; +} + +class FBView::TapScroller : public ZLRunnable { + +public: + TapScroller(FBView &view, int y); + +private: + void run(); + +private: + FBView &myView; + const int myY; +}; + +FBView::TapScroller::TapScroller(FBView &view, int y) : myView(view), myY(y) { +} + +void FBView::TapScroller::run() { + myView.doTapScrolling(myY); +} + +bool FBView::onStylusRelease(int x, int y) { + const bool hadSelection = !selectionModel().isEmpty(); + + if (!myTapScroller.isNull()) { + ZLTimeManager::Instance().removeTask(myTapScroller); + myTapScroller.reset(); + } + + if (ZLTextView::onStylusRelease(x, y)) { + return true; + } + + if (_onStylusRelease(x, y)) { + return true; + } + + Reader &reader = Reader::Instance(); + myIsReleasedWithoutMotion = + myIsReleasedWithoutMotion && std::abs(x - pressedX()) <= 5 && std::abs(y - pressedY()) <= 5; + if (!hadSelection && isReleasedWithoutMotion() && + reader.EnableTapScrollingOption.value() && + (!ZLBooleanOption(ZLCategoryKey::EMPTY, ZLOption::PLATFORM_GROUP, ZLOption::FINGER_TAP_DETECTABLE, false).value() || + !reader.TapScrollingOnFingerOnlyOption.value())) { + myTapScroller = new TapScroller(*this, y); + ZLTimeManager::Instance().addAutoRemovableTask(myTapScroller, doubleClickDelay()); + return true; + } + + return false; +} + +bool FBView::_onStylusRelease(int, int) { + return false; +} + +bool FBView::onStylusMove(int x, int y) { + if (ZLTextView::onStylusMove(x, y)) { + return true; + } + + if (_onStylusMove(x, y)) { + return true; + } + + return false; +} + +bool FBView::_onStylusMove(int, int) { + return false; +} + +bool FBView::onStylusMovePressed(int x, int y) { + if (myIsReleasedWithoutMotion) { + if (std::abs(x - pressedX()) > 5 || std::abs(y - pressedY()) > 5) { + myIsReleasedWithoutMotion = false; + activateSelection(pressedX(), pressedY()); + } + } + + if (ZLTextView::onStylusMovePressed(x, y)) { + return true; + } + + if (_onStylusMovePressed(x, y)) { + return true; + } + + return false; +} + +bool FBView::_onStylusMovePressed(int, int) { + return false; +} + +std::string FBView::word(const ZLTextElementRectangle &rectangle) const { + std::string txt; + + if (rectangle.Kind == ZLTextElement::WORD_ELEMENT) { + ZLTextWordCursor cursor = textArea().startCursor(); + cursor.moveToParagraph(rectangle.ParagraphIndex); + cursor.moveTo(rectangle.ElementIndex, 0); + const ZLTextWord &word = (ZLTextWord&)cursor.element(); + ZLUnicodeUtil::Ucs4String ucs4; + ZLUnicodeUtil::utf8ToUcs4(ucs4, word.Data, word.Size); + ZLUnicodeUtil::Ucs4String::iterator it = ucs4.begin(); + while ((it != ucs4.end()) && !ZLUnicodeUtil::isLetter(*it)) { + ++it; + } + if (it != ucs4.end()) { + ucs4.erase(ucs4.begin(), it); + it = ucs4.end() - 1; + while (!ZLUnicodeUtil::isLetter(*it)) { + --it; + } + ucs4.erase(it + 1, ucs4.end()); + + ZLUnicodeUtil::ucs4ToUtf8(txt, ucs4); + } + } + return txt; +} + +int FBView::leftMargin() const { + return FBOptions::Instance().LeftMarginOption.value(); +} + +int FBView::rightMargin() const { + return FBOptions::Instance().RightMarginOption.value(); +} + +int FBView::topMargin() const { + return FBOptions::Instance().TopMarginOption.value(); +} + +int FBView::bottomMargin() const { + return FBOptions::Instance().BottomMarginOption.value(); +} + +ZLColor FBView::backgroundColor() const { + return FBOptions::Instance().BackgroundColorOption.value(); +} + +ZLColor FBView::color(const std::string &colorStyle) const { + return FBOptions::Instance().colorOption(colorStyle).value(); +} + +shared_ptr<ZLTextStyle> FBView::baseStyle() const { + return FBTextStyle::InstanceAsPtr(); +} + +ZLBooleanOption &FBView::selectionOption() { + if (ourSelectionOption.isNull()) { + ourSelectionOption = new ZLBooleanOption(ZLCategoryKey::LOOK_AND_FEEL, "Options", "IsSelectionEnabled", true); + } + return *ourSelectionOption; +} + +bool FBView::isSelectionEnabled() const { + return selectionOption().value(); +} + +int FBView::doubleClickDelay() const { + return isSelectionEnabled() ? 200 : 0; +} + +bool FBView::hasContents() const { + return true; +} diff --git a/reader/src/reader/View.h b/reader/src/reader/View.h new file mode 100644 index 0000000..368b6b8 --- /dev/null +++ b/reader/src/reader/View.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBVIEW_H__ +#define __FBVIEW_H__ + +#include <ZLTextView.h> +#include <ZLTextStyle.h> +#include <ZLRunnable.h> + +class FBIndicatorStyle : public ZLTextPositionIndicatorInfo { + +public: + ZLIntegerRangeOption TypeOption; + ZLBooleanOption IsSensitiveOption; + ZLBooleanOption ShowTextPositionOption; + ZLBooleanOption ShowTimeOption; + ZLColorOption ColorOption; + ZLIntegerRangeOption HeightOption; + ZLIntegerRangeOption OffsetOption; + ZLIntegerRangeOption FontSizeOption; + +public: + FBIndicatorStyle(); + + Type type() const; + bool isSensitive() const; + bool isTextPositionShown() const; + bool isTimeShown() const; + ZLColor color() const; + int height() const; + int offset() const; + int fontSize() const; +}; + +class FBView : public ZLTextView { + +private: + class TapScroller; + +public: + static FBIndicatorStyle& commonIndicatorInfo(); + static ZLBooleanOption &selectionOption(); + + virtual bool hasContents() const; + +private: + static shared_ptr<ZLTextPositionIndicatorInfo> ourIndicatorInfo; + static shared_ptr<ZLBooleanOption> ourSelectionOption; + +protected: + void doTapScrolling(int y); + +public: + FBView(ZLPaintContext &context); + + void setCaption(const std::string &caption); + +private: + bool onFingerTap(int x, int y); + + const std::string &caption() const; + + int leftMargin() const; + int rightMargin() const; + int topMargin() const; + int bottomMargin() const; + ZLColor backgroundColor() const; + ZLColor color(const std::string &colorStyle) const; + shared_ptr<ZLTextStyle> baseStyle() const; + + bool isSelectionEnabled() const; + int doubleClickDelay() const; + +protected: + bool onStylusPress(int x, int y); + virtual bool _onStylusPress(int x, int y); + bool onStylusRelease(int x, int y); + virtual bool _onStylusRelease(int x, int y); + bool onStylusMove(int x, int y); + virtual bool _onStylusMove(int x, int y); + bool onStylusMovePressed(int x, int y); + virtual bool _onStylusMovePressed(int x, int y); + + int pressedX() const; + int pressedY() const; + bool isReleasedWithoutMotion() const; + + std::string word(const ZLTextElementRectangle &rectangle) const; + + shared_ptr<ZLTextPositionIndicatorInfo> indicatorInfo() const; + +private: + std::string myCaption; + + int myPressedX; + int myPressedY; + bool myIsReleasedWithoutMotion; + + shared_ptr<ZLRunnable> myTapScroller; +}; + +inline int FBView::pressedX() const { return myPressedX; } +inline int FBView::pressedY() const { return myPressedY; } +inline bool FBView::isReleasedWithoutMotion() const { return myIsReleasedWithoutMotion; } + +#endif /* __FBVIEW_H__ */ diff --git a/reader/src/reader/main.cpp b/reader/src/reader/main.cpp new file mode 100644 index 0000000..967c068 --- /dev/null +++ b/reader/src/reader/main.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> + +#include "Reader.h" + +int main(int argc, char **argv) { + if (!ZLibrary::init(argc, argv)) { + return 1; + } + ZLibrary::run(new Reader(argc == 1 ? std::string() : argv[1])); + ZLibrary::shutdown(); + return 0; +} diff --git a/reader/src/tree/FBTree.cpp b/reader/src/tree/FBTree.cpp new file mode 100644 index 0000000..25e0bb3 --- /dev/null +++ b/reader/src/tree/FBTree.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#include <ZLibrary.h> +#include <ZLFileImage.h> +#include <ZLResource.h> +#include <ZLTreeListener.h> + +#include "FBTree.h" + +const ZLTypeId FBTree::TYPE_ID(ZLTreeTitledNode::TYPE_ID); + +const ZLTypeId &FBTree::typeId() const { + return TYPE_ID; +} + +std::map<std::string,shared_ptr<const ZLImage> > FBTree::ourDefaultCovers; +std::map<std::string,std::string> FBTree::ourDefaultUrls; + +// is there already any implementation of this stuff anywhere? +//TODO move it to some Utils class +static char hex_helper(int c) { + static char tmp[] = "0123456789ABCDEF"; + return tmp[c]; +} + +static std::string percent_encoding(const std::string &str) { + std::string result; + for (std::size_t i = 0; i < str.size(); ++i) { + const char c = str[i]; + if (str[i] == '\\' || str[i] == '/') { + result += '/'; + } else if (std::isalpha(c) || std::isdigit(c) || c == '.' || c == '-' || c == '_' || c == '~') { + result += str[i]; + } else { + result += "%"; + result += hex_helper((c & 0xf0) >> 4); + result += hex_helper(c & 0x0f); + } + } + return result; +} + +//TODO maybe use just one expand action? +class FBTree::ExpandTreeAction : public ZLTreeAction { + +public: + ExpandTreeAction(FBTree &node); + void run(); + ZLResourceKey key() const; + +private: + FBTree &myNode; +}; + +FBTree::ExpandTreeAction::ExpandTreeAction(FBTree &node) : myNode(node) { +} + +void FBTree::ExpandTreeAction::run() { + myNode.expand(); +} + +ZLResourceKey FBTree::ExpandTreeAction::key() const { + return ZLResourceKey("expandTree"); +} + +shared_ptr<const ZLImage> FBTree::defaultCoverImage(const std::string &id) { + shared_ptr<const ZLImage> cover = ourDefaultCovers[id]; + if (cover.isNull()) { + cover = new ZLFileImage( + ZLFile(ZLibrary::ApplicationImageDirectory() + ZLibrary::FileNameDelimiter + id), 0 + ); + ourDefaultCovers[id] = cover; + } + return cover; +} + +//std::string FBTree::defaultImageUrl(const std::string &id) { +// std::string &url = ourDefaultUrls[id]; +// if (url.empty()) { +// url = ZLibrary::ApplicationImageDirectory(); +// url += "/"; +// url += id; +// url = LOCALFILE_SCHEME + SCHEME_POSTFIX + percent_encoding(url); +// } +// return url; +//} + +void FBTree::expand() { + if (ZLTreeListener *handler = listener()) { + handler->onExpandRequest(this); + } +} + +FBTree::FBTree(ZLTreeNode *parent, std::size_t position) : ZLTreeTitledNode(parent, position)/*, myCoverImageIsStored(false)*/ { } + +std::string FBTree::subtitle() const { + std::string result; + int count = 0; + const ZLTreeNode::List &subNodes = children(); + ZLTreeNode::List::const_iterator it = subNodes.begin(); + for (; it != subNodes.end() && count < 3; ++it, ++count) { + if (count > 0) { + result += ", "; + } + result += ((const FBTree*)*it)->title(); + } + if (it != subNodes.end()) { + result += ", ..."; + } + return result; +} + +void FBTree::registerExpandTreeAction() { + registerAction(new ExpandTreeAction(*this)); +} + +//shared_ptr<const ZLImage> FBTree::coverImage() const { +// if (!myCoverImageIsStored) { +// myCoverImageIsStored = true; +// myStoredCoverImage = image(); +// } +// return myStoredCoverImage; +//} + + diff --git a/reader/src/tree/FBTree.h b/reader/src/tree/FBTree.h new file mode 100644 index 0000000..e0efb38 --- /dev/null +++ b/reader/src/tree/FBTree.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * 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. + */ + +#ifndef __FBTREE_H__ +#define __FBTREE_H__ + +#include <ZLTreeTitledNode.h> + +class FBTree : public ZLTreeTitledNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +private: + class ExpandTreeAction; + +public: + static shared_ptr<const ZLImage> defaultCoverImage(const std::string &id); + //static std::string defaultImageUrl(const std::string &id); + +public: //TODO make protected + void expand(); + +private: + static std::map<std::string,shared_ptr<const ZLImage> > ourDefaultCovers; + static std::map<std::string,std::string> ourDefaultUrls; + +public: + FBTree(ZLTreeNode *parent, std::size_t position = (std::size_t)-1); +// shared_ptr<const ZLImage> coverImage() const; + std::string subtitle() const; + +protected: + void registerExpandTreeAction(); + +private: +// mutable bool myCoverImageIsStored; +// mutable shared_ptr<const ZLImage> myStoredCoverImage; +}; + + + + + +#endif /* __FBTREE_H__ */ |
