diff --git a/source/COPYING.TXT b/source/COPYING.TXT new file mode 100644 index 0000000..d18617e --- /dev/null +++ b/source/COPYING.TXT @@ -0,0 +1,460 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + diff --git a/source/distro/COPYING.TXT b/source/distro/COPYING.TXT new file mode 100644 index 0000000..101dfa2 --- /dev/null +++ b/source/distro/COPYING.TXT @@ -0,0 +1,460 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + diff --git a/source/distro/History.txt b/source/distro/History.txt new file mode 100644 index 0000000..e80ec69 --- /dev/null +++ b/source/distro/History.txt @@ -0,0 +1,121 @@ +Version history for Writer2LaTeX +================================ + +Version 0.9.4 (February 2009) + -Filters: + - Changed to oxt format and separated into Writer2LaTeX and Writer2xhtml extensions + - Added (localized) dialogs to the filters + - LaTeX: + - Export vector graphics to pdf for use with pdfTeX. + - Support equations generated by OOoLaTeX. + - XHTML: + - Improved navigation features for splitted documents + - Do not export hidden or filtered rows and columns. Apply print ranges. + - Improved batch conversion + - General: + - Export images to a subdirectory. + +Version 0.5 (June 2007) + - LaTeX: + - support fancyhdr.sty + - support geometry.sty + - support supertabular.sty + - support tabulary.sty + - support colortbl.sty + - support l, c, r columns in tables + - support floating figures and tables + - some graphics improvements + - custom tabstop handling + - flexible handling of notes (ignore, comment, marginpar, pdf annotation) + - string replace (eg. LaTeX -> \LaTeX) + - XHTML: + - convert an entire directory with index page(s) + - convert using a template document + - support html forms + - custom tabstop handling + - support continued lists + - improved export of table formatting + - support background images + - improved table of contents + - General: + - support OpenDocument + - now installable as uno package (extension) + - no longer using the XMerge framework + +Version 0.4 (July 2005) + - LaTeX: + - improved readability of output (wrap long lines, do not include unused + labels and hypertargets) + - support for more languages + - writer.sty is replaced by the optional package ooomath.sty + - color.sty is now optional + - new options to ignore hard page and line breaks + - new option to ignore double spaces + - new option to specify that the document is *not* multilingual + - support for cp1251 (Windows cyrillic) and latin2 inputenc + - improved style maps for paragraphs (avoid line break, verbatim content) + - cleaned up configuration of formatting + - improved export of list formatting + - support for other documentclasses than article + - support for lastpage.sty + - support for eurosym.sty + - support for tipa.sty + - support for various 8-bit fonts: Wingdings, Windows Symbol + - support for OpenSymbol + - XHTML: + - converts units to px (default) + - Calc2xhtml added + - improved support for table formatting; table formatting is now always + exported + - (partial) bidi support + - support for sections (margins and background color) + - new option to scale column widths + - new options to ignore double spaces, hard line breaks and empty paragraphs + - General + - Added ant build file (provided by Michael Niedermair) + - Now possible to specify output path+file name on command line + - removed usage of document specific configuration files (*-config.xml) + - new option to create user configuration automatically + +Version 0.3.2 (February 2004) + - LaTeX: + - support for custom math symbols (%symbol) + - improved handling of paragraph formatting + - support for table borders + - support for alphabetical index + - support for pdf meta data + - XHTML: + - support for three different XHTML variants + - long documents can be split in several XHTML documents + - support for custom style sheets + - more flexible handling of fomatting + - support for most XHTML elements (including blockquote, dl, hr) + - support for alphabetical index + - support for meta data + +Version 0.3 (October 2003) + - support for BibTeX + - support for greek and russian text + - support for more languages + - support for latin1, cp1250, iso-8859-7, koi8-r and utf8 (Dominique + Unruh's ucs.sty) inputencodings + - support for symbol fonts: pifont.sty, wasysym.sty, ifsym.sty and + bbding.sty + - support for ulem.sty (underline/cross out) + - export of footnotes configuration, list label styles, heading + styles and hard paragraph formatting can be disabled + - custom export of list styles + - bugfixes + +Version 0.2 (March 2003) + - support for tables + - support for graphics + - support for outline numbering and list styles + - support for page styles + - support for sections (columns) + - custom export of text and paragraph styles + - integration with xmerge (enables use as export filter) + - export to XHTML + MathML + +Version 0.1 (September 2002) + - first simple version \ No newline at end of file diff --git a/source/distro/Readme.txt b/source/distro/Readme.txt new file mode 100644 index 0000000..f87afdd --- /dev/null +++ b/source/distro/Readme.txt @@ -0,0 +1,18 @@ +Writer2LaTeX version 0.9.4 +========================== + +This is the distribution of Writer2LaTeX version 0.9.4 + +Latest version can be found at the web site + http://writer2latex.sourceforge.net + +You can read about installation and usage of Writer2LaTeX +in the user guide, which is included in the +directory doc. + +Bugs and feature requests should be reported to + henrikjust (at) openoffice.org + + +February 2009 +Henrik Just diff --git a/source/distro/changelog.txt b/source/distro/changelog.txt new file mode 100644 index 0000000..25b4bcf --- /dev/null +++ b/source/distro/changelog.txt @@ -0,0 +1,325 @@ +Changelog for Writer2LaTeX version 0.5 -> 1.0 + +---------- version 1.0 beta ---------- + +[w2l] Bugfix: Fixed crash for tables with fewer columns than rows + +---------- version 0.9.4 ----------- + +[w2l] Added sample LaTeX configuration for Google Docs from Elefterios Stamatogiannakis + +[w2x] Added MathML named entites table from Bruno Mascret + +[all] Bugfix: Locked controls are now updated correctly when the dialog is displayed + +[w2l] New backed xetex (initial prototype) + +[c2x] Bugfix: Corrected wrong calculation of column number for columns with two letters + (affected apply_print_ranges=true) + +[c2x] Bugfix: Ensure that we always export a document, even if there are no defined + print ranges (affected apply_print_ranges=true) + +[c2x] Bugfix: Now also exports uplink for spreadsheets + +[w2l] Bugfix: No longer incorrectly assume math mode when exporting plain text + +[all] Added support for the new Writer notes/annotations (which now can contain several + formatted paragraphs rather than a single, plain text paragraph) + +[all] Added russian and ukrainian translations from Volodymyr Volkov + +[all] Bugfix: Removed PreferredFilter propery from type definitions (makes sense + only for import filters) + +[all] Changed unix startscript: By default assume that w2l and writer2latex are + in the same directory (thus using dirname $0), and assume that the java executable + is either in the PATH or the location is defined by JAVA_HOME + (which these assumptions manual editing of the script is usually not required) + +[all] Added french translation from Jacques Lamoine + +[w2l] The option simple_table_limit now refers to the *total* width of the table + measured in characters rather than the width of individual cells + +[w2x] Bugfix: The position and dimensions of a frame is now calculated correctly + (previously the size of margins, borders and padding was not taken into account) + +[w2l] The inputencoding utf8 now uses the LaTeX standard rather than ucs.sty + (which only supports latin and cyrillic alphabets) + +[w2l] New style map family "text-attribute" to map text formatting to LaTeX code + currently only the values "bold", "italic", "small-caps", "subscript" and + "superscript" are supported, and the verbatim attribute is not supported + +---------- version 0.9.3 ----------- + +[all] All source files are now US ASCII; added encoding of source files to build file + +[all] Added more File-based methods to the API + +[w2l] The paper sizes defined by standard LaTeX document classes are now + identified and added as global options (a4paper, a5paper, b5paper, + letterpaper, legalpaper, executivepaper, including landscape variants) + +[w2x] Bugfix: Now only exports the name of a text box if it actually exists! + +[w2l] Removed option "pagecolor" from \hypersetup (this option has been removed + from the hyperref package) + +[all] Filter bugfix: The new option name "ConfigURL" is now used in the dialogs + +[all] Added (partial) german localization from Martin Friedrich + +[w2x] New option use_named_entities: When set to true, named character entities + as defined in xhtml 1.0 are used (currently only those within ISO latin 1) + +[w2x] Characters not supported by the encoding are now exported as numeric + character entities + +[w2x] Bugfix: Internal hyperlinks to tables, sections, frames and graphics now + works correctly + +[w2x] Bugfix: Subtables are no longer exported with an id attribute + +[all] Bugfix: table:number-rows-repeated is now treated correctly + +[c2x] New option: apply_print_ranges + +---------- version 0.9.2 ----------- + +[c2x] No longer exports
for tables without + +[all] Renamed "class" to "family" in style maps to avoid confusion + with css classes (old name is still accepted) + +[all] Filter: Renamed template and config options to the more + descriptive TemplateURL and ConfigURL + +[all] API: Added convenience method convert(File) to Converterer + +[all] API: Added convenience method write(File) to ConverterResult + +[all] New option: save_images_in_subdir + +[all] Use Robert Harders public domain Base64 decoder (replacing + the non-standard decoder in sun.misc) + +[all] MIMETypes used in the API are now defined in writer2latex.api.MIMETypes + +[all] Renamed the option keep_image_size to original_image_size (the meaning of + this option was confusing). The old name is still recognized. + +[all] OOo now saves SVM files with a MIME type in the package format. + This is now recognized by w2l, which implies that GraphicConverter + implementations can use SVM files from a package + +[w2x] New uno service org.openoffice.da.writer2xhtml.BatchConverter + provides batch conversion via uno. Interaction with the user can be implemented + using the interface org.openoffice.da.writer2xhtml.XBatchHandler + +[w2x] Batch processing from the command line can now be cancelled (using the Enter key) + +[all] API: Created new API for batch conversion + +[w2l] Bugfix: Tables were in rare cases exported with invalid row alignment + (null character) + +[w2x] Filter ui bugfix: Default value for RepeatLevels changed from + 6 to 5 (6 was not valid) + +[w2x] Filter: The xhtml export now uses it's own custom configuration + (writer2xhtml.xml, also stored in the user configuration of OOo) + +[w2l] Tabstops are now exported as \ \ , which usually is closer to + the expectations of the user (and is not ignored at the beginning of a par.) + +[w2x] Empty paragraphs are now (again!) exported with a + (otherwise they are ignored by the browser) + +[w2x] Xhtml specific options no longer starts with the prefix xhtml_ + (is still accepted for backwards compatibility) + +[all] Filter: Added display name and description to the extensions + +[w2x] BatchConverter: Localized alternative text for icons + +[w2b] Bugfix: Replace ";" with "and" also in in editor field + +[w2x] Added new options xslt_path to give the path to the XSL + transformation from w3c (also in the ui) + +[all] Filter: Optimized the size of the extensions by excluding code not + relevant for the format(s) supported by the extension + +[all] Separated LaTeX and xhtml code. As a consequence, it is possible to build + and run Writer2LaTeX with support for only one format + +[c2x] New options display_hiddens_rows_cols and display_filtered_rows_cols. If + set to false (default), rows and columns that are hidden or filtered are not + exported + +[all] Filter: Translated dialogs to Danish + +[all] Filter: Raised requirement in description.xml to OOo 2.2 + (needs support for localized dialogs) + +[w2l] Added ui option "Support additional symbols". This sets all the + options use_pifont, use_ifsym, use_wasysym, use_eurosym and use_tipa. + The pseudo-option additional_symbols can be used in the LockedOptions list + +[all] Bugfix: The class w2l.xmerge.DOMDocument did not throw IOException when + trying to read a non-xml document + +[w2x] Bugfix: The convert method did not restart document enumeration + (relevant if it's called several times for the same converter instance) + +[w2x] API: Created new API for batch conversion, which is also moved + from Application to a separate class + +[all] API: The API now uses a interface to the configuration rather than using + the class writer2latex.util.Config + +[w2x] Style of header/footer in index pages (batch conversion) aligned with + document header/footer + +[all] Added package descriptions to the javadoc + +[w2l] Always export non-breaking space as ~ even if inputenc supports it + directly - non-breaking spaces are usually not easy to identify in text editors + +---------- version 0.9.1 ----------- + +[w2x] New option: xhtml_add_bom (default false), if set to true + a BOM will be added at the start of generated xhtml files + +[w2x] Fixed typo in filter name: XHTML 1.0 + MathML 2.0 should be + XHTML 1.1 + MathML 2.0 + +[w2l] Added support for the latin language + +[w2l] Removed article.xml from w2l - it now belongs to Writer4LaTeX + +[all] The distribution now includes a sample configuration + package: xhtml-config-sample.oxt + +[all] Filter: Split the filter component into two extensions: + writer2latex.oxt for LaTeX and BibTeX, writer2xhtml.oxt for xhtml + The build file now produces optimized jars for each application, and the + standalone jar does not contain any uno code + +[w2l] Added (imcomplete) support for some of the Euclid fonts from Design Science + +[w2b] Replace ";" with "and" in author field (multiple authors) + +[w2l] Added support for formulas inserted by OOoLaTeX + +[w2x] Now adds mini-toc to the element with id "panel" if it exists in the xhtml + template + +[w2l] API: Added new api for standalone StarMath converter + Writer2LaTeX api: writer2latex.api.StarMathConverter + Uno service: org.openoffice.da.writer2latex.StarMathConverter + +[all] Filter: Added dialogs to all filters (w2l, w2x and c2x) + +[w2l] Vector graphics (except wmf) is now exported as pdf if backend is pdftex + +[all] API: In the GraphicConverter interface, the method + supportsFormat has been replaced with the method supportsConversion + +[w2l] Added support for *numbered* display equations: If paragraph + contains exactly one equation and exactly one sequence field (and otherwise + only whitespace and brackets), it treated as a numbered equation + +[w2l] I18n: If several characters in a row are converted using math mode, they + are now combined (ie. ${\alpha}{\beta}$ rather than ${\alpha}$${\beta}$) + +[all] Extended FilterData to support the property AutoCreate. If set to true, + the configuration file will be created if it does not exist + +[w2l] Even if formatting=IGNORE_ALL, we should still obey character style maps + from the configuration + +[w2x] Added german translation of navigation pane (w2l.util.L10n) + +[all] Bugfix: A paragraph with a bibliographic reference as the only + content was considered empty (and the reference was lost) + +[w2l] Use url decoding when creating file names for linked sections + (in order to obtain more readable file names) + +[w2l] Avoid redundant \mathit in StarMathConverter in some rare + cases (such as greek letters pasted into Math) + +[w2l] Support formulas for sequence fields (only the most common + cases oow:Name, oow:Name+Number, oow:Name-Number and oow:Number) + +[c2x] New options xhtml_display_hidden_sheets, xhtml_use_title_as_heading and + xhtml_use_sheet_names_as_headings + +[o2x] New option xhtml_notes. If true notes (annotations) are exported to xhtml + comments, if false they are ignored + +[c2x] Convert notes (annotations) + +[w2l] Heading formatting: The prefix and suffix to the counter should not be + included in \thesection, but rather in the formatting. This means that the + prefix and suffix no longer will be exported if formatting=CONVERT_BASIC + +[w2l] Added support for chapter references to reference marks and bookmarks + (if the marks are contained in a heading) + +[w2l] New option external_bibtex_files gives a list of BibTeX files. If nonempty, + these files will be used instead of converting the actual bibliography marks + +[w2l] New option metadata. If true, export metadata as \author, + \date and pdf metadata, as well as pdf metadata (if use_hyperref is true) + +[all] Filters/API: Changed filternames to the more obvious + org.openoffice.da.writer2latex etc. + +[w2l] Updated clean.xml and ultraclean.xml. Both configurations + now exports predefined Writer styles (like article.xml) + +[w2x] New option: xhtml_repeat_levels defines the number of heading + levels to repeat when splitting a file (0 means no levels are repeated) + +[w2x] Allow xhtml templates without header and footer elements + +[w2x] Bugfix (w2l.office.ListCounter): OpenDocument does not use + numberings like 1.0.1 if a list level is missing, but rather 1.1.1 + +[all] Command line application now uses internal standard configurations + (*ultraclean.xml etc.) + +[all] Command line application now accepts several configuration + files (by using the -config option more than once) + +[w2x] Use text style for label when applying numbering to heading + +[w2x] Added support for other list styes applied to headings + +[w2x] Added support for text:restart-numbering, text:is-list-header on headings + +[w2x] No longer add hr and [] to links in navigation (the template and style + sheet should take care of this) + +[all] New filter configuration concept: Configuration packages containing an OOo + template, a w2l configuration and registry information to bind these together: + When a configuration package is installed in OOo, the configuration is added + to the filter ui, and is preselected for documents based on the OOo template + +[all] Repackaging: Distribution files are included in source, build + file is extended to create the distribution; source distribution is separated + +[all] Changed to new extension format (.oxt) + +[all] Filter: Added messagebox to display the error in case an + exception happens during conversion + +[all] Moved default configurations to jar; the FilterData property + can refer to these using the special url *filename.xml + +[all] The filter now reads the FilterData property, which can be + used to specify options, configuration fil (url) and xhtml template (url) \ No newline at end of file diff --git a/source/distro/doc/user-manual.odt b/source/distro/doc/user-manual.odt new file mode 100644 index 0000000..2efa35c Binary files /dev/null and b/source/distro/doc/user-manual.odt differ diff --git a/source/distro/doc/w2llogo.png b/source/distro/doc/w2llogo.png new file mode 100644 index 0000000..990bc7c Binary files /dev/null and b/source/distro/doc/w2llogo.png differ diff --git a/source/distro/latex/obsolete/writer.sty b/source/distro/latex/obsolete/writer.sty new file mode 100644 index 0000000..ed8e7cd --- /dev/null +++ b/source/distro/latex/obsolete/writer.sty @@ -0,0 +1,83 @@ +%% File: ooomath.sty, Copyright (C) 2002-2004 Henrik Just +%% +%% This file may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.2 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.2 or later is part of all distributions of LaTeX +%% version 1999/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{ooomath}[2004/08/08 v1.0 - stylefile used by Writer2LaTeX] + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Some math mode macros defining additional symbols +% \ddotsup is taken from "The comprehensive LaTeX symbol list" +\newcommand\defeq{\stackrel{\mathrm{def}}{=}} +\newcommand\lambdabar{\mathchar'26\mkern-10mu\lambda} +\newcommand\ddotsup{\mathinner{\mkern1mu\raise\p@\vbox{\kern7\p@\hbox{.}}\mkern2mu\raise4\p@\hbox{.}\mkern2mu\raise7\p@ +\hbox{.}\mkern1mu}} +% Fallback definitions for math mode macros defined in other packages +\providecommand\multimapdotbothA{\bullet\kern-0.4em-\kern-0.4em\circ} +\providecommand\multimapdotbothB{\circ\kern-0.4em-\kern-0.4em\bullet} +\providecommand\oiint{\oint} % should be area integral... +\providecommand\oiiint{\oint} % should be volume integral... +\providecommand\llbracket{[} % should be double... +\providecommand\rrbracket{]} % should be double... +% More math mode macros +\newcommand\wideslash[2]{{}^{#1}/_{#2}} % too small +\newcommand\widebslash[2]{{}_{#1}\backslash^{#2}} % too small +\newcommand\normalsubformula[1]{\text{$#1$}} +\newcommand\boldsubformula[1]{\text{\mathversion{bold}$#1$}} +% Multiscripts, based on leftidx.sty by Harald Harders +\newlength{\idxmathdepth} +\newlength{\idxmathtotal} +\newlength{\idxmathwidth} +\newlength{\idxraiseme} +% +\newcommand{\idxdheight}[1]{% +\protect\settoheight{\idxmathtotal}{\(\displaystyle#1\)}% +\protect\settodepth{\idxmathdepth}{\(\displaystyle#1\)}% +\protect\settowidth{\idxmathwidth}{\(\displaystyle#1\)}% +\protect\addtolength{\idxmathtotal}{\idxmathdepth}% +\protect\setlength{\idxraiseme}{\idxmathtotal/2-\idxmathdepth}} +\newcommand{\idxtheight}[1]{% +\protect\settoheight{\idxmathtotal}{\(\textstyle #1\)}% +\protect\settodepth{\idxmathdepth}{\(\textstyle #1\)}% +\protect\settowidth{\idxmathwidth}{\(\textstyle#1\)}% +\protect\addtolength{\idxmathtotal}{\idxmathdepth}% +\protect\setlength{\idxraiseme}{\idxmathtotal/2-\idxmathdepth}} +\newcommand{\idxsheight}[1]{% +\protect\settoheight{\idxmathtotal}{\(\scriptstyle #1\)}% +\protect\settodepth{\idxmathdepth}{\(\scriptstyle #1\)}% +\protect\settowidth{\idxmathwidth}{\(\scriptstyle#1\)}% +\protect\addtolength{\idxmathtotal}{\idxmathdepth}% +\protect\setlength{\idxraiseme}{\idxmathtotal/2-\idxmathdepth}} +\newcommand{\idxssheight}[1]{% +\protect\settoheight{\idxmathtotal}{\(\scriptscriptstyle #1\)}% +\protect\settodepth{\idxmathdepth}{\(\scriptscriptstyle #1\)}% +\protect\settowidth{\idxmathwidth}{\(\scriptscriptstyle#1\)}% +\protect\addtolength{\idxmathtotal}{\idxmathdepth}% +\protect\setlength{\idxraiseme}{\idxmathtotal/2-\idxmathdepth}} +% \multiscripts{
+ |
+ |
This is a java-uno adapter class which implements XStream using a + * byte array. (We need this because XGraphicProvider demans read/write access + * when storing a graphic to a stream.)
+ */ +public class ByteArrayXStream implements XInputStream, XOutputStream, XSeekable, XStream { + + // Keep data about our byte array (we read and write to the same byte array) + + private int initialSize = 100240; // 10 kb + private int size = 0; // The current buffer size + private int position = 0; // The current write position, always<=size + private int readPosition = 0; // The current read position, always<=position + private boolean closed = false; // The XStream is closed + private byte[] buffer; // The buffer + + // Constructor: Initialize the byte array + + public ByteArrayXStream() { + size = initialSize; + buffer = new byte[size]; + } + + // Implementation of XOutputStream + + public void closeOutput() + throws com.sun.star.io.NotConnectedException, + com.sun.star.io.BufferSizeExceededException, + com.sun.star.io.IOException { + + // trim buffer + if ( buffer.length > position) { + byte[] newBuffer = new byte[position]; + System.arraycopy(buffer, 0, newBuffer, 0, position); + buffer = newBuffer; + } + closed = true; + } + + public void flush() + throws com.sun.star.io.NotConnectedException, + com.sun.star.io.BufferSizeExceededException, + com.sun.star.io.IOException { + } + + public void writeBytes(byte[] values) + throws com.sun.star.io.NotConnectedException, + com.sun.star.io.BufferSizeExceededException, + com.sun.star.io.IOException { + if ( values.length > size-position ) { + byte[] newBuffer = null; + while ( values.length > size-position ) + size *= 2; + newBuffer = new byte[size]; + System.arraycopy(buffer, 0, newBuffer, 0, position); + buffer = newBuffer; + } + System.arraycopy(values, 0, buffer, position, values.length); + position += values.length; + } + + // Implementation of XInputStream + + private void _check() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException { + if(closed) { + throw new com.sun.star.io.IOException("input closed"); + } + } + + public int available() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException { + _check(); + return position - readPosition; + } + + public void closeInput() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException { + closed = true; + } + + public int readBytes(byte[][] values, int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException { + _check(); + try { + int remain = (int)(position - readPosition); + if (param > remain) param = remain; + /* ARGH!!! */ + if (values[0] == null){ + values[0] = new byte[param]; + // System.err.println("allocated new buffer of "+param+" bytes"); + } + System.arraycopy(buffer, readPosition, values[0], 0, param); + // System.err.println("readbytes() -> "+param); + readPosition += param; + return param; + } catch (ArrayIndexOutOfBoundsException ae) { + // System.err.println("readbytes() -> ArrayIndexOutOfBounds"); + ae.printStackTrace(); + throw new com.sun.star.io.BufferSizeExceededException("buffer overflow"); + } catch (Exception e) { + // System.err.println("readbytes() -> Exception: "+e.getMessage()); + e.printStackTrace(); + throw new com.sun.star.io.IOException("error accessing buffer"); + } + } + + public int readSomeBytes(byte[][] values, int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException { + // System.err.println("readSomebytes()"); + return readBytes(values, param); + } + + public void skipBytes(int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException { + // System.err.println("skipBytes("+param+")"); + _check(); + if (param > (position - readPosition)) + throw new com.sun.star.io.BufferSizeExceededException("buffer overflow"); + readPosition += param; + } + + + // Implementation of XSeekable + + public long getLength() throws com.sun.star.io.IOException { + // System.err.println("getLength() -> "+m_length); + if (buffer != null) return position; + else throw new com.sun.star.io.IOException("no bytes"); + } + + public long getPosition() throws com.sun.star.io.IOException { + // System.err.println("getPosition() -> "+m_pos); + if (buffer != null) return readPosition; + else throw new com.sun.star.io.IOException("no bytes"); + } + + public void seek(long param) throws com.sun.star.lang.IllegalArgumentException, com.sun.star.io.IOException { + // System.err.println("seek("+param+")"); + if (buffer != null) { + if (param < 0 || param > position) throw new com.sun.star.lang.IllegalArgumentException("invalid seek position"); + else readPosition = (int)param; + } else throw new com.sun.star.io.IOException("no bytes"); + } + + // Implementation of XStream + public XInputStream getInputStream() { return this; } + + public XOutputStream getOutputStream() { return this; } + + // Get the buffer + public byte[] getBuffer() { return buffer; } + +} + diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java new file mode 100644 index 0000000..3899deb --- /dev/null +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java @@ -0,0 +1,504 @@ +/************************************************************************ + * + * ExportFilterBase.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-24) + * + */ + +// This file was originally based on OOo's XMergeBridge, which is (c) by Sun Microsystems + +package org.openoffice.da.comp.w2lcommon.filter; + +import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter; +import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter; + +//import com.sun.star.beans.PropertyValue; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.lang.XServiceName; +import com.sun.star.lang.XTypeProvider; +import com.sun.star.uno.AnyConverter; +import com.sun.star.ucb.XSimpleFileAccess2; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +//import com.sun.star.xml.sax.InputSource; +//import com.sun.star.xml.sax.XParser; +import com.sun.star.xml.sax.XDocumentHandler; +import com.sun.star.xml.XExportFilter; + +import org.openoffice.da.comp.w2lcommon.helper.MessageBox; +//import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper; +import writer2latex.api.Converter; +import writer2latex.api.ConverterFactory; +import writer2latex.api.ConverterResult; +import writer2latex.api.OutputFile; + +import java.util.Iterator; +//import java.util.Enumeration; +//import java.util.Vector; +import java.io.*; +//import javax.xml.parsers.*; +//import org.xml.sax.SAXException; +//import java.net.URI; + + +/** This class provides an abstract uno component which implements an XExportFilter. + * The filter is actually generic and only then constructor and 3 strings needs + * to changed by the subclass. + */ +public abstract class ExportFilterBase implements + XExportFilter, + XServiceName, + XServiceInfo, + XDocumentHandler, + XTypeProvider { + + /** Service name for the component */ + public static final String __serviceName = ""; + + /** Implementation name for the component */ + public static final String __implementationName = ""; + + /** Filter name to include in error messages */ + public static final String __displayName = ""; + + private static XComponentContext xComponentContext = null; + protected static XMultiServiceFactory xMSF; + private static XInputStream xInStream =null; + private static XOutputStream xOutStream=null; + private static XOutputStream xos = null; + private static String sdMime=null; + private static String sURL=""; + + private Object filterData; + private XSimpleFileAccess2 sfa2; + + + /** We need to get the Service Manager from the Component context to + * instantiate certain services, hence this constructor. + * The subclass must override this to set xMSF properly from the reigstration class + */ + public ExportFilterBase(XComponentContext xComponentContext1) { + xComponentContext = xComponentContext1; + xMSF = null; + } + + + // Some utility methods: + + String getFileName(String origName) { + String name=null; + if (origName !=null) { + if(origName.equalsIgnoreCase("")) + name = "OutFile"; + else { + if (origName.lastIndexOf("/")>=0) { + origName=origName.substring(origName.lastIndexOf("/")+1,origName.length()); + } + if (origName.lastIndexOf(".")>=0) { + name = origName.substring(0,(origName.lastIndexOf("."))); + } + else { + name=origName; + } + } + } + else{ + name = "OutFile"; + } + + return name; + } + + public String replace(String origString, String origChar, String replaceChar){ + String tmp=""; + int index=origString.indexOf(origChar); + if(index !=-1){ + while (index !=-1){ + String first =origString.substring(0,index); + first=first.concat(replaceChar); + tmp=tmp.concat(first); + origString=origString.substring(index+1,origString.length()); + index=origString.indexOf(origChar); + if(index==-1) { + tmp=tmp.concat(origString); + } + } + } + return tmp; + } + + public String needsMask(String origString) { + if (origString.indexOf("&")!=-1){ + origString=replace(origString,"&","&"); + } + if (origString.indexOf("\"")!=-1){ + origString=replace(origString,"\"","""); + } + if (origString.indexOf("<")!=-1){ + origString=replace(origString,"<","<"); + } + if (origString.indexOf(">")!=-1){ + origString=replace(origString,">",">"); + } + return origString; + + } + + + // Implementation of XExportFilter: + + public boolean exporter(com.sun.star.beans.PropertyValue[] aSourceData, + java.lang.String[] msUserData) throws com.sun.star.uno.RuntimeException{ + + sURL=null; + filterData = null; + + // Get user data from configuration (type detection) + //String udConvertClass=msUserData[0]; + //String udImport =msUserData[2]; + //String udExport =msUserData[3]; + sdMime = msUserData[5]; + + // Get source data (only the OutputStream and the URL are actually used) + com.sun.star.beans.PropertyValue[] pValue = aSourceData; + for (int i = 0 ; i < pValue.length; i++) { + try{ + if (pValue[i].Name.compareTo("OutputStream")==0){ + xos=(com.sun.star.io.XOutputStream)AnyConverter.toObject(new Type(com.sun.star.io.XOutputStream.class), pValue[i].Value); + } + //if (pValue[i].Name.compareTo("FileName")==0){ + // sFileName=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); + //} + if (pValue[i].Name.compareTo("URL")==0){ + sURL=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); + } + //if (pValue[i].Name.compareTo("Title")==0){ + // title=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); + //} + if (pValue[i].Name.compareTo("FilterData")==0) { + filterData = pValue[i].Value; + } + } + catch(com.sun.star.lang.IllegalArgumentException AnyExec){ + System.err.println("\nIllegalArgumentException "+AnyExec); + } + } + + + if (sURL==null){ + sURL=""; + } + + // Create a pipe to be used by the XDocumentHandler implementation: + try { + Object xPipeObj=xMSF.createInstance("com.sun.star.io.Pipe"); + xInStream = (XInputStream) UnoRuntime.queryInterface( + XInputStream.class , xPipeObj ); + xOutStream = (XOutputStream) UnoRuntime.queryInterface( + XOutputStream.class , xPipeObj ); + } + catch (Exception e){ + System.err.println("Exception "+e); + return false; + } + + return true; + } + + + + // Implementation of XDocumentHandler: + // Flat xml is created by the sax events and passed through the pipe + // created by exporter() + + public void startDocument () { + //Do nothing + } + + public void endDocument()throws com.sun.star.uno.RuntimeException { + try{ + xOutStream.closeOutput(); + convert(xInStream,xos); + } + catch (IOException e){ + MessageBox msgBox = new MessageBox(xComponentContext); + msgBox.showMessage(__displayName+": IO error in conversion", + e.toString()+" at "+e.getStackTrace()[0].toString()); + throw new com.sun.star.uno.RuntimeException(e.getMessage()); + } + catch (Exception e){ + MessageBox msgBox = new MessageBox(xComponentContext); + msgBox.showMessage(__displayName+": Internal error in conversion", + e.toString()+" at "+e.getStackTrace()[0].toString()); + throw new com.sun.star.uno.RuntimeException(__displayName+" Exception"); + } + } + + + + public void startElement (String str, com.sun.star.xml.sax.XAttributeList xattribs) + { + + str="<".concat(str); + if (xattribs !=null) + { + str= str.concat(" "); + int len=xattribs.getLength(); + for (short i=0;iConverter
+ * All errors are silently ignored
+ */
+public class FilterDataParser {
+
+ //private static XComponentContext xComponentContext = null;
+
+ private XSimpleFileAccess2 sfa2;
+ private XStringSubstitution xPathSub;
+
+ public FilterDataParser(XComponentContext xComponentContext) {
+ //this.xComponentContext = xComponentContext;
+
+ // Get the SimpleFileAccess service
+ sfa2 = null;
+ try {
+ Object sfaObject = xComponentContext.getServiceManager().createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess", xComponentContext);
+ sfa2 = (XSimpleFileAccess2) UnoRuntime.queryInterface(XSimpleFileAccess2.class, sfaObject);
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // failed to get SimpleFileAccess service (should not happen)
+ }
+
+ // Get the PathSubstitution service
+ xPathSub = null;
+ try {
+ Object psObject = xComponentContext.getServiceManager().createInstanceWithContext(
+ "com.sun.star.util.PathSubstitution", xComponentContext);
+ xPathSub = (XStringSubstitution) UnoRuntime.queryInterface(XStringSubstitution.class, psObject);
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // failed to get PathSubstitution service (should not happen)
+ }
+ }
+
+ /** Apply the given FilterData property to the given converter
+ * @param data an Any containing the FilterData property
+ * @param converter a writer2latex.api.Converter
implementation
+ */
+ public void applyFilterData(Object data, Converter converter) {
+ // Get the array from the data, if possible
+ PropertyValue[] filterData = null;
+ if (AnyConverter.isArray(data)) {
+ try {
+ Object[] arrayData = (Object[]) AnyConverter.toArray(data);
+ if (arrayData instanceof PropertyValue[]) {
+ filterData = (PropertyValue[]) arrayData;
+ }
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ // Failed to convert to array; should not happen - ignore
+ }
+ }
+ if (filterData==null) { return; }
+
+ PropertyHelper props = new PropertyHelper(filterData);
+
+ // Get the special properties TemplateURL, ConfigURL and AutoCreate
+ Object tpl = props.get("TemplateURL");
+ String sTemplate = null;
+ if (tpl!=null && AnyConverter.isString(tpl)) {
+ try {
+ sTemplate = substituteVariables(AnyConverter.toString(tpl));
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ // Failed to convert to String; should not happen - ignore
+ }
+ }
+
+ Object auto = props.get("AutoCreate");
+ boolean bAutoCreate = false;
+ if (auto!=null && AnyConverter.isString(auto)) {
+ try {
+ if ("true".equals(AnyConverter.toString(auto))) {
+ bAutoCreate = true;
+ }
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ // Failed to convert to String; should not happen - ignore
+ }
+ }
+
+ Object cfg = props.get("ConfigURL");
+ String sConfig = null;
+ if (cfg!=null && AnyConverter.isString(cfg)) {
+ try {
+ sConfig = substituteVariables(AnyConverter.toString(cfg));
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ // Failed to convert to String; should not happen - ignore
+ }
+ }
+
+ // Load the template from the specified URL, if any
+ if (sfa2!=null && sTemplate!=null && sTemplate.length()>0) {
+ try {
+ XInputStream xIs = sfa2.openFileRead(sTemplate);
+ if (xIs!=null) {
+ InputStream is = new XInputStreamToInputStreamAdapter(xIs);
+ converter.readTemplate(is);
+ is.close();
+ xIs.closeInput();
+ }
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ catch (NotConnectedException e) {
+ // ignore
+ }
+ catch (CommandAbortedException e) {
+ // ignore
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // ignore
+ }
+ }
+
+ // Create config if required
+ try {
+ if (bAutoCreate && sfa2!=null && sConfig!=null && !sConfig.startsWith("*") && !sfa2.exists(sConfig)) {
+ // Note: Requires random access, ie. must be a file URL:
+ XOutputStream xOs = sfa2.openFileWrite(sConfig);
+ if (xOs!=null) {
+ OutputStream os = new XOutputStreamToOutputStreamAdapter(xOs);
+ converter.getConfig().write(os);
+ os.flush();
+ os.close();
+ xOs.closeOutput();
+ }
+ }
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ catch (NotConnectedException e) {
+ // ignore
+ }
+ catch (CommandAbortedException e) {
+ // Ignore
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // Ignore
+ }
+
+ // Load the configuration from the specified URL, if any
+ if (sConfig!=null) {
+ if (sConfig.startsWith("*")) { // internal configuration
+ try {
+ converter.getConfig().readDefaultConfig(sConfig.substring(1));
+ }
+ catch (IllegalArgumentException e) {
+ // ignore
+ }
+ }
+ else if (sfa2!=null) { // real URL
+ try {
+ XInputStream xIs = sfa2.openFileRead(sConfig);;
+ if (xIs!=null) {
+ InputStream is = new XInputStreamToInputStreamAdapter(xIs);
+ converter.getConfig().read(is);
+ is.close();
+ xIs.closeInput();
+ }
+ }
+ catch (IOException e) {
+ // Ignore
+ }
+ catch (NotConnectedException e) {
+ // Ignore
+ }
+ catch (CommandAbortedException e) {
+ // Ignore
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // Ignore
+ }
+ }
+ }
+
+ // Read further configuration properties
+ Enumeration keys = props.keys();
+ while (keys.hasMoreElements()) {
+ String sKey = (String) keys.nextElement();
+ if (!"ConfigURL".equals(sKey) && !"TemplateURL".equals(sKey) && !"AutoCreate".equals(sKey)) {
+ Object value = props.get(sKey);
+ if (AnyConverter.isString(value)) {
+ try {
+ converter.getConfig().setOption(sKey,AnyConverter.toString(value));
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ // Failed to convert to String; should not happen - ignore
+ }
+ }
+ }
+ }
+ }
+
+ private String substituteVariables(String sUrl) {
+ if (xPathSub!=null) {
+ try {
+ return xPathSub.substituteVariables(sUrl, false);
+ }
+ catch (com.sun.star.container.NoSuchElementException e) {
+ // Found an unknown variable, no substitution
+ // (This will only happen if false is replaced by true above)
+ return sUrl;
+ }
+ }
+ else { // Not path substitution available
+ return sUrl;
+ }
+ }
+
+}
+
+
+
diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl.java
new file mode 100644
index 0000000..e291271
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl.java
@@ -0,0 +1,67 @@
+/************************************************************************
+ *
+ * GraphicConverterImpl.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-07-21)
+ *
+ */
+
+package org.openoffice.da.comp.w2lcommon.filter;
+
+import com.sun.star.uno.XComponentContext;
+
+import writer2latex.api.GraphicConverter;
+
+public class GraphicConverterImpl implements GraphicConverter {
+
+ private GraphicConverter graphicConverter1;
+ private GraphicConverter graphicConverter2;
+
+ public GraphicConverterImpl(XComponentContext xComponentContext) {
+ graphicConverter1 = new GraphicConverterImpl1(xComponentContext);
+ graphicConverter2 = new GraphicConverterImpl2(xComponentContext);
+ }
+
+ public boolean supportsConversion(String sSourceMime, String sTargetMime, boolean bCrop, boolean bResize) {
+ return graphicConverter1.supportsConversion(sSourceMime, sTargetMime, bCrop, bResize) ||
+ graphicConverter2.supportsConversion(sSourceMime, sTargetMime, bCrop, bResize);
+ }
+
+ public byte[] convert(byte[] source, String sSourceMime, String sTargetMime) {
+ byte[] result = null;
+
+ // Prefer the simple implementation (GraphicProvider)
+ if (graphicConverter1.supportsConversion(sSourceMime, sTargetMime, false, false)) {
+ result = graphicConverter1.convert(source, sSourceMime, sTargetMime);
+ }
+
+ // If this is not possible or fails, try the complex implementation
+ if (result==null) {
+ result = graphicConverter2.convert(source, sSourceMime, sTargetMime);
+ }
+
+ return result;
+
+ }
+
+
+}
+
diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl1.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl1.java
new file mode 100644
index 0000000..d2faa17
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/GraphicConverterImpl1.java
@@ -0,0 +1,194 @@
+/************************************************************************
+ *
+ * GraphicConverterImpl1.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ */
+
+// Version 1.0 (2008-11-22)
+
+package org.openoffice.da.comp.w2lcommon.filter;
+
+// Java uno helper class
+import com.sun.star.lib.uno.adapter.ByteArrayToXInputStreamAdapter;
+
+// UNO classes
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.graphic.XGraphic;
+import com.sun.star.graphic.XGraphicProvider;
+//import com.sun.star.io.XInputStream;
+//import com.sun.star.io.XOutputStream;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.uno.UnoRuntime;
+
+//import java.io.InputStream;
+//import java.io.OutputStream;
+
+import writer2latex.api.GraphicConverter;
+import writer2latex.api.MIMETypes;
+
+/** A GraphicConverter implementation which uses the GraphicProvider service
+ * to convert the graphic. This service does only support simple format
+ * conversion using the "internal" graphics filters in Draw. Advanced features
+ * like pdf, crop and resize thus cannot be handled.
+ */
+public class GraphicConverterImpl1 implements GraphicConverter {
+
+ // Signatures for start and end in exp
+ private byte[] psStart;
+ private byte[] psEnd;
+
+
+ private XGraphicProvider xGraphicProvider;
+
+ public GraphicConverterImpl1(XComponentContext xComponentContext) {
+ try {
+ // Get the XGraphicProvider interface of the GraphicProvider service
+ XMultiComponentFactory xMCF = xComponentContext.getServiceManager();
+ Object graphicProviderObject = xMCF.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", xComponentContext);
+ xGraphicProvider = (XGraphicProvider) UnoRuntime.queryInterface(XGraphicProvider.class, graphicProviderObject);
+ }
+ catch (com.sun.star.uno.Exception ex) {
+ System.err.println("Failed to get XGraphicProvider object");
+ xGraphicProvider = null;
+ }
+ try {
+ psStart = "%!PS-Adobe".getBytes("US-ASCII");
+ psEnd = "%%EOF".getBytes("US-ASCII");
+ }
+ catch (java.io.UnsupportedEncodingException ex) {
+ // US-ASCII *is* supported :-)
+ }
+
+ }
+
+ public boolean supportsConversion(String sSourceMime, String sTargetMime, boolean bCrop, boolean bResize) {
+ // We don't support cropping and resizing
+ if (bCrop || bResize) { return false; }
+
+ // We can convert vector formats to eps:
+ if (MIMETypes.EPS.equals(sTargetMime) && (MIMETypes.WMF.equals(sSourceMime) && MIMETypes.SVM.equals(sSourceMime))) {
+ return true;
+ }
+
+ // And we can convert all formats to bitmaps
+ boolean bSupportsSource =
+ MIMETypes.PNG.equals(sSourceMime) || MIMETypes.JPEG.equals(sSourceMime) ||
+ MIMETypes.GIF.equals(sSourceMime) || MIMETypes.TIFF.equals(sSourceMime) ||
+ MIMETypes.BMP.equals(sSourceMime) || MIMETypes.WMF.equals(sSourceMime) ||
+ MIMETypes.SVM.equals(sSourceMime);
+ boolean bSupportsTarget =
+ MIMETypes.PNG.equals(sTargetMime) || MIMETypes.JPEG.equals(sTargetMime) ||
+ MIMETypes.GIF.equals(sTargetMime) || MIMETypes.TIFF.equals(sTargetMime) ||
+ MIMETypes.BMP.equals(sTargetMime);
+ return bSupportsSource && bSupportsTarget;
+ }
+
+ public byte[] convert(byte[] source, String sSourceMime, String sTargetMime) {
+
+ // It seems that the GraphicProvider can only create proper eps if
+ // the source is a vector format, hence
+ if (MIMETypes.EPS.equals(sTargetMime)) {
+ if (!MIMETypes.WMF.equals(sSourceMime) && !MIMETypes.SVM.equals(sSourceMime)) {
+ return null;
+ }
+ }
+
+ ByteArrayToXInputStreamAdapter xSource = new ByteArrayToXInputStreamAdapter(source);
+ ByteArrayXStream xTarget = new ByteArrayXStream();
+ try {
+ // Read the source
+ PropertyValue[] sourceProps = new PropertyValue[1];
+ sourceProps[0] = new PropertyValue();
+ sourceProps[0].Name = "InputStream";
+ sourceProps[0].Value = xSource;
+ XGraphic result = xGraphicProvider.queryGraphic(sourceProps);
+
+ // Store as new type
+ PropertyValue[] targetProps = new PropertyValue[2];
+ targetProps[0] = new PropertyValue();
+ targetProps[0].Name = "MimeType";
+ targetProps[0].Value = sTargetMime;
+ targetProps[1] = new PropertyValue();
+ targetProps[1].Name = "OutputStream";
+ targetProps[1].Value = xTarget;
+ xGraphicProvider.storeGraphic(result,targetProps);
+
+
+ // Close the output and return the result
+ xTarget.closeOutput();
+ xTarget.flush();
+ if (MIMETypes.EPS.equals(sTargetMime)) {
+ return cleanEps(xTarget.getBuffer());
+ }
+ else {
+ return xTarget.getBuffer();
+ }
+ }
+ catch (com.sun.star.io.IOException e) {
+ return null;
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ return null;
+ }
+ catch (com.sun.star.lang.WrappedTargetException e) {
+ return null;
+ }
+ catch (Throwable e) {
+ return null;
+ }
+ }
+
+ private byte[] cleanEps(byte[] blob) {
+ int n = blob.length;
+
+ int nStart = 0;
+ for (int i=0; iXSingleServiceFactory
for creating the
+ * component
+ *
+ * @param implName the name of the implementation for which a
+ * service is desired
+ * @param multiFactory the service manager to be used if needed
+ * @param regKey the registryKey
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+ xMultiServiceFactory = multiFactory;
+ XSingleServiceFactory xSingleServiceFactory = null;
+ if (implName.equals(W2LExportFilter.class.getName()) ) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(W2LExportFilter.class,
+ W2LExportFilter.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(LaTeXOptionsDialog.__implementationName)) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(LaTeXOptionsDialog.class,
+ LaTeXOptionsDialog.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(W2LStarMathConverter.__implementationName)) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(W2LStarMathConverter.class,
+ W2LStarMathConverter.__serviceName,
+ multiFactory,
+ regKey);
+ }
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * Writes the service information into the given registry key.
+ * This method is called by the JavaLoader
+ *
+ * @return returns true if the operation succeeded
+ * @param regKey the registryKey
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static boolean __writeRegistryServiceInfo(XRegistryKey regKey) {
+ return
+ FactoryHelper.writeRegistryServiceInfo(W2LExportFilter.__implementationName,
+ W2LExportFilter.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(LaTeXOptionsDialog.__implementationName,
+ LaTeXOptionsDialog.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(W2LStarMathConverter.__implementationName,
+ W2LStarMathConverter.__serviceName, regKey);
+ }
+}
+
diff --git a/source/java/org/openoffice/da/comp/writer2latex/W2LStarMathConverter.java b/source/java/org/openoffice/da/comp/writer2latex/W2LStarMathConverter.java
new file mode 100644
index 0000000..3b720a7
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/writer2latex/W2LStarMathConverter.java
@@ -0,0 +1,125 @@
+/************************************************************************
+ *
+ * W2LStarMathConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ */
+
+// Version 1.0 (2008-11-22)
+
+package org.openoffice.da.comp.writer2latex;
+
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.uno.Type;
+//import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.lang.XServiceName;
+
+import writer2latex.api.ConverterFactory;
+import writer2latex.api.StarMathConverter;
+
+// Import interface as defined in uno idl
+import org.openoffice.da.writer2latex.XW2LStarMathConverter;
+
+/** This class provides a uno component which implements the interface
+ * org.openoffice.da.writer2latex.XW2LConverter
+ */
+public class W2LStarMathConverter implements
+ XW2LStarMathConverter,
+ XServiceName,
+ XServiceInfo,
+ XTypeProvider {
+
+ /** The component will be registered under this name.
+ */
+ public static final String __serviceName = "org.openoffice.da.writer2latex.W2LStarMathConverter";
+
+ public static final String __implementationName = "org.openoffice.da.comp.writer2latex.W2LStarMathConverter";
+
+ //private static XComponentContext xComponentContext = null;
+ private static StarMathConverter starMathConverter;
+
+ public W2LStarMathConverter(XComponentContext xComponentContext1) {
+ starMathConverter = ConverterFactory.createStarMathConverter();
+ }
+
+ // Implementation of XW2LConverter:
+ public String convertFormula(String sStarMathFormula) {
+ return starMathConverter.convert(sStarMathFormula);
+ }
+
+ public String getPreamble() {
+ return starMathConverter.getPreamble();
+ }
+
+
+ // Implement methods from interface XTypeProvider
+ // Implementation of XTypeProvider
+
+ public com.sun.star.uno.Type[] getTypes() {
+ Type[] typeReturn = {};
+
+ try {
+ typeReturn = new Type[] {
+ new Type( XW2LStarMathConverter.class ),
+ new Type( XTypeProvider.class ),
+ new Type( XServiceName.class ),
+ new Type( XServiceInfo.class ) };
+ }
+ catch( Exception exception ) {
+
+ }
+
+ return( typeReturn );
+ }
+
+
+ public byte[] getImplementationId() {
+ byte[] byteReturn = {};
+
+ byteReturn = new String( "" + this.hashCode() ).getBytes();
+
+ return( byteReturn );
+ }
+
+ // Implement method from interface XServiceName
+ public String getServiceName() {
+ return( __serviceName );
+ }
+
+ // Implement methods from interface XServiceInfo
+ public boolean supportsService(String stringServiceName) {
+ return( stringServiceName.equals( __serviceName ) );
+ }
+
+ public String getImplementationName() {
+ return( __implementationName );
+ }
+
+ public String[] getSupportedServiceNames() {
+ String[] stringSupportedServiceNames = { __serviceName };
+ return( stringSupportedServiceNames );
+ }
+
+
+}
+
+
+
diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/BatchConverter.java b/source/java/org/openoffice/da/comp/writer2xhtml/BatchConverter.java
new file mode 100644
index 0000000..b150190
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/writer2xhtml/BatchConverter.java
@@ -0,0 +1,541 @@
+/************************************************************************
+ *
+ * BatchConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-16)
+ *
+ */
+
+package org.openoffice.da.comp.writer2xhtml;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter;
+import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.document.XDocumentInfoSupplier;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XStorable;
+import com.sun.star.io.NotConnectedException;
+import com.sun.star.io.XInputStream;
+import com.sun.star.io.XOutputStream;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XServiceName;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.ucb.CommandAbortedException;
+import com.sun.star.ucb.XSimpleFileAccess2;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+//import writer2latex.api.BatchConverter;
+//import writer2latex.api.BatchHandler;
+//import writer2latex.api.Converter;
+import writer2latex.api.ConverterFactory;
+import writer2latex.api.IndexPageEntry;
+import writer2latex.api.MIMETypes;
+import writer2latex.api.OutputFile;
+
+// Import interfaces as defined in uno idl
+import org.openoffice.da.writer2xhtml.XBatchConverter;
+import org.openoffice.da.writer2xhtml.XBatchHandler;
+import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
+
+/** This class provides a uno component which implements the interface
+ * org.openoffice.da.writer2xhtml.XBatchConverter
+ */
+public class BatchConverter implements
+ XBatchConverter,
+ XServiceName,
+ XServiceInfo,
+ XTypeProvider {
+
+ /** The component will be registered under this name.
+ */
+ public static final String __serviceName = "org.openoffice.da.writer2xhtml.BatchConverter";
+
+ public static final String __implementationName = "org.openoffice.da.comp.writer2xhtml.BatchConverter";
+
+ private XComponentContext xComponentContext = null;
+
+ private XSimpleFileAccess2 sfa2 = null;
+ private writer2latex.api.BatchConverter batchConverter = null;
+
+ private XBatchHandler handler;
+
+ // Based on convert arguments
+ private boolean bRecurse = true;
+ private String sWriterFilterName = "org.openoffice.da.writer2xhtml";
+ private Object writerFilterData = null;
+ private String sCalcFilterName = "org.openoffice.da.calc2xhtml";
+ private Object calcFilterData = null;
+ private boolean bIncludePdf = true;
+ private boolean bIncludeOriginal = false;
+ private boolean bUseTitle = true;
+ private boolean bUseDescription = true;
+ private String sUplink = "";
+ private String sDirectoryIcon = "";
+ private String sDocumentIcon = "";
+ private String sTemplateURL = null;
+
+ public BatchConverter(XComponentContext xComponentContext) {
+ this.xComponentContext = xComponentContext;
+ // Get the SimpleFileAccess service
+ try {
+ Object sfaObject = xComponentContext.getServiceManager().createInstanceWithContext(
+ "com.sun.star.ucb.SimpleFileAccess", xComponentContext);
+ sfa2 = (XSimpleFileAccess2) UnoRuntime.queryInterface(XSimpleFileAccess2.class, sfaObject);
+ }
+ catch (com.sun.star.uno.Exception e) {
+ // failed to get SimpleFileAccess service (should not happen)
+ }
+ }
+
+ // Helper: Get a string from an any
+ private String getValue(Object any) {
+ if (AnyConverter.isString(any)) {
+ try {
+ return AnyConverter.toString(any);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e) {
+ return "";
+ }
+ }
+ else {
+ return "";
+ }
+ }
+
+ // Implementation of XBatchConverter:
+ public void convert(String sSourceURL, String sTargetURL, PropertyValue[] lArguments, XBatchHandler handler) {
+ // Create batch converter (currently we don't need to set a converter)
+ batchConverter = ConverterFactory.createBatchConverter(MIMETypes.XHTML);
+
+ this.handler = handler;
+
+ // Read the arguments
+ int nSize = lArguments.length;
+ for (int i=0; i
+ * @return returns true if the operation succeeded
+ * @param regKey the registryKey
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static boolean __writeRegistryServiceInfo(XRegistryKey regKey) {
+ return
+ FactoryHelper.writeRegistryServiceInfo(BatchConverter.__implementationName,
+ BatchConverter.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(W2XExportFilter.__implementationName,
+ W2XExportFilter.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(XhtmlOptionsDialog.__implementationName,
+ XhtmlOptionsDialog.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(XhtmlOptionsDialogXsl.__implementationName,
+ XhtmlOptionsDialogXsl.__serviceName, regKey) &
+ FactoryHelper.writeRegistryServiceInfo(XhtmlOptionsDialogCalc.__implementationName,
+ XhtmlOptionsDialogCalc.__serviceName, regKey);
+ }
+}
+
diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialog.java b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialog.java
new file mode 100644
index 0000000..ea982d0
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialog.java
@@ -0,0 +1,216 @@
+/************************************************************************
+ *
+ * XhtmlOptionsDialog.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-16)
+ *
+ */
+
+package org.openoffice.da.comp.writer2xhtml;
+
+import com.sun.star.awt.XDialog;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.uno.XComponentContext;
+
+import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
+import org.openoffice.da.comp.w2lcommon.filter.OptionsDialogBase;
+
+/** This class provides a uno component which implements a filter ui for the
+ * Xhtml export
+ */
+public class XhtmlOptionsDialog extends OptionsDialogBase {
+
+ /** The component will be registered under this name.
+ */
+ public static String __serviceName = "org.openoffice.da.writer2xhtml.XhtmlOptionsDialog";
+
+ /** The component should also have an implementation name.
+ */
+ public static String __implementationName = "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialog";
+
+ public String getDialogLibraryName() { return "W2XDialogs"; }
+
+ /** Return the name of the dialog within the library
+ */
+ public String getDialogName() { return "XhtmlOptions"; }
+
+ /** Return the name of the registry path
+ */
+ public String getRegistryPath() {
+ return "/org.openoffice.da.Writer2xhtml.Options/XhtmlOptions";
+ }
+
+ /** Create a new XhtmlOptionsDialog */
+ public XhtmlOptionsDialog(XComponentContext xContext) {
+ super(xContext);
+ xMSF = W2XRegistration.xMultiServiceFactory;
+ }
+
+ /** Load settings from the registry to the dialog */
+ protected void loadSettings(XPropertySet xProps) {
+ // Style
+ loadConfig(xProps);
+ loadCheckBoxOption(xProps, "ConvertToPx");
+ loadNumericOption(xProps, "Scaling");
+ loadNumericOption(xProps, "ColumnScaling");
+ loadCheckBoxOption(xProps, "OriginalImageSize");
+
+ // Special content
+ loadCheckBoxOption(xProps, "Notes");
+ loadCheckBoxOption(xProps, "UseDublinCore");
+
+ // AutoCorrect
+ loadCheckBoxOption(xProps, "IgnoreHardLineBreaks");
+ loadCheckBoxOption(xProps, "IgnoreEmptyParagraphs");
+ loadCheckBoxOption(xProps, "IgnoreDoubleSpaces");
+
+ // Files
+ loadCheckBoxOption(xProps, "Split");
+ loadListBoxOption(xProps, "SplitLevel");
+ loadListBoxOption(xProps, "RepeatLevels");
+ loadCheckBoxOption(xProps, "SaveImagesInSubdir");
+ loadTextFieldOption(xProps, "XsltPath");
+
+ updateLockedOptions();
+ enableControls();
+ }
+
+ /** Save settings from the dialog to the registry and create FilterData */
+ protected void saveSettings(XPropertySet xProps, PropertyHelper helper) {
+ // Style
+ short nConfig = saveConfig(xProps, helper);
+ String[] sCoreStyles = { "Chocolate", "Midnight", "Modernist",
+ "Oldstyle", "Steely", "Swiss", "Traditional", "Ultramarine" };
+ switch (nConfig) {
+ case 0: helper.put("ConfigURL","*default.xml"); break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: helper.put("ConfigURL","*cleanxhtml.xml");
+ helper.put("custom_stylesheet",
+ "http://www.w3.org/StyleSheets/Core/"+sCoreStyles[nConfig-1]);
+ break;
+ case 9: helper.put("ConfigURL","$(user)/writer2xhtml.xml");
+ helper.put("AutoCreate","true");
+ }
+
+ saveCheckBoxOption(xProps, helper, "ConvertToPx", "convert_to_px");
+ saveNumericOptionAsPercentage(xProps, helper, "Scaling", "scaling");
+ saveNumericOptionAsPercentage(xProps, helper, "ColumnScaling", "column_scaling");
+ saveCheckBoxOption(xProps, helper, "OriginalImageSize", "original_image_size");
+
+ // Special content
+ saveCheckBoxOption(xProps, helper, "Notes", "notes");
+ saveCheckBoxOption(xProps, helper, "UseDublinCore", "use_dublin_core");
+
+ // AutoCorrect
+ saveCheckBoxOption(xProps, helper, "IgnoreHardLineBreaks", "ignore_hard_line_breaks");
+ saveCheckBoxOption(xProps, helper, "IgnoreEmptyParagraphs", "ignore_empty_paragraphs");
+ saveCheckBoxOption(xProps, helper, "IgnoreDoubleSpaces", "ignore_double_spaces");
+
+ // Files
+ boolean bSplit = saveCheckBoxOption(xProps, "Split");
+ short nSplitLevel = saveListBoxOption(xProps, "SplitLevel");
+ short nRepeatLevels = saveListBoxOption(xProps, "RepeatLevels");
+ if (!isLocked("split_level")) {
+ if (bSplit) {
+ helper.put("split_level",Integer.toString(nSplitLevel+1));
+ helper.put("repeat_levels",Integer.toString(nRepeatLevels));
+ }
+ else {
+ helper.put("split_level","0");
+ }
+ }
+
+ saveCheckBoxOption(xProps, helper, "SaveImagesInSubdir", "save_images_in_subdir");
+ saveTextFieldOption(xProps, helper, "XsltPath", "xslt_path");
+
+ }
+
+
+ // Implement XDialogEventHandler
+ public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
+ if (sMethod.equals("ConfigChange")) {
+ updateLockedOptions();
+ enableControls();
+ }
+ else if (sMethod.equals("SplitChange")) {
+ enableSplitLevel();
+ }
+ return true;
+ }
+
+ public String[] getSupportedMethodNames() {
+ String[] sNames = { "ConfigChange", "SplitChange" };
+ return sNames;
+ }
+
+ private void enableControls() {
+ // Style
+ setControlEnabled("ScalingLabel",!isLocked("scaling"));
+ setControlEnabled("Scaling",!isLocked("scaling"));
+ setControlEnabled("ColumnScalingLabel",!isLocked("column_scaling"));
+ setControlEnabled("ColumnScaling",!isLocked("column_scaling"));
+ setControlEnabled("ConvertToPx",!isLocked("convert_to_px"));
+ setControlEnabled("OriginalImageSize",!isLocked("original_image_size"));
+
+ // Special content
+ setControlEnabled("Notes",!isLocked("notes"));
+ setControlEnabled("UseDublinCore",!isLocked("use_dublin_core"));
+
+ // AutoCorrect
+ setControlEnabled("IgnoreHardLineBreaks",!isLocked("ignore_hard_line_breaks"));
+ setControlEnabled("IgnoreEmptyParagraphs",!isLocked("ignore_empty_paragraphs"));
+ setControlEnabled("IgnoreDoubleSpaces",!isLocked("ignore_double_spaces"));
+
+ // Files
+ boolean bSplit = getCheckBoxStateAsBoolean("Split");
+ setControlEnabled("Split",!isLocked("split_level"));
+ setControlEnabled("SplitLevelLabel",!isLocked("split_level") && bSplit);
+ setControlEnabled("SplitLevel",!isLocked("split_level") && bSplit);
+ setControlEnabled("RepeatLevelsLabel",!isLocked("repeat_levels") && !isLocked("split_level") && bSplit);
+ setControlEnabled("RepeatLevels",!isLocked("repeat_levels") && !isLocked("split_level") && bSplit);
+ setControlEnabled("SaveImagesInSubdir",!isLocked("save_images_in_subdir"));
+ setControlEnabled("XsltPathLabel",(this instanceof XhtmlOptionsDialogXsl) && !isLocked("xslt_path"));
+ setControlEnabled("XsltPath",(this instanceof XhtmlOptionsDialogXsl) && !isLocked("xslt_path"));
+ }
+
+ private void enableSplitLevel() {
+ if (!isLocked("split_level")) {
+ boolean bState = getCheckBoxStateAsBoolean("Split");
+ setControlEnabled("SplitLevelLabel",bState);
+ setControlEnabled("SplitLevel",bState);
+ if (!isLocked("repeat_levels")) {
+ setControlEnabled("RepeatLevelsLabel",bState);
+ setControlEnabled("RepeatLevels",bState);
+ }
+ }
+ }
+
+
+}
+
+
+
diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogCalc.java b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogCalc.java
new file mode 100644
index 0000000..874d6d1
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogCalc.java
@@ -0,0 +1,174 @@
+/************************************************************************
+ *
+ * XhtmlOptionsDialogCalc.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-18)
+ *
+ */
+
+package org.openoffice.da.comp.writer2xhtml;
+
+import com.sun.star.awt.XDialog;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.uno.XComponentContext;
+
+import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
+import org.openoffice.da.comp.w2lcommon.filter.OptionsDialogBase;
+
+/** This class provides a uno component which implements a filter ui for the
+ * Xhtml export in Calc
+ */
+public class XhtmlOptionsDialogCalc extends OptionsDialogBase {
+
+ /** The component will be registered under this name.
+ */
+ public static String __serviceName = "org.openoffice.da.writerxhtml.XhtmlOptionsDialogCalc";
+
+ /** The component should also have an implementation name.
+ */
+ public static String __implementationName = "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialogCalc";
+
+ public String getDialogLibraryName() { return "W2XDialogs"; }
+
+ /** Return the name of the dialog within the library
+ */
+ public String getDialogName() { return "XhtmlOptionsCalc"; }
+
+ /** Return the name of the registry path
+ */
+ public String getRegistryPath() {
+ return "/org.openoffice.da.Writer2xhtml.Options/XhtmlOptionsCalc";
+ }
+
+ /** Create a new XhtmlOptionsDialogCalc */
+ public XhtmlOptionsDialogCalc(XComponentContext xContext) {
+ super(xContext);
+ xMSF = W2XRegistration.xMultiServiceFactory;
+ }
+
+ /** Load settings from the registry to the dialog */
+ protected void loadSettings(XPropertySet xProps) {
+ // Style
+ loadConfig(xProps);
+ loadCheckBoxOption(xProps, "ConvertToPx");
+ loadNumericOption(xProps, "Scaling");
+ loadNumericOption(xProps, "ColumnScaling");
+ loadCheckBoxOption(xProps, "OriginalImageSize");
+
+ // Special content
+ loadCheckBoxOption(xProps, "Notes");
+ loadCheckBoxOption(xProps, "UseDublinCore");
+
+ // Sheets
+ loadCheckBoxOption(xProps, "DisplayHiddenSheets");
+ loadCheckBoxOption(xProps, "DisplayHiddenRowsCols");
+ loadCheckBoxOption(xProps, "DisplayFilteredRowsCols");
+ loadCheckBoxOption(xProps, "ApplyPrintRanges");
+ loadCheckBoxOption(xProps, "UseTitleAsHeading");
+ loadCheckBoxOption(xProps, "UseSheetNamesAsHeadings");
+
+ // Files
+ loadCheckBoxOption(xProps, "CalcSplit");
+ loadCheckBoxOption(xProps, "SaveImagesInSubdir");
+
+ updateLockedOptions();
+ enableControls();
+ }
+
+ /** Save settings from the dialog to the registry and create FilterData */
+ protected void saveSettings(XPropertySet xProps, PropertyHelper helper) {
+ // Style
+ short nConfig = saveConfig(xProps, helper);
+ if (nConfig==0) {
+ helper.put("ConfigURL","*default.xml");
+ }
+ else if (nConfig==1) {
+ helper.put("ConfigURL","$(user)/writer2xhtml.xml");
+ helper.put("AutoCreate","true");
+ }
+
+ saveCheckBoxOption(xProps, helper, "ConvertToPx", "convert_to_px");
+ saveNumericOptionAsPercentage(xProps, helper, "Scaling", "scaling");
+ saveNumericOptionAsPercentage(xProps, helper, "ColumnScaling", "column_scaling");
+ saveCheckBoxOption(xProps, helper, "OriginalImageSize", "original_image_size");
+
+ // Special content
+ saveCheckBoxOption(xProps, helper, "Notes", "notes");
+ saveCheckBoxOption(xProps, helper, "UseDublinCore", "use_dublin_core");
+
+ // Sheets
+ saveCheckBoxOption(xProps, helper, "DisplayHiddenSheets", "display_hidden_sheets");
+ saveCheckBoxOption(xProps, helper, "DisplayHiddenRowsCols", "display_hidden_rows_cols");
+ saveCheckBoxOption(xProps, helper, "DisplayFilteredRowsCols", "display_filtered_rows_cols");
+ saveCheckBoxOption(xProps, helper, "ApplyPrintRanges", "apply_print_ranges");
+ saveCheckBoxOption(xProps, helper, "UseTitleAsHeading", "use_title_as_heading");
+ saveCheckBoxOption(xProps, helper, "UseSheetNamesAsHeadings", "use_sheet_names_as_headings");
+
+ // Files
+ saveCheckBoxOption(xProps, helper, "CalcSplit", "calc_split");
+ saveCheckBoxOption(xProps, helper, "SaveImagesInSubdir", "save_images_in_subdir");
+
+ }
+
+ // Implement XDialogEventHandler
+ public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
+ if (sMethod.equals("ConfigChange")) {
+ updateLockedOptions();
+ enableControls();
+ }
+ return true;
+ }
+
+ public String[] getSupportedMethodNames() {
+ String[] sNames = { "ConfigChange" };
+ return sNames;
+ }
+
+ private void enableControls() {
+ // Style
+ setControlEnabled("ConvertToPx",!isLocked("convert_to_px"));
+ setControlEnabled("ScalingLabel",!isLocked("scaling"));
+ setControlEnabled("Scaling",!isLocked("scaling"));
+ setControlEnabled("ColumnScalingLabel",!isLocked("column_scaling"));
+ setControlEnabled("ColumnScaling",!isLocked("column_scaling"));
+ setControlEnabled("OriginalImageSize",!isLocked("original_image_size"));
+
+ // Special content
+ setControlEnabled("Notes",!isLocked("notes"));
+ setControlEnabled("UseDublinCore",!isLocked("use_dublin_core"));
+
+ // Sheets
+ setControlEnabled("DisplayHiddenSheets", !isLocked("display_hidden_sheets"));
+ setControlEnabled("DisplayHiddenRowsCols", !isLocked("display_hidden_rows_cols"));
+ setControlEnabled("DisplayFilteredRowsCols", !isLocked("display_filtered_rows_cols"));
+ setControlEnabled("ApplyPrintRanges", !isLocked("apply_print_ranges"));
+ setControlEnabled("UseTitleAsHeading", !isLocked("use_title_as_heading"));
+ setControlEnabled("UseSheetNamesAsHeadings", !isLocked("use_sheet_names_as_headings"));
+
+ // Files
+ setControlEnabled("CalcSplit",!isLocked("calc_split"));
+ setControlEnabled("SaveImagesInSubdir",!isLocked("save_images_in_subdir"));
+ }
+
+}
+
+
+
diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogXsl.java b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogXsl.java
new file mode 100644
index 0000000..df6bda3
--- /dev/null
+++ b/source/java/org/openoffice/da/comp/writer2xhtml/XhtmlOptionsDialogXsl.java
@@ -0,0 +1,52 @@
+/************************************************************************
+ *
+ * XhtmlOptionsDialogXsl.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-09-11)
+ *
+ */
+
+package org.openoffice.da.comp.writer2xhtml;
+
+import com.sun.star.uno.XComponentContext;
+
+/** This class provides a uno component which implements a filter ui for the
+ * Xhtml export (xsl variant)
+ * This variant of the dialog has the XsltPath setting enabled
+ */
+public class XhtmlOptionsDialogXsl extends XhtmlOptionsDialog {
+ /** The component will be registered under this name.
+ */
+ public static String __serviceName = "org.openoffice.da.writer2xhtml.XhtmlOptionsDialogXsl";
+
+ /** The component should also have an implementation name.
+ */
+ public static String __implementationName = "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialogXsl";
+
+ /** Create a new XhtmlOptionsDialogXsl */
+ public XhtmlOptionsDialogXsl(XComponentContext xContext) {
+ super(xContext);
+ }
+
+}
+
+
+
diff --git a/source/java/writer2latex/Application.java b/source/java/writer2latex/Application.java
new file mode 100644
index 0000000..2e8f213
--- /dev/null
+++ b/source/java/writer2latex/Application.java
@@ -0,0 +1,382 @@
+/************************************************************************
+ *
+ * Application.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+//import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import writer2latex.api.BatchConverter;
+import writer2latex.api.Converter;
+import writer2latex.api.ConverterFactory;
+import writer2latex.api.ConverterResult;
+import writer2latex.api.MIMETypes;
+//import writer2latex.api.OutputFile;
+
+import writer2latex.util.Misc;
+
+/**
+ * Commandline utility to convert an OpenOffice.org Writer XML file into XHTML/LaTeX/BibTeX The utility is invoked with the following command line: Where the available options are
+ * where Create a Currently supported MIME types are: Create a The only currently supported MIME type is This package contains the api for using Writer2LaTeX. The api consitst of a factory class and a number of interfaces, and is
+used by the command line application as well as by the filters.
+
+
diff --git a/source/java/writer2latex/api/StarMathConverter.java b/source/java/writer2latex/api/StarMathConverter.java
new file mode 100644
index 0000000..1492a62
--- /dev/null
+++ b/source/java/writer2latex/api/StarMathConverter.java
@@ -0,0 +1,61 @@
+/************************************************************************
+ *
+ * StarMathConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+//import java.io.InputStream;
+//import java.io.IOException;
+
+/** This is an interface for a converter, which offers conversion of
+ * a StarMath formula into LaTeX
+ * Instances of this interface are created using the
+ * {@link ConverterFactory}
+ */
+public interface StarMathConverter {
+
+ /** Get the configuration used when converting.
+ *
+ * @return the configuration used by this converter
+ */
+ public Config getConfig();
+
+ /** Convert a StarMath formula
+ *
+ * @param sStarMathFormula is a string containing the StarMath formula
+ * @return a string containing the converted LaTeX formula
+ */
+ public String convert(String sStarMathFormula);
+
+ /** Create a suitable LaTeX preamble to process the formulas converted so far
+ *
+ * @return a string containg the entire LaTeX preamble
+ */
+ public String getPreamble();
+
+}
+
+
+
diff --git a/source/java/writer2latex/base/BatchConverterBase.java b/source/java/writer2latex/base/BatchConverterBase.java
new file mode 100644
index 0000000..cebf051
--- /dev/null
+++ b/source/java/writer2latex/base/BatchConverterBase.java
@@ -0,0 +1,182 @@
+/************************************************************************
+ *
+ * BatchConverterBase.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-10-15)
+ *
+ */
+
+package writer2latex.base;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import writer2latex.api.BatchConverter;
+import writer2latex.api.BatchHandler;
+import writer2latex.api.Converter;
+import writer2latex.api.ConverterResult;
+import writer2latex.api.IndexPageEntry;
+import writer2latex.api.OutputFile;
+
+import writer2latex.util.Misc;
+
+/**
+ * Abstract base implementation of JavaLoader
+ *
+ * @return returns a XSingleServiceFactory
for creating the
+ * component
+ *
+ * @param implName the name of the implementation for which a
+ * service is desired
+ * @param multiFactory the service manager to be used if needed
+ * @param regKey the registryKey
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory, XRegistryKey regKey) {
+ xMultiServiceFactory = multiFactory;
+ XSingleServiceFactory xSingleServiceFactory = null;
+ if (implName.equals(W2XExportFilter.class.getName()) ) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(W2XExportFilter.class,
+ W2XExportFilter.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(BatchConverter.__implementationName) ) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(BatchConverter.class,
+ BatchConverter.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(XhtmlOptionsDialog.__implementationName)) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(XhtmlOptionsDialog.class,
+ XhtmlOptionsDialog.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(XhtmlOptionsDialogXsl.__implementationName)) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(XhtmlOptionsDialogXsl.class,
+ XhtmlOptionsDialogXsl.__serviceName,
+ multiFactory,
+ regKey);
+ }
+ else if (implName.equals(XhtmlOptionsDialogCalc.__implementationName)) {
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(XhtmlOptionsDialogCalc.class,
+ XhtmlOptionsDialogCalc.__serviceName,
+ multiFactory,
+ regKey);
+ }
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * Writes the service information into the given registry key.
+ * This method is called by the JavaLoader
+ * java -jar writer2latex.jar [options] source [target]
+ *
+ *
+ * -latex
, -bibtex
, -xhtml
,
+ -xhtml+mathml
, -xhtml+mathml+xsl
+ * -recurse
+ * -ultraclean
, -clean
, -pdfscreen
,
+ * -pdfprint
, -cleanxhtml
+ * -config[=]filename
+ * -template[=]filename
+ * -option[=]value
+ * option
can be any simple option known to Writer2LaTeX
+ * (see documentation for the configuration file).BatchHandler
for command line usage
+ */
+public class BatchHandlerImpl implements BatchHandler {
+ private int nIndent = 0;
+
+ private void writeMessage(String sMsg) {
+ for (int i=0; iConverter
implementation to use for
+ * conversion of the individual documents.
+ * If no converter is given, the convert
method cannot
+ * convert documents (but can still create index pages).
+ *
+ * @param converter the Converter
to use
+ */
+ public void setConverter(Converter converter);
+
+ /** Read a template to use as a base for the index pages.
+ * The format of the template depends on the BatchConverter
+ * implementation.
+ *
+ * @param is an InputStream
from which to read the template
+ * @throws IOException if some exception occurs while reading the template
+ */
+ public void readTemplate(InputStream is) throws IOException;
+
+ /** Read a template to use as a base for the index pages.
+ * The format of the template depends on the BatchConverter
+ * implementation.
+ *
+ * @param file the file from which to read the template
+ * @throws IOException if the file does not exist or some exception occurs
+ * while reading the template
+ */
+ public void readTemplate(File file) throws IOException;
+
+ /** Create an index page with specific entries
+ *
+ * @param sHeading a heading describing the index page
+ * @param entries an array of IndexPageEntry
objects (null entries
+ * are allowed, and will be ignored) describing the individual directories
+ * and documents
+ */
+ public OutputFile createIndexFile(String sHeading, IndexPageEntry[] entries);
+
+ /** Convert a directory using the given Converter
(if none is given,
+ * all files will be ignored).
+ * This method fails silently if you haven't set a converter.
+ *
+ * @param source a File
representing the directory to convert
+ * @param target a File
representing the directory to contain
+ * the converted documents
+ * @param bRecurse determines wether or not to recurse into subdirectories
+ * @param handler a BatchHandler
+ */
+ public void convert(File source, File target, boolean bRecurse, BatchHandler handler);
+
+}
diff --git a/source/java/writer2latex/api/BatchHandler.java b/source/java/writer2latex/api/BatchHandler.java
new file mode 100644
index 0000000..647ae5d
--- /dev/null
+++ b/source/java/writer2latex/api/BatchHandler.java
@@ -0,0 +1,77 @@
+/************************************************************************
+ *
+ * BatchHandler.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+/** This is a call back interface to handle user interaction during a
+ * batch conversion with a {@link BatchConverter}
+ */
+public interface BatchHandler {
+
+ /** Notification that the conversion is started */
+ public void startConversion();
+
+ /** Notification that the conversion has finished */
+ public void endConversion();
+
+ /** Notification that a directory conversion starts
+ *
+ * @param sName the name of the directory to convert
+ */
+ public void startDirectory(String sName);
+
+ /** Notification that a directory conversion has finished
+ *
+ * @param sName the name of the directory
+ * @param bSuccess true if the conversion was successful (this only means
+ * that the index page was created with success, not that the conversion
+ * of files and subdirectories was successful)
+ */
+ public void endDirectory(String sName, boolean bSuccess);
+
+ /** Notification that a file conversion starts
+ *
+ * @param sName the name of the file to convert
+ */
+ public void startFile(String sName);
+
+ /** Notification that a file conversion has finished
+ *
+ * @param sName the name of the file
+ * @param bSuccess true if the conversion of this file was successful
+ */
+ public void endFile(String sName, boolean bSuccess);
+
+ /** Notification that the conversion may be cancelled. The
+ * {@link BatchConverter} fires this event once per document.
+ * Cancelling the conversion does not delete files that was already
+ * converted
+ *
+ * @return true if the handler wants to cancel the conversion
+ */
+ public boolean cancel();
+
+}
diff --git a/source/java/writer2latex/api/Config.java b/source/java/writer2latex/api/Config.java
new file mode 100644
index 0000000..3ce8864
--- /dev/null
+++ b/source/java/writer2latex/api/Config.java
@@ -0,0 +1,99 @@
+/************************************************************************
+ *
+ * Config.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.IllegalArgumentException;
+
+/** This is an interface for configuration of a {@link Converter}.
+ * A configuration always supports simple name/value options.
+ * In addition, you can read and write configurations using streams
+ * or abstract file names. The format depends on the {@link Converter}
+ * implementation, cf. the user's manual.
+ */
+public interface Config {
+
+ /** Read a default configuration: The available configurations depend on the
+ * {@link Converter} implementation
+ *
+ * @param sName the name of the configuration
+ * @throws IllegalArgumentException if the configuration does not exist
+ */
+ public void readDefaultConfig(String sName) throws IllegalArgumentException;
+
+ /** Read a configuration (stream based version)
+ *
+ * @param is the InputStream
to read from
+ * @throws IOException if an error occurs reading the stream, or the data
+ * is not in the right format
+ */
+ public void read(InputStream is) throws IOException;
+
+ /** Read a configuration (file based version)
+ *
+ * @param file the File
to read from
+ * @throws IOException if the file does not exist, an error occurs reading
+ * the file, or the data is not in the right format
+ */
+ public void read(File file) throws IOException;
+
+ /** Write the configuration (stream based version)
+ *
+ * @param os the OutputStream
to write to
+ * @throws IOException if an error occurs writing to the stream
+ */
+ public void write(OutputStream os) throws IOException;
+
+ /** Write the configuration (file based version)
+ *
+ * @param file the File
to write to
+ * @throws IOException if an error occurs writing to the file
+ */
+ public void write(File file) throws IOException;
+
+ /** Set a name/value option. Options that are not defined by the
+ * {@link Converter} implementation as well as null values are
+ * silently ignored
+ *
+ * @param sName the name of the option
+ * @param sValue the value of the option
+ */
+ public void setOption(String sName, String sValue);
+
+ /** Get a named option
+ *
+ * @param sName the name of the option
+ * @return the value of the option, or null
if the option does
+ * not exist or the given name is null
+ */
+ public String getOption(String sName);
+
+}
+
diff --git a/source/java/writer2latex/api/Converter.java b/source/java/writer2latex/api/Converter.java
new file mode 100644
index 0000000..2b3315f
--- /dev/null
+++ b/source/java/writer2latex/api/Converter.java
@@ -0,0 +1,99 @@
+/************************************************************************
+ *
+ * Converter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+
+/** This is an interface for a converter, which offers conversion of
+ * OpenDocument (or OpenOffice.org 1.x) documents into a specific format.
+ * Instances of this interface are created using the
+ * ConverterFactory
+ */
+public interface Converter {
+
+ /** Get the interface for the configuration of this converter
+ *
+ * @return the configuration
+ */
+ public Config getConfig();
+
+ /** Define a GraphicConverter
implementation to use for
+ * conversion of graphic files. If no converter is specified, graphic
+ * files will not be converted into other formats.
+ *
+ * @param gc the GraphicConverter
to use
+ */
+ public void setGraphicConverter(GraphicConverter gc);
+
+ /** Read a template to use as a base for the converted document.
+ * The format of the template depends on the Converter
+ * implementation.
+ *
+ * @param is an InputStream
from which to read the template
+ * @throws IOException if some exception occurs while reading the template
+ */
+ public void readTemplate(InputStream is) throws IOException;
+
+ /** Read a template to use as a base for the converted document.
+ * The format of the template depends on the Converter
+ * implementation.
+ *
+ * @param file a file from which to read the template
+ * @throws IOException if the file does not exist or some exception occurs
+ * while reading the template
+ */
+ public void readTemplate(File file) throws IOException;
+
+ /** Convert a document
+ *
+ * @param is an InputStream
from which to read the source document.
+ * @param sTargetFileName the file name to use for the converted document
+ * (if the converted document is a compound document consisting consisting
+ * of several files, this name will be used for the master document)
+ * @return a ConverterResult
containing the converted document
+ * @throws IOException if some exception occurs while reading the document
+ */
+ public ConverterResult convert(InputStream is, String sTargetFileName)
+ throws IOException;
+
+ /** Convert a document
+ *
+ * @param source a File
from which to read the source document.
+ * @param sTargetFileName the file name to use for the converted document
+ * (if the converted document is a compound document consisting consisting
+ * of several files, this name will be used for the master document)
+ * @return a ConverterResult
containing the converted document
+ * @throws FileNotFoundException if the file does not exist
+ * @throws IOException if some exception occurs while reading the document
+ */
+ public ConverterResult convert(File source, String sTargetFileName)
+ throws FileNotFoundException, IOException;
+
+}
diff --git a/source/java/writer2latex/api/ConverterFactory.java b/source/java/writer2latex/api/ConverterFactory.java
new file mode 100644
index 0000000..3ae2478
--- /dev/null
+++ b/source/java/writer2latex/api/ConverterFactory.java
@@ -0,0 +1,126 @@
+/************************************************************************
+ *
+ * ConverterFactory.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-18)
+ *
+ */
+
+package writer2latex.api;
+
+/** This is a factory class which provides static methods to create converters
+ * for documents in OpenDocument (or OpenOffice.org 1.x) format into a specific MIME type
+ */
+public class ConverterFactory {
+
+ // Version information
+ private static final String VERSION = "0.9.4";
+ private static final String DATE = "2008-02-19";
+
+ /** Return version information
+ * @return the Writer2LaTeX version in the form
+ * (major version).(minor version).(development version).(patch level)
+ */
+ public static String getVersion() { return VERSION; }
+
+ /** Return date information
+ * @return the release date for this Writer2LaTeX version
+ */
+ public static String getDate() { return DATE; }
+
+ /** Converter
implementation which supports
+ * conversion into the specified MIME type.
+ *
+ *
+ * @param sMIME the MIME type of the target format
+ * @return the required application/x-latex
for LaTeX formatapplication/x-bibtex
for BibTeX formattext/html
for XHTML 1.0 strict formatapplication/xhtml+xml
for XHTML+MathMLapplication/xml
for XHTML+MathML using stylesheets from w3c's
+ * math working groupConverter
or null if a converter for
+ * the requested MIME type could not be created
+ */
+ public static Converter createConverter(String sMIME) {
+ Object converter = null;
+ if (MIMETypes.LATEX.equals(sMIME)) {
+ converter = createInstance("writer2latex.latex.ConverterPalette");
+ }
+ else if (MIMETypes.BIBTEX.equals(sMIME)) {
+ converter = createInstance("writer2latex.bibtex.Converter");
+ }
+ else if (MIMETypes.XHTML.equals(sMIME)) {
+ converter = createInstance("writer2latex.xhtml.Xhtml10Converter");
+ }
+ else if (MIMETypes.XHTML_MATHML.equals(sMIME)) {
+ converter = createInstance("writer2latex.xhtml.XhtmlMathMLConverter");
+ }
+ else if (MIMETypes.XHTML_MATHML_XSL.equals(sMIME)) {
+ converter = createInstance("writer2latex.xhtml.XhtmlMathMLXSLConverter");
+ }
+ return converter instanceof Converter ? (Converter) converter : null;
+ }
+
+ /** BatchConverter
implementation which supports
+ * conversion into the specified MIME typetext/html
+ * (XHTML 1.0 strict)BatchConverter
or null if a converter
+ * for the requested MIME type could not be created
+ */
+ public static BatchConverter createBatchConverter(String sMIME) {
+ Object converter = null;
+ if (MIMETypes.XHTML.equals(sMIME)) {
+ converter = createInstance("writer2latex.xhtml.BatchConverterImpl");
+ }
+ return converter instanceof BatchConverter ? (BatchConverter) converter : null;
+ }
+
+ /** Create a StarMathConverter
implementation
+ *
+ * @return the converter
+ */
+ public static StarMathConverter createStarMathConverter() {
+ Object converter = createInstance("writer2latex.latex.StarMathConverter");
+ return converter instanceof StarMathConverter ? (StarMathConverter) converter : null;
+ }
+
+ private static Object createInstance(String sClassName) {
+ try {
+ return Class.forName(sClassName).newInstance();
+ }
+ catch (java.lang.ClassNotFoundException e) {
+ return null;
+ }
+ catch (java.lang.InstantiationException e) {
+ return null;
+ }
+ catch (java.lang.IllegalAccessException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/source/java/writer2latex/api/ConverterResult.java b/source/java/writer2latex/api/ConverterResult.java
new file mode 100644
index 0000000..eba2e97
--- /dev/null
+++ b/source/java/writer2latex/api/ConverterResult.java
@@ -0,0 +1,59 @@
+/************************************************************************
+ *
+ * ConverterResult.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-24)
+ *
+ */
+
+package writer2latex.api;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+/** A ConverterResult
represent a document, which is the result
+ * of a conversion performed by a Converter
implementation.
+ */
+public interface ConverterResult {
+
+ /** Get the master document
+ * @return OutputFile
the master document
+ */
+ public OutputFile getMasterDocument();
+
+ /** Gets an Iterator
to access all files in the
+ * ConverterResult
. This includes the master document.
+ * @return an Iterator
of all files
+ */
+ public Iterator iterator();
+
+ /** Write all files of the ConverterResult
to a directory.
+ * Subdirectories are created as required by the individual
+ * OutputFile
s.
+ * @param dir the directory to write to (this directory must exist).
+ If the parameter is null, the default directory is used
+ * @throws IOException if the directory does not exist or one or more files
+ * could not be written
+ */
+ public void write(File dir) throws IOException;
+
+}
diff --git a/source/java/writer2latex/api/GraphicConverter.java b/source/java/writer2latex/api/GraphicConverter.java
new file mode 100644
index 0000000..8ccb426
--- /dev/null
+++ b/source/java/writer2latex/api/GraphicConverter.java
@@ -0,0 +1,58 @@
+/************************************************************************
+ *
+ * GraphicConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+/** A simple interface for a graphic converter which converts between various
+ * graphics formats
+ */
+public interface GraphicConverter {
+
+ /** Check whether a certain conversion is supported by the converter
+ *
+ * @param sSourceMime a string containing the source Mime type
+ * @param sTargetMime a string containing the target Mime type
+ * @param bCrop true if the target graphic should be cropped
+ * @param bResize true if the target graphic should be resized
+ * (the last two parameters are for future use)
+ * @return true if the conversion is supported
+ */
+ public boolean supportsConversion(String sSourceMime, String sTargetMime, boolean bCrop, boolean bResize);
+
+ /** Convert a graphics file from one format to another
+ *
+ * @param source a byte array containing the source graphic
+ * @param sSourceMime a string containing the Mime type of the source
+ * @param sTargetMime a string containing the desired Mime type of the target
+ * @return a byte array containing the converted graphic. Returns null
+ * if the conversion failed.
+ */
+ public byte[] convert(byte[] source, String sSourceMime, String sTargetMime);
+
+}
+
+
+
diff --git a/source/java/writer2latex/api/IndexPageEntry.java b/source/java/writer2latex/api/IndexPageEntry.java
new file mode 100644
index 0000000..6d28423
--- /dev/null
+++ b/source/java/writer2latex/api/IndexPageEntry.java
@@ -0,0 +1,141 @@
+/************************************************************************
+ *
+ * IndexPageEntry.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-08)
+ *
+ */
+
+package writer2latex.api;
+
+/** This class represents a single entry on an index page created by a batch converter
+ */
+public class IndexPageEntry {
+
+ private String sFile;
+ private String sDisplayName;
+ private String sDescription = null;
+ private String sPdfFile = null;
+ private String sOriginalFile = null;
+ private boolean bIsDirectory;
+
+ /** Construct a new IndexPageEntry
based on a file name.
+ * The file name is also used as display name.
+ *
+ * @param sFile the file name for this entry
+ * @param bIsDirectory true if this is a directory, false if it is a file
+ */
+ public IndexPageEntry(String sFile, boolean bIsDirectory) {
+ this.sFile = sFile;
+ this.sDisplayName = sFile;
+ this.bIsDirectory = bIsDirectory;
+ }
+
+ /** Set the file name
+ *
+ * @param sFile the file name
+ */
+ public void setFile(String sFile) {
+ this.sFile = sFile;
+ }
+
+ /** Set the display name for this entry. The display name is the
+ * name presented on the index page.
+ *
+ * @param sDisplayName the display name
+ */
+ public void setDisplayName(String sDisplayName) {
+ this.sDisplayName = sDisplayName;
+ }
+
+ /** Set the description of this file (additional information about the file)
+ *
+ * @param sDescription the description
+ */
+ public void setDescription(String sDescription) {
+ this.sDescription = sDescription;
+ }
+
+ /** Set the file name for a pdf file associated with this file
+ *
+ * @param sPdfFile the file name
+ */
+ public void setPdfFile(String sPdfFile) {
+ this.sPdfFile = sPdfFile;
+ }
+
+ /** Set the file name for the original file
+ *
+ * @param sOriginalFile the origianl file name
+ */
+ public void setOriginalFile(String sOriginalFile) {
+ this.sOriginalFile = sOriginalFile;
+ }
+
+ /** Get the file name
+ *
+ * @return the file name
+ */
+ public String getFile() {
+ return sFile;
+ }
+
+ /** Get the display name
+ *
+ * @return the display name
+ */
+ public String getDisplayName() {
+ return sDisplayName;
+ }
+
+ /** Get the description
+ *
+ * @return the description, or null if there is no description
+ */
+ public String getDescription() {
+ return sDescription;
+ }
+
+ /** Get the pdf file name
+ *
+ * @return the file name or null if there is none
+ */
+ public String getPdfFile() {
+ return sPdfFile;
+ }
+
+ /** Get the original file name
+ *
+ * @return the file name or null if there is none
+ */
+ public String getOriginalFile() {
+ return sOriginalFile;
+ }
+
+ /** Check whether this is a file or a directory
+ *
+ * @return true for a directory, false for a file
+ */
+ public boolean isDirectory() {
+ return bIsDirectory;
+ }
+
+}
diff --git a/source/java/writer2latex/api/MIMETypes.java b/source/java/writer2latex/api/MIMETypes.java
new file mode 100644
index 0000000..6f27fed
--- /dev/null
+++ b/source/java/writer2latex/api/MIMETypes.java
@@ -0,0 +1,55 @@
+/************************************************************************
+ *
+ * MIMETypes.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+/* Some helpers to handle the MIME types used by OOo
+ */
+
+public class MIMETypes {
+ // Various graphics formats, see
+ // http://api.openoffice.org/docs/common/ref/com/sun/star/graphic/MediaProperties.html#MimeType
+ public static final String PNG="image/png";
+ public static final String JPEG="image/jpeg";
+ public static final String GIF="image/gif";
+ public static final String TIFF="image/tiff";
+ public static final String BMP="image/bmp";
+ public static final String WMF="image/x-wmf";
+ public static final String EPS="image/x-eps";
+ // MIME type for SVM has changed
+ //public static final String SVM="image/x-svm";
+ public static final String SVM="application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+ public static final String PDF="application/pdf";
+
+ // Desitination formats
+ public static final String XHTML="text/html";
+ public static final String XHTML_MATHML="application/xhtml+xml";
+ public static final String XHTML_MATHML_XSL="application/xml";
+ public static final String LATEX="application/x-latex";
+ public static final String BIBTEX="application/x-bibtex";
+ public static final String TEXT="text";
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/api/OutputFile.java b/source/java/writer2latex/api/OutputFile.java
new file mode 100644
index 0000000..78c94a5
--- /dev/null
+++ b/source/java/writer2latex/api/OutputFile.java
@@ -0,0 +1,53 @@
+/************************************************************************
+ *
+ * OutputFile.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.api;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/** An OutputFile
represent a single file in a
+ * {@link ConverterResult}, which is output from a {@link Converter}
+ * implementation.
+ */
+public interface OutputFile {
+
+ /** Writes the OutputFile
to an OutputStream
.
+ *
+ * @param os OutputStream
to which the content should be written
+ * @throws IOException if any I/O error occurs
+ */
+ public void write(OutputStream os) throws IOException;
+
+ /** Returns the file name of the OutputFile
. This includes
+ * the file extension and may also include a relative path, always using
+ * / as separator.
+ *
+ * @return the file name of this OutputFile
+ */
+ public String getFileName();
+
+}
diff --git a/source/java/writer2latex/api/Package.html b/source/java/writer2latex/api/Package.html
new file mode 100644
index 0000000..9dbd1da
--- /dev/null
+++ b/source/java/writer2latex/api/Package.html
@@ -0,0 +1,13 @@
+
+
+
+
+ writer2latex.api.BatchConverter
.
+ * The base implementation handles the traversal of directories and files, and
+ * leaves the handling of indexpages to the subclass.
+ */
+public abstract class BatchConverterBase implements BatchConverter {
+
+ private Converter converter;
+
+ public BatchConverterBase() {
+ converter = null;
+ }
+
+ // Partial implementation of the interface
+
+ public void setConverter(Converter converter) {
+ this.converter = converter;
+ }
+
+ public void convert(File source, File target, boolean bRecurse, BatchHandler handler) {
+ handler.startConversion();
+ convertDirectory(source, target, bRecurse, source.getName(), handler);
+ handler.endConversion();
+ }
+
+ protected abstract String getIndexFileName();
+
+ // Convert files and directories in the directory indir
+ // (return false if conversion has been cancelled by the BatchHandler)
+ private boolean convertDirectory(File indir, File outdir, boolean bRecurse, String sHeading, BatchHandler handler) {
+ handler.startDirectory(indir.getPath());
+
+ // Step 1: Get the directory
+ File[] contents = indir.listFiles();
+ int nLen = contents.length;
+ IndexPageEntry[] entries = new IndexPageEntry[nLen];
+
+ // Step 2: Traverse subdirectories, if allowed
+ if (bRecurse) {
+ String sUplink = getConfig().getOption("uplink");
+ for (int i=0; iwriter2latex.api.Converter
This package contains (abstract) base implementations of some of the +interfaces in writer2latex.api
+ +They are intended to be subclassed by converters into specific formats +e.g. LaTeX, xhtml
+ + + + diff --git a/source/java/writer2latex/bibtex/BibTeXDocument.java b/source/java/writer2latex/bibtex/BibTeXDocument.java new file mode 100644 index 0000000..8411de1 --- /dev/null +++ b/source/java/writer2latex/bibtex/BibTeXDocument.java @@ -0,0 +1,238 @@ +/************************************************************************ + * + * BibTeXDocument.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2009 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2009-02-17) + * + */ + +package writer2latex.bibtex; + +import writer2latex.xmerge.Document; + +import java.util.Hashtable; +import java.util.Enumeration; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import writer2latex.api.ConverterFactory; +import writer2latex.latex.LaTeXConfig; +import writer2latex.latex.i18n.ClassicI18n; +import writer2latex.latex.i18n.I18n; +import writer2latex.util.ExportNameCollection; +//import writer2latex.util.Misc; +import writer2latex.office.BibMark; + +/** + *Class representing a BibTeX document.
+ * + */ +public class BibTeXDocument implements Document { + private static final String FILE_EXTENSION = ".bib"; + + private String sName; + private Hashtable entries = new Hashtable(); + private ExportNameCollection exportNames = new ExportNameCollection(true); + private I18n i18n; + + /** + *Constructs a new BibTeX Document.
+ * + *This new document is empty. Bibliographic data must added
+ * using the put
method.
BibTeXDocument
.
+ */
+ public BibTeXDocument(String sName) {
+ this.sName = trimDocumentName(sName);
+ // Use default config (only ascii, no extra font packages)
+ i18n = new ClassicI18n(new LaTeXConfig());
+ }
+
+ /**
+ * This method is supposed to read byte
data from the InputStream.
+ * Currently it does nothing, since we don't need it.
Returns the Document
name with no file extension.
Document
name with no file extension.
+ */
+ public String getName() {
+ return sName;
+ }
+
+
+ /**
+ * Returns the Document
name with file extension.
Document
name with file extension.
+ */
+ public String getFileName() {
+ return new String(sName + FILE_EXTENSION);
+ }
+
+
+ /**
+ * Writes out the Document
content to the specified
+ * OutputStream
.
This method may not be thread-safe. + * Implementations may or may not synchronize this + * method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.
+ * + * @param osOutputStream
to write out the
+ * Document
content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ // BibTeX files are plain ascii
+ OutputStreamWriter osw = new OutputStreamWriter(os,"ASCII");
+ osw.write("%% This file was converted to BibTeX by Writer2BibTeX ver. "+ConverterFactory.getVersion()+".\n");
+ osw.write("%% See http://www.hj-gym.dk/~hj/writer2latex for more info.\n");
+ osw.write("\n");
+ Enumeration enumeration = entries.elements();
+ while (enumeration.hasMoreElements()) {
+ BibMark entry = (BibMark) enumeration.nextElement();
+ osw.write("@");
+ osw.write(entry.getEntryType().toUpperCase());
+ osw.write("{");
+ osw.write(exportNames.getExportName(entry.getIdentifier()));
+ osw.write(",\n");
+ for (int i=0; iCheck if this entry exists
+ */ + public boolean containsKey(String sIdentifier) { + return entries.containsKey(sIdentifier); + } + + /* + *Add an entry
+ */ + public void put(BibMark entry) { + entries.put(entry.getIdentifier(),entry); + exportNames.addName(entry.getIdentifier()); + } + + /* + *Get export name for an identifier
+ */ + public String getExportName(String sIdentifier) { + return exportNames.getExportName(sIdentifier); + } + + /* + * Utility method to make sure the document name is stripped of any file + * extensions before use. + */ + private String trimDocumentName(String name) { + String temp = name.toLowerCase(); + + if (temp.endsWith(FILE_EXTENSION)) { + // strip the extension + int nlen = name.length(); + int endIndex = nlen - FILE_EXTENSION.length(); + name = name.substring(0,endIndex); + } + + return name; + } +} + \ No newline at end of file diff --git a/source/java/writer2latex/bibtex/Converter.java b/source/java/writer2latex/bibtex/Converter.java new file mode 100644 index 0000000..b2b3b2e --- /dev/null +++ b/source/java/writer2latex/bibtex/Converter.java @@ -0,0 +1,91 @@ +/************************************************************************ + * + * Converter.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2001-2008 by Henrik Just + * + * All Rights Reserved. + * + * version 1.0 (2008-11-22) + * + */ + +package writer2latex.bibtex; + +import writer2latex.api.Config; +//import writer2latex.api.ConverterResult; +import writer2latex.base.ConverterBase; +import writer2latex.latex.LaTeXConfig; +import writer2latex.office.BibMark; +import writer2latex.office.XMLString; +import writer2latex.util.Misc; + +//import writer2latex.xmerge.ConvertData; +//import writer2latex.xmerge.OfficeDocument; + +import java.io.IOException; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + *BibTeX export
+ * + *This class extracts bibliographic information from an OpenDocument text file to a BibTeX data file.
+ * + */ +public final class Converter extends ConverterBase { + + // Configuration - TODO: Doesn't really use it - should use some fake config + private LaTeXConfig config; + + public Config getConfig() { return config; } + + // Constructor + public Converter() { + super(); + config = new LaTeXConfig(); + } + + /** + *Convert the data passed into the InputStream
+ * into BibTeX format.
This package contains BibTeX specific code.
+It contains a writerlatex.api.Converter
implementation for
+conversion into BibTeX, as well as code to convert to BibTeX as part of a
+conversion into LaTeX.
use_bibtex
: If true, citations will be exported as \cite
+ * commands. If false, citations will be exported as static textuse_index
: If false, the bibliography will be omitteduse_bibtex
true and external_bibtex_files
+ * empty: The citations will be exported to a BibTeX file, which will be used
+ * for the bibliographyuse_bibtex
true and external_bibtex_files
+ * non-empty: The citations will be not be exported to a BibTeX file, the
+ * files referred to by the option will be used insteaduse_bibtex
false: The bibliography will be exported as
+ * static text.
+ * bibtex_style
If BibTeX is used, this style will be applied
+ * BibConverter
to
+ * the preamble.
+ * @param pack the LaTeXDocumentPortion to which
+ * declarations of packages should be added (\\usepackage).
+ * @param decl the LaTeXDocumentPortion to which
+ * other declarations should be added.
+ */
+ public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
+ // Currently nothing; may add support for eg. natbib later
+ }
+
+ /** Process a bibliography (text:bibliography tag)
+ * @param node The element containing the Bibliography
+ * @param ldp the LaTeXDocumentPortion to which LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleBibliography (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ if (config.useBibtex()) {
+ // Use the style given in the configuration
+ // TODO: Create a bst file from the settings of the text:bibliography
+ ldp.append("\\bibliographystyle{")
+ .append(config.bibtexStyle())
+ .append("}").nl();
+
+ // Use BibTeX file from configuration, or exported BibTeX file
+ if (config.externalBibtexFiles().length()>0) {
+ ldp.append("\\bibliography{")
+ .append(config.externalBibtexFiles())
+ .append("}").nl();
+ }
+ else {
+ if (bibDoc==null) { bibDoc = new BibTeXDocument(palette.getOutFileName()); }
+ ldp.append("\\bibliography{")
+ .append(bibDoc.getName())
+ .append("}").nl();
+ }
+ }
+ else { // typeset current content
+ Element body = Misc.getChildByTagName(node,XMLString.TEXT_INDEX_BODY);
+ if (body!=null) {
+ Element title = Misc.getChildByTagName(body,XMLString.TEXT_INDEX_TITLE);
+ if (title!=null) { palette.getBlockCv().traverseBlockText(title,ldp,oc); }
+ palette.getBlockCv().traverseBlockText(body,ldp,oc);
+ }
+ }
+ }
+
+ /** Process a Bibliography Mark (text:bibliography-mark tag)
+ * @param node The element containing the Mark
+ * @param ldp the LaTeXDocumentPortion to which LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleBibliographyMark(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.useBibtex()) {
+ String sIdentifier = node.getAttribute(XMLString.TEXT_IDENTIFIER);
+ if (sIdentifier!=null) {
+ if (config.externalBibtexFiles().length()==0) {
+ if (bibDoc==null) { bibDoc = new BibTeXDocument(palette.getOutFileName()); }
+ if (!bibDoc.containsKey(sIdentifier)) {
+ bibDoc.put(new BibMark(node));
+ }
+ }
+ ldp.append("\\cite{")
+ .append(bibDoc.getExportName(sIdentifier))
+ .append("}");
+ }
+ }
+ else { // use current value
+ palette.getInlineCv().traverseInlineText(node,ldp,oc);
+ }
+ }
+
+ /** Get the BibTeX document, if any (the document is only created if it's
+ * specified in the configuration *and* the document contains bibliographic
+ * data *and* the configuration does not specify external BibTeX files
+ * @return the BiBTeXDocument, or null if it does not exist).
+ */
+ public BibTeXDocument getBibTeXDocument () {
+ return bibDoc;
+ }
+
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/latex/BlockConverter.java b/source/java/writer2latex/latex/BlockConverter.java
new file mode 100644
index 0000000..182c8c1
--- /dev/null
+++ b/source/java/writer2latex/latex/BlockConverter.java
@@ -0,0 +1,378 @@
+/************************************************************************
+ *
+ * BlockConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.latex;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import writer2latex.latex.util.BeforeAfter;
+import writer2latex.latex.util.Context;
+//import writer2latex.latex.util.HeadingMap;
+import writer2latex.latex.util.StyleMap;
+import writer2latex.office.ListStyle;
+import writer2latex.office.OfficeReader;
+//import writer2latex.office.TableReader;
+import writer2latex.office.XMLString;
+import writer2latex.util.Misc;
+
+/**
+ * This class handles basic block content, including the main text body, + * sections, tables, lists, headings and paragraphs.
+ */ +public class BlockConverter extends ConverterHelper { + + public BlockConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { + super(ofr,config,palette); + } + + public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { + // currently do nothing.. + } + + + /**Traverse block text (eg. content of body, section, list item). + * This is traversed in logical order and dedicated handlers take care of + * each block element.
+ *(Note: As a rule, all handling of block level elements should add a + * newline to the LaTeX document at the end of the block)
+ * @param node The element containing the block text + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void traverseBlockText(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ Context ic = (Context) oc.clone();
+
+ // The current paragraph block:
+ StyleMap blockMap = config.getParBlockStyleMap();
+ String sBlockName = null;
+
+ if (node.hasChildNodes()) {
+ NodeList list = node.getChildNodes();
+ int nLen = list.getLength();
+
+ for (int i = 0; i < nLen; i++) {
+ Node childNode = list.item(i);
+
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element child = (Element)childNode;
+ String sTagName = child.getTagName();
+
+ // Start/End a paragraph block (not in tables)
+ if (!ic.isInTable()) {
+ if (sTagName.equals(XMLString.TEXT_P)) {
+ String sStyleName = ofr.getParStyles().getDisplayName(child.getAttribute(XMLString.TEXT_STYLE_NAME));
+ if (sBlockName!=null && !blockMap.isNext(sBlockName,sStyleName)) {
+ // end current block
+ String sAfter = blockMap.getAfter(sBlockName);
+ if (sAfter.length()>0) ldp.append(sAfter).nl();
+ sBlockName = null;
+ ic.setVerbatim(false);
+ }
+ if (sBlockName==null && blockMap.contains(sStyleName)) {
+ // start a new block
+ sBlockName = sStyleName;
+ String sBefore = blockMap.getBefore(sBlockName);
+ if (sBefore.length()>0) ldp.append(sBefore).nl();
+ ic.setVerbatim(blockMap.getVerbatim(sStyleName));
+ }
+ }
+ else if (sBlockName!=null) {
+ // non-paragraph: end current block
+ String sAfter = blockMap.getAfter(sBlockName);
+ if (sAfter.length()>0) ldp.append(sAfter).nl();
+ sBlockName = null;
+ ic.setVerbatim(false);
+ }
+ }
+
+ palette.getFieldCv().flushReferenceMarks(ldp,ic);
+ palette.getIndexCv().flushIndexMarks(ldp,ic);
+
+ palette.getInfo().addDebugInfo(child,ldp);
+
+ // Basic block content; handle by this class
+ if (sTagName.equals(XMLString.TEXT_P)) {
+ // is this a caption?
+ String sSequence = ofr.getSequenceName(child);
+ if (ofr.isFigureSequenceName(sSequence)) {
+ palette.getDrawCv().handleCaption(child,ldp,ic);
+ }
+ else if (ofr.isTableSequenceName(sSequence)) {
+ // Next node *should* be a table
+ if (i+1Process a list (text:ordered-lst or text:unordered-list tag)
+ * @param node The element containing the list + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleList(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // Set up new context
+ Context ic = (Context) oc.clone();
+ ic.incListLevel();
+
+ // Get the style name, if we don't know it already
+ if (ic.getListStyleName()==null) {
+ ic.setListStyleName(node.getAttribute(XMLString.TEXT_STYLE_NAME));
+ }
+
+ // Use the style to determine the type of list
+ ListStyle style = ofr.getListStyle(ic.getListStyleName());
+ boolean bOrdered = style!=null && style.isNumber(ic.getListLevel());
+
+ // If the list contains headings, ignore it!
+ if (ic.isIgnoreLists() || listContainsHeadings(node)) {
+ ic.setIgnoreLists(true);
+ traverseList(node,ldp,ic);
+ return;
+ }
+
+ // Apply the style
+ BeforeAfter ba = new BeforeAfter();
+ palette.getListSc().applyListStyle(ic.getListStyleName(),ic.getListLevel(),
+ bOrdered,"true".equals(node.getAttribute(XMLString.TEXT_CONTINUE_NUMBERING)),
+ ba);
+
+ // Export the list
+ if (ba.getBefore().length()>0) { ldp.append(ba.getBefore()).nl(); }
+ traverseList(node,ldp,ic);
+ if (ba.getAfter().length()>0) { ldp.append(ba.getAfter()).nl(); }
+ }
+
+ /*
+ * Process the contents of a list
+ */
+ private void traverseList (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (node.hasChildNodes()) {
+ NodeList list = node.getChildNodes();
+ int nLen = list.getLength();
+
+ for (int i = 0; i < nLen; i++) {
+ Node child = list.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+
+ palette.getInfo().addDebugInfo((Element)child,ldp);
+
+ if (nodeName.equals(XMLString.TEXT_LIST_ITEM)) {
+ handleListItem((Element)child,ldp,oc);
+ }
+ if (nodeName.equals(XMLString.TEXT_LIST_HEADER)) {
+ handleListItem((Element)child,ldp,oc);
+ }
+ }
+ }
+ }
+ }
+
+ private void handleListItem(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // Are we ignoring this list?
+ if (oc.isIgnoreLists()) {
+ traverseBlockText(node,ldp,oc);
+ return;
+ }
+
+ // Apply the style
+ BeforeAfter ba = new BeforeAfter();
+ palette.getListSc().applyListItemStyle(
+ oc.getListStyleName(), oc.getListLevel(),
+ node.getNodeName().equals(XMLString.TEXT_LIST_HEADER),
+ "true".equals(node.getAttribute(XMLString.TEXT_RESTART_NUMBERING)),
+ Misc.getPosInteger(node.getAttribute(XMLString.TEXT_START_VALUE),1)-1,
+ ba);
+
+ // export the list item
+ if (ba.getBefore().length()>0) {
+ ldp.append(ba.getBefore());
+ if (config.formatting()>=LaTeXConfig.CONVERT_MOST) { ldp.nl(); }
+ }
+ traverseBlockText(node,ldp,oc);
+ if (ba.getAfter().length()>0) { ldp.append(ba.getAfter()).nl(); }
+ }
+
+ /*
+ * Helper: Check to see, if this list contains headings
+ * (in that case we will ignore the list!)
+ */
+ private boolean listContainsHeadings (Node node) {
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nList.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+ if (nodeName.equals(XMLString.TEXT_LIST_ITEM)) {
+ if (listItemContainsHeadings(child)) return true;
+ }
+ if (nodeName.equals(XMLString.TEXT_LIST_HEADER)) {
+ if (listItemContainsHeadings(child)) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean listItemContainsHeadings(Node node) {
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+ for (int i = 0; i < len; i++) {
+ Node child = nList.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String nodeName = child.getNodeName();
+ if(nodeName.equals(XMLString.TEXT_H)) {
+ return true;
+ }
+ if (nodeName.equals(XMLString.TEXT_LIST)) {
+ if (listContainsHeadings(child)) return true;
+ }
+ if (nodeName.equals(XMLString.TEXT_ORDERED_LIST)) {
+ if (listContainsHeadings(child)) return true;
+ }
+ if (nodeName.equals(XMLString.TEXT_UNORDERED_LIST)) {
+ if (listContainsHeadings(child)) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/latex/CaptionConverter.java b/source/java/writer2latex/latex/CaptionConverter.java
new file mode 100644
index 0000000..75f48cf
--- /dev/null
+++ b/source/java/writer2latex/latex/CaptionConverter.java
@@ -0,0 +1,163 @@
+/************************************************************************
+ *
+ * CaptionConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.latex;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import writer2latex.latex.util.Context;
+import writer2latex.office.OfficeReader;
+import writer2latex.office.XMLString;
+
+/**
+ * This class converts captions (for figures and tables) to LaTeX.
+ *Packages: + *
Options: + *
TODO: Implement formatting of captions using the features of caption.sty + * (only if formatting>=CONVERT_BASIC) + */ +public class CaptionConverter extends ConverterHelper { + + private boolean bNeedCaptionOf = false; + + private Element seqField = null; // the sequence field within the current caption + + public CaptionConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { + super(ofr,config,palette); + } + + public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { + if (bNeedCaptionOf) { + if (config.useCaption()) { + pack.append("\\usepackage{caption}").nl(); + } + else { // use definition borrowed from capt-of.sty + decl.append("% Non-floating captions").nl() + .append("\\makeatletter").nl() + .append("\\newcommand\\captionof[1]{\\def\\@captype{#1}\\caption}").nl() + .append("\\makeatother").nl(); + } + } + } + + /** + *
Process content of a text:p tag as a caption body (inluding label)
+ * @param node The text:p element node containing the caption + * @param ldp TheLaTeXDocumentPortion
to add LaTeX code to
+ * @param oc The current context
+ * @param bIsCaptionOf true if this is caption uses captionof
+ */
+ public void handleCaptionBody(Element node,LaTeXDocumentPortion ldp, Context oc, boolean bIsCaptionOf) {
+ bNeedCaptionOf|=bIsCaptionOf;
+
+ // Get rid of the caption label before converting
+ removeCaptionLabel(node,0);
+ Element label = seqField;
+ seqField = null;
+
+ // Get the stylename of the paragraph and push the font used
+ String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
+ palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getParStyle(sStyleName)));
+
+ if (palette.getHeadingCv().containsElements(node)) {
+ ldp.append("[");
+ palette.getInlineCv().traversePlainInlineText(node,ldp,oc);
+ ldp.append("]");
+ }
+ // Update context before traversing text
+ Context ic = (Context) oc.clone();
+ ldp.append("{");
+ palette.getInlineCv().traverseInlineText(node,ldp,ic);
+ ldp.append("}").nl();
+
+ // Insert label
+ palette.getFieldCv().handleSequence(label,ldp,oc);
+
+ // Flush any index marks
+ palette.getIndexCv().flushIndexMarks(ldp,oc);
+
+ // pop the font name
+ palette.getI18n().popSpecialTable();
+
+ }
+
+ // In OpenDocument a caption is an ordinary paragraph with a text:seqence
+ // element. For example
+ // Table writer2latex.latex.style.I18n
+ */
+public class CharStyleConverter extends StyleConverter {
+
+ // Cache of converted font declarations
+ private Hashtable fontDecls = new Hashtable();
+
+ // Which formatting should we export?
+ private boolean bIgnoreHardFontsize;
+ private boolean bIgnoreFontsize;
+ private boolean bIgnoreFont;
+ private boolean bIgnoreAll;
+ private boolean bUseUlem;
+ // Do we need actually use ulem.sty or \textsubscript?
+ private boolean bNeedUlem = false;
+ private boolean bNeedSubscript = false;
+
+ /** Constructs a new CharStyleConverter
.
Use a text style in LaTeX.
+ * @param sName the name of the text style + * @param ba aBeforeAfter
to put code into
+ */
+ public void applyTextStyle(String sName, BeforeAfter ba, Context context) {
+ if (sName==null) { return; }
+ String sDisplayName = ofr.getTextStyles().getDisplayName(sName);
+
+ if (bIgnoreAll) {
+ // Even if all is ignored, we still apply style maps from config..
+ StyleMap sm = config.getTextStyleMap();
+ if (sm.contains(sDisplayName)) {
+ ba.add(sm.getBefore(sDisplayName),sm.getAfter(sDisplayName));
+ }
+ return;
+ }
+
+ // Style already converted?
+ if (styleMap.contains(sName)) {
+ ba.add(styleMap.getBefore(sName),styleMap.getAfter(sName));
+ context.updateFormattingFromStyle(ofr.getTextStyle(sName));
+ // it's verbatim if specified as such in the configuration
+ StyleMap sm = config.getTextStyleMap();
+ boolean bIsVerbatim = sm.contains(sDisplayName) && sm.getVerbatim(sDisplayName);
+ context.setVerbatim(bIsVerbatim);
+ context.setNoLineBreaks(bIsVerbatim);
+ return;
+ }
+
+ // The style may already be declared in the configuration:
+ StyleMap sm = config.getTextStyleMap();
+ if (sm.contains(sDisplayName)) {
+ styleMap.put(sName,sm.getBefore(sDisplayName),sm.getAfter(sDisplayName));
+ applyTextStyle(sName,ba,context);
+ return;
+ }
+
+ // Get the style, if it exists:
+ StyleWithProperties style = ofr.getTextStyle(sName);
+ if (style==null) {
+ styleMap.put(sName,"","");
+ applyTextStyle(sName,ba,context);
+ return;
+ }
+
+ // Convert automatic style
+ if (style.isAutomatic()) {
+ palette.getI18n().applyLanguage(style,false,true,ba);
+ applyFont(style,false,true,ba,context);
+ applyFontEffects(style,true,ba);
+ context.updateFormattingFromStyle(ofr.getTextStyle(sName));
+ return;
+ }
+
+ // Convert soft style:
+ // This must be converted relative to a blank context!
+ BeforeAfter baText = new BeforeAfter();
+ palette.getI18n().applyLanguage(style,false,true,baText);
+ applyFont(style,false,true,baText,new Context());
+ applyFontEffects(style,true,baText);
+ // declare the text style (\newcommand)
+ String sTeXName = styleNames.getExportName(ofr.getTextStyles().getDisplayName(sName));
+ styleMap.put(sName,"\\textstyle"+sTeXName+"{","}");
+ declarations.append("\\newcommand\\textstyle")
+ .append(sTeXName).append("[1]{")
+ .append(baText.getBefore()).append("#1").append(baText.getAfter())
+ .append("}").nl();
+ applyTextStyle(sName,ba,context);
+ }
+
+ public String getFontName(StyleWithProperties style) {
+ if (style!=null) {
+ String sName = style.getProperty(XMLString.STYLE_FONT_NAME);
+ if (sName!=null) {
+ FontDeclaration fd = ofr.getFontDeclaration(sName);
+ if (fd!=null) {
+ return fd.getFontFamily();
+ }
+ }
+ }
+ return null;
+ }
+
+ // Get the font name from a char style
+ public String getFontName(String sStyleName) {
+ return getFontName(ofr.getTextStyle(sStyleName));
+ }
+
+ /** Apply hard character formatting (no inheritance).
+ *This is used in sections and {foot|end}notes
+ * @param style the style to use + * @param ba theBeforeAfter
to add LaTeX code to
+ */
+ public void applyHardCharFormatting(StyleWithProperties style, BeforeAfter ba) {
+ palette.getI18n().applyLanguage(style,true,false,ba);
+ applyFont(style,true,false,ba,new Context());
+ if (!ba.isEmpty()) { ba.add(" ",""); }
+ }
+
+ /** Apply all font attributes (family, series, shape, size and color).
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ public void applyFont(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (style==null) { return; }
+ applyNfssSize(style,bDecl,bInherit,ba,context);
+ applyNfssFamily(style,bDecl,bInherit,ba,context);
+ applyNfssSeries(style,bDecl,bInherit,ba,context);
+ applyNfssShape(style,bDecl,bInherit,ba,context);
+ palette.getColorCv().applyColor(style,bDecl,bInherit,ba,context);
+ }
+
+ /** Reset to normal font, size and color.
+ * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ public void applyNormalFont(BeforeAfter ba) {
+ ba.add("\\normalfont\\normalsize","");
+ palette.getColorCv().applyNormalColor(ba);
+ }
+
+ /** Apply default font attributes (family, series, shape, size and color).
+ * @param style the OOo style to read attributesfrom + * @param ldp theLaTeXDocumentPortion
to add LaTeX code to.
+ */
+ public void applyDefaultFont(StyleWithProperties style, LaTeXDocumentPortion ldp) {
+ if (style==null) { return; }
+
+ String s = convertFontDeclaration(style.getProperty(XMLString.STYLE_FONT_NAME));
+ if (s!=null){
+ ldp.append("\\renewcommand\\familydefault{\\")
+ .append(s).append("default}").nl();
+ } // TODO: Else read props directly from the style
+
+ s = nfssSeries(style.getProperty(XMLString.FO_FONT_WEIGHT));
+ if (s!=null) {
+ ldp.append("\\renewcommand\\seriesdefault{\\")
+ .append(s).append("default}").nl();
+ }
+
+ s = nfssShape(style.getProperty(XMLString.FO_FONT_VARIANT),
+ style.getProperty(XMLString.FO_FONT_STYLE));
+ if (s!=null) {
+ ldp.append("\\renewcommand\\shapedefault{\\")
+ .append(s).append("default}").nl();
+ }
+
+ palette.getColorCv().setNormalColor(style.getProperty(XMLString.FO_COLOR),ldp);
+ }
+
+ /** Apply font effects (position, underline, crossout, change case.
+ * @param style the OOo style to read attributesfrom + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ public void applyFontEffects(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style==null) { return; }
+ applyTextPosition(style, bInherit, ba);
+ applyUnderline(style, bInherit, ba);
+ applyCrossout(style, bInherit, ba);
+ applyChangeCase(style, bInherit, ba);
+ }
+
+ // Remaining methods are private
+
+ /** Apply font family.
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyNfssFamily(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (style==null || bIgnoreFont) { return; }
+ String sFontName=style.getProperty(XMLString.STYLE_FONT_NAME,bInherit);
+ if (sFontName!=null){
+ String sFamily = convertFontDeclaration(sFontName);
+ if (sFamily==null) { return; }
+ if (sFamily.equals(convertFontDeclaration(context.getFontName()))) { return; }
+ if (bDecl) { ba.add("\\"+sFamily+"family",""); }
+ else { ba.add("\\text"+sFamily+"{","}"); }
+ } // TODO: Else read props directly from the style
+ }
+
+ /** Apply font series.
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyNfssSeries(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (style!=null && !bIgnoreAll) {
+ String sSeries = nfssSeries(style.getProperty(XMLString.FO_FONT_WEIGHT,bInherit));
+ if (sSeries!=null) {
+ // Temporary: Support text-attribute style maps for this particular case
+ // TODO: Reimplement the CharStyleConverter to properly support this...
+ if (!bDecl && "bf".equals(sSeries) && config.getTextAttributeStyleMap().contains("bold")) {
+ ba.add(config.getTextAttributeStyleMap().getBefore("bold"),
+ config.getTextAttributeStyleMap().getAfter("bold"));
+ }
+ else {
+ if (style.isAutomatic()) { // optimize hard formatting
+ if (sSeries.equals(nfssSeries(context.getFontWeight()))) { return; }
+ if (context.getFontWeight()==null && sSeries.equals("md")) { return; }
+ }
+ if (bDecl) { ba.add("\\"+sSeries+"series",""); }
+ else { ba.add("\\text"+sSeries+"{","}"); }
+ }
+ }
+ }
+ }
+
+ /** Apply font shape.
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyNfssShape(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (style!=null && !bIgnoreAll) {
+ String sVariant = style.getProperty(XMLString.FO_FONT_VARIANT, bInherit);
+ String sStyle = style.getProperty(XMLString.FO_FONT_STYLE, bInherit);
+ String sShape = nfssShape(sVariant,sStyle);
+ if (sShape!=null) {
+ // Temporary: Support text-attribute style maps for this particular case
+ // TODO: Reimplement the CharStyleConverter to properly support this...
+ if (!bDecl && "sc".equals(sShape) && config.getTextAttributeStyleMap().contains("small-caps")) {
+ ba.add(config.getTextAttributeStyleMap().getBefore("small-caps"),
+ config.getTextAttributeStyleMap().getAfter("small-caps"));
+ }
+ else if (!bDecl && "it".equals(sShape) && config.getTextAttributeStyleMap().contains("italic")) {
+ ba.add(config.getTextAttributeStyleMap().getBefore("italic"),
+ config.getTextAttributeStyleMap().getAfter("italic"));
+ }
+ else {
+ if (style.isAutomatic()) { // optimize hard formatting
+ if (sShape.equals(nfssShape(context.getFontVariant(),context.getFontStyle()))) return;
+ if (context.getFontVariant()==null && context.getFontStyle()==null && sShape.equals("up")) return;
+ }
+ if (bDecl) ba.add("\\"+sShape+"shape","");
+ else ba.add("\\text"+sShape+"{","}");
+ }
+ }
+ }
+ }
+
+ /** Apply font size.
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyNfssSize(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (style==null|| bIgnoreFontsize || (bIgnoreHardFontsize && style.isAutomatic())) { return; }
+ if (style.getProperty(XMLString.FO_FONT_SIZE, bInherit)==null) { return; }
+ String sSize = nfssSize(style.getAbsoluteProperty(XMLString.FO_FONT_SIZE));
+ if (sSize==null) { return; }
+ if (sSize.equals(nfssSize(context.getFontSize()))) { return; }
+ if (bDecl) { ba.add(sSize,""); }
+ else { ba.add("{"+sSize+" ","}"); }
+ }
+
+ // Remaining methods are not context-sensitive
+
+ /** Apply text position.
+ * @param style the OOo style to read attributesfrom + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyTextPosition(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style!=null && !bIgnoreAll) {
+ String s = textPosition(style.getProperty(XMLString.STYLE_TEXT_POSITION, bInherit));
+ // Temporary: Support text-attribute style maps for this particular case
+ // TODO: Reimplement the CharStyleConverter to properly support this...
+ if (config.getTextAttributeStyleMap().contains("superscript") && "\\textsuperscript".equals(s)) {
+ ba.add(config.getTextAttributeStyleMap().getBefore("superscript"),
+ config.getTextAttributeStyleMap().getAfter("superscript"));
+ }
+ else if (config.getTextAttributeStyleMap().contains("subscript") && "\\textsubscript".equals(s)) {
+ ba.add(config.getTextAttributeStyleMap().getBefore("subscript"),
+ config.getTextAttributeStyleMap().getAfter("subscript"));
+ }
+ else if (s!=null) {
+ ba.add(s+"{","}");
+ }
+ }
+ }
+
+ /** Apply text underline.
+ * @param style the OOo style to read attributesfrom + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyUnderline(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style==null || !bUseUlem) { return; }
+ if (bIgnoreAll) { return; }
+ String sTag = ofr.isOpenDocument() ?
+ XMLString.STYLE_TEXT_UNDERLINE_STYLE :
+ XMLString.STYLE_TEXT_UNDERLINE;
+ String s = underline(style.getProperty(sTag, bInherit));
+ if (s!=null) { bNeedUlem = true; ba.add(s+"{","}"); }
+ }
+
+ /** Apply text crossout.
+ * @param style the OOo style to read attributesfrom + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyCrossout(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style==null || !bUseUlem) { return; }
+ if (bIgnoreAll) { return; }
+ String sTag = ofr.isOpenDocument() ?
+ XMLString.STYLE_TEXT_LINE_THROUGH_STYLE :
+ XMLString.STYLE_TEXT_CROSSING_OUT;
+ String s = crossout(style.getProperty(sTag, bInherit));
+ if (s!=null) { bNeedUlem = true; ba.add(s+"{","}"); }
+ }
+
+ /** Apply change case.
+ * @param style the OOo style to read attributesfrom + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ private void applyChangeCase(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style==null) { return; }
+ if (bIgnoreAll) { return; }
+ String s = changeCase(style.getProperty(XMLString.FO_TEXT_TRANSFORM));
+ if (s!=null) { ba.add(s+"{","}"); }
+ }
+
+ /** Convert font declarations to LaTeX.
+ *It returns a generic LaTeX font family (rm, tt, sf).
+ *It returns null if the font declaration doesn't exist.
+ * @param sName the name of the font declaration + * @returnString
with a LaTeX generic fontfamily
+ */
+ private String convertFontDeclaration(String sName) {
+ FontDeclaration fd = ofr.getFontDeclaration(sName);
+ if (fd==null) { return null; }
+ if (!fontDecls.containsKey(sName)) {
+ String sFontFamily = fd.getFontFamily();
+ String sFontPitch = fd.getFontPitch();
+ String sFontFamilyGeneric = fd.getFontFamilyGeneric();
+ fontDecls.put(sName,nfssFamily(sFontFamily,sFontFamilyGeneric,sFontPitch));
+ }
+ return (String) fontDecls.get(sName);
+ }
+
+ // The remaining methods are static helpers to convert single style properties
+
+ // Font change. These methods return the declaration form if the paramater
+ // bDecl is true, and otherwise the command form
+
+ private static final String nfssFamily(String sFontFamily, String sFontFamilyGeneric,
+ String sFontPitch){
+ // Note: Defaults to rm
+ // TODO: What about decorative, script, system?
+ if ("fixed".equals(sFontPitch)) return "tt";
+ else if ("modern".equals(sFontFamilyGeneric)) return "tt";
+ else if ("swiss".equals(sFontFamilyGeneric)) return "sf";
+ else return "rm";
+ }
+
+ private static final String nfssSeries(String sFontWeight){
+ if (sFontWeight==null) return null;
+ if ("bold".equals(sFontWeight)) return "bf";
+ else return "md";
+ }
+
+ private static final String nfssShape(String sFontVariant, String sFontStyle){
+ if (sFontVariant==null && sFontStyle==null) return null;
+ if ("small-caps".equals(sFontVariant)) return "sc";
+ else if ("italic".equals(sFontStyle)) return "it";
+ else if ("oblique".equals(sFontStyle)) return "sl";
+ else return "up";
+ }
+
+ private static final String nfssSize(String sFontSize){
+ if (sFontSize==null) return null;
+ return "\\fontsize{"+sFontSize+"}{"+Misc.multiply("120%",sFontSize)+"}\\selectfont";
+ }
+
+ // other character formatting
+
+ private final String textPosition(String sTextPosition){
+ if (sTextPosition==null) return null;
+ if (sTextPosition.startsWith("super")) return "\\textsuperscript";
+ if (sTextPosition.startsWith("sub") || sTextPosition.startsWith("-")) {
+ bNeedSubscript = true;
+ return "\\textsubscript";
+ }
+ if (sTextPosition.startsWith("0%")) return null;
+ return "\\textsuperscript";
+ }
+
+ private static final String underline(String sUnderline) {
+ if (sUnderline==null) { return null; }
+ if (sUnderline.equals("none")) { return null; }
+ if (sUnderline.indexOf("wave")>=0) { return "\\uwave"; }
+ return "\\uline";
+ }
+
+ private static final String crossout(String sCrossout) {
+ if (sCrossout==null) { return null; }
+ if (sCrossout.equals("X")) { return "\\xout"; }
+ if (sCrossout.equals("slash")) { return "\\xout"; }
+ return "\\sout";
+ }
+
+ private static final String changeCase(String sTextTransform){
+ if ("lowercase".equals(sTextTransform)) return "\\MakeLowercase";
+ if ("uppercase".equals(sTextTransform)) return "\\MakeUppercase";
+ return null;
+ }
+
+}
diff --git a/source/java/writer2latex/latex/ColorConverter.java b/source/java/writer2latex/latex/ColorConverter.java
new file mode 100644
index 0000000..173fe64
--- /dev/null
+++ b/source/java/writer2latex/latex/ColorConverter.java
@@ -0,0 +1,202 @@
+/************************************************************************
+ *
+ * ColorConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.latex;
+
+import writer2latex.latex.util.BeforeAfter;
+import writer2latex.latex.util.Context;
+import writer2latex.office.OfficeReader;
+import writer2latex.office.StyleWithProperties;
+import writer2latex.office.XMLString;
+import writer2latex.util.Misc;
+
+
+/** This class converts color
+ */
+public class ColorConverter extends ConverterHelper {
+
+ private static final int RED = 0;
+ private static final int GREEN = 1;
+ private static final int BLUE = 2;
+
+ private boolean bUseColor;
+
+ /** Constructs a new CharStyleConverter
.
Apply foreground color.
+ * @param style the OOo style to read attributesfrom + * @param bDecl true if declaration form is required + * @param bInherit true if inherited properties should be used + * @param ba theBeforeAfter
to add LaTeX code to.
+ * @param context the current context
+ */
+ public void applyColor(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (bUseColor && style!=null) {
+ String sColor = style.getProperty(XMLString.FO_COLOR,bInherit);
+ if (sColor!=null) {
+ if (!sColor.equals(context.getFontColor())) {
+ // Convert color if it differs from the current font color
+ context.setFontColor(sColor);
+ applyColor(sColor, bDecl, ba, context);
+ }
+ }
+ else {
+ // No color; maybe automatic color?
+ String sAutomatic = style.getProperty(XMLString.STYLE_USE_WINDOW_FONT_COLOR,bInherit);
+ if (sAutomatic==null && bInherit) {
+ // We may need to inherit this property from the default style
+ StyleWithProperties defaultStyle = ofr.getDefaultParStyle();
+ if (defaultStyle!=null) {
+ sAutomatic = defaultStyle.getProperty(XMLString.STYLE_USE_WINDOW_FONT_COLOR,bInherit);
+ }
+ }
+ if ("true".equals(sAutomatic)) {
+ // Automatic color based on background
+ if (context.getBgColor()!=null) { applyAutomaticColor(ba,bDecl,context); }
+ }
+ }
+ }
+ }
+
+ /** Apply a specific foreground color.
+ * @param sColor the rgb color to use + * @param bDecl true if declaration form is required + * @param ba theBeforeAfter
to add LaTeX code to.
+ */
+ public void applyColor(String sColor, boolean bDecl, BeforeAfter ba, Context context) {
+ // Note: if bDecl is true, nothing will be put in the "after" part of ba.
+ if (bUseColor && sColor!=null) {
+ // If there's a background color, allow all colors
+ String s = context.getBgColor()!=null ? fullcolor(sColor) : color(sColor);
+ if (s!=null) {
+ if (bDecl) { ba.add("\\color"+s,""); }
+ else { ba.add("\\textcolor"+s+"{","}"); }
+ }
+ }
+ }
+
+ public void applyBgColor(String sCommand, String sColor, BeforeAfter ba, Context context) {
+ // Note: Will only fill "before" part of ba
+ if (sColor!=null && !"transparent".equals(sColor)) {
+ String s = fullcolor(sColor);
+ if (bUseColor && s!=null) {
+ context.setBgColor(sColor);
+ ba.add(sCommand+s,"");
+ }
+ }
+ }
+
+ public void applyAutomaticColor(BeforeAfter ba, boolean bDecl, Context context) {
+ String s = automaticcolor(context.getBgColor());
+ if (s!=null) {
+ if (bDecl) { ba.add("\\color"+s,""); }
+ else { ba.add("\\textcolor"+s+"{","}"); }
+ }
+ }
+
+ private static final String automaticcolor(String sBgColor) {
+ if (sBgColor!=null && sBgColor.length()==7) {
+ float[] rgb = getRgb(sBgColor);
+ if (rgb[RED]+rgb[GREEN]+rgb[BLUE]<0.6) {
+ // Dark background
+ return "{white}";
+ }
+ }
+ return "{black}";
+ }
+
+ private static final String color(String sColor){
+ if ("#000000".equalsIgnoreCase(sColor)) { return "{black}"; }
+ else if ("#ff0000".equalsIgnoreCase(sColor)) { return "{red}"; }
+ else if ("#00ff00".equalsIgnoreCase(sColor)) { return "{green}"; }
+ else if ("#0000ff".equalsIgnoreCase(sColor)) { return "{blue}"; }
+ else if ("#ffff00".equalsIgnoreCase(sColor)) { return "{yellow}"; }
+ else if ("#ff00ff".equalsIgnoreCase(sColor)) { return "{magenta}"; }
+ else if ("#00ffff".equalsIgnoreCase(sColor)) { return "{cyan}"; }
+ //no white, since we don't have background colors:
+ //else if ("#ffffff".equalsIgnoreCase(sColor)) { return "{white}"; }
+ else {
+ if (sColor==null || sColor.length()!=7) return null;
+ float[] rgb = getRgb(sColor);
+ // avoid very bright colors (since we don't have background colors):
+ if (rgb[RED]+rgb[GREEN]+rgb[BLUE]>2.7) { return "{black}"; }
+ else { return "[rgb]{"+rgb[RED]+","+rgb[GREEN]+","+rgb[BLUE]+"}"; }
+ }
+ }
+
+ private static final String fullcolor(String sColor){
+ if ("#000000".equalsIgnoreCase(sColor)) { return "{black}"; }
+ else if ("#ff0000".equalsIgnoreCase(sColor)) { return "{red}"; }
+ else if ("#00ff00".equalsIgnoreCase(sColor)) { return "{green}"; }
+ else if ("#0000ff".equalsIgnoreCase(sColor)) { return "{blue}"; }
+ else if ("#ffff00".equalsIgnoreCase(sColor)) { return "{yellow}"; }
+ else if ("#ff00ff".equalsIgnoreCase(sColor)) { return "{magenta}"; }
+ else if ("#00ffff".equalsIgnoreCase(sColor)) { return "{cyan}"; }
+ else if ("#ffffff".equalsIgnoreCase(sColor)) { return "{white}"; }
+ else {
+ // This could mean transparent:
+ if (sColor==null || sColor.length()!=7) return null;
+ float[] rgb = getRgb(sColor);
+ return "[rgb]{"+rgb[RED]+","+rgb[GREEN]+","+rgb[BLUE]+"}";
+ }
+ }
+
+ private static final float[] getRgb(String sColor) {
+ float[] rgb = new float[3];
+ rgb[RED] = (float)Misc.getIntegerFromHex(sColor.substring(1,3),0)/255;
+ rgb[GREEN] = (float)Misc.getIntegerFromHex(sColor.substring(3,5),0)/255;
+ rgb[BLUE] = (float)Misc.getIntegerFromHex(sColor.substring(5,7),0)/255;
+ return rgb;
+ }
+
+
+}
diff --git a/source/java/writer2latex/latex/ContentHandlingOption.java b/source/java/writer2latex/latex/ContentHandlingOption.java
new file mode 100644
index 0000000..166afb0
--- /dev/null
+++ b/source/java/writer2latex/latex/ContentHandlingOption.java
@@ -0,0 +1,43 @@
+/************************************************************************
+ *
+ * ContentHandlingOption.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-09-08)
+ *
+ */
+
+package writer2latex.latex;
+
+import writer2latex.base.IntegerOption;
+
+public class ContentHandlingOption extends IntegerOption {
+ public ContentHandlingOption(String sName, String sDefaultValue) {
+ super(sName,sDefaultValue);
+ }
+
+ public void setString(String sValue) {
+ super.setString(sValue);
+ if ("accept".equals(sValue)) nValue = LaTeXConfig.ACCEPT;
+ else if ("ignore".equals(sValue)) nValue = LaTeXConfig.IGNORE;
+ else if ("warning".equals(sValue)) nValue = LaTeXConfig.WARNING;
+ else if ("error".equals(sValue)) nValue = LaTeXConfig.ERROR;
+ }
+}
diff --git a/source/java/writer2latex/latex/ConverterHelper.java b/source/java/writer2latex/latex/ConverterHelper.java
new file mode 100644
index 0000000..56eeeb8
--- /dev/null
+++ b/source/java/writer2latex/latex/ConverterHelper.java
@@ -0,0 +1,49 @@
+/************************************************************************
+ *
+ * ConverterHelper.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-09-08)
+ *
+ */
+
+package writer2latex.latex;
+
+import writer2latex.office.OfficeReader;
+
+/**
+ * This is an abstract superclass for converter helpers.
+ */ +public abstract class ConverterHelper { + + protected OfficeReader ofr; + protected LaTeXConfig config; + protected ConverterPalette palette; + + protected ConverterHelper(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { + this.ofr = ofr; + this.config = config; + this.palette = palette; + } + + public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { + } + +} \ No newline at end of file diff --git a/source/java/writer2latex/latex/ConverterPalette.java b/source/java/writer2latex/latex/ConverterPalette.java new file mode 100644 index 0000000..82896fa --- /dev/null +++ b/source/java/writer2latex/latex/ConverterPalette.java @@ -0,0 +1,303 @@ +/************************************************************************ + * + * ConverterPalette.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2009 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2009-02-17) + * + */ + +package writer2latex.latex; + +import org.w3c.dom.Element; + +import java.io.IOException; +import java.util.LinkedList; + +import writer2latex.api.Config; +import writer2latex.api.ConverterFactory; +//import writer2latex.api.ConverterResult; +import writer2latex.base.ConverterBase; +import writer2latex.latex.i18n.ClassicI18n; +import writer2latex.latex.i18n.I18n; +import writer2latex.latex.i18n.XeTeXI18n; +import writer2latex.latex.util.Context; +import writer2latex.latex.util.Info; +import writer2latex.util.CSVList; +import writer2latex.util.ExportNameCollection; +import writer2latex.util.Misc; +import writer2latex.office.MIMETypes; +import writer2latex.office.StyleWithProperties; +import writer2latex.office.XMLString; + +/** + *This class converts a Writer XML file to a LaTeX file<.
+ */ +public final class ConverterPalette extends ConverterBase { + + // Configuration + private LaTeXConfig config; + + public Config getConfig() { return config; } + + // The main outfile + private LaTeXDocument texDoc; + + // Various data used in conversion + private Context mainContext; // main context + private CSVList globalOptions; // global options + + // The helpers (the "colors" of the palette) + private I18n i18n; + private ColorConverter colorCv; + private CharStyleConverter charSc; + private ListStyleConverter listSc; + private PageStyleConverter pageSc; + private BlockConverter blockCv; + private ParConverter parCv; + private HeadingConverter headingCv; + private IndexConverter indexCv; + private BibConverter bibCv; + private SectionConverter sectionCv; + private TableConverter tableCv; + private NoteConverter noteCv; + private CaptionConverter captionCv; + private InlineConverter inlineCv; + private FieldConverter fieldCv; + private DrawConverter drawCv; + private MathmlConverter mathmlCv; + private Info info; + + // Constructor + public ConverterPalette() { + super(); + config = new LaTeXConfig(); + } + + // Accessor methods for data + + public String getOutFileName() { return sTargetFileName; } + + public Context getMainContext() { return mainContext; } + + public void addGlobalOption(String sOption) { + globalOptions.addValue(sOption); + } + + // Accessor methods for helpers + public I18n getI18n() { return i18n; } + public ColorConverter getColorCv() { return colorCv; } + public CharStyleConverter getCharSc() { return charSc; } + public ListStyleConverter getListSc() { return listSc; } + public PageStyleConverter getPageSc() { return pageSc; } + public BlockConverter getBlockCv() { return blockCv; } + public ParConverter getParCv() { return parCv; } + public HeadingConverter getHeadingCv() { return headingCv; } + public IndexConverter getIndexCv() { return indexCv; } + public BibConverter getBibCv() { return bibCv; } + public SectionConverter getSectionCv() { return sectionCv; } + public TableConverter getTableCv() { return tableCv; } + public NoteConverter getNoteCv() { return noteCv; } + public CaptionConverter getCaptionCv() { return captionCv; } + public InlineConverter getInlineCv() { return inlineCv; } + public FieldConverter getFieldCv() { return fieldCv; } + public DrawConverter getDrawCv() { return drawCv; } + public MathmlConverter getMathmlCv() { return mathmlCv; } + public Info getInfo() { return info; } + + + // fill out inner converter method + public void convertInner() throws IOException { + sTargetFileName = Misc.trimDocumentName(sTargetFileName,".tex"); + imageLoader.setOutFileName(new ExportNameCollection(true).getExportName(sTargetFileName)); + + imageLoader.setUseSubdir(config.saveImagesInSubdir()); + + // Set graphics formats depending on backend + if (config.getBackend()==LaTeXConfig.PDFTEX || config.getBackend()==LaTeXConfig.XETEX) { + imageLoader.setDefaultFormat(MIMETypes.PNG); + imageLoader.setDefaultVectorFormat(MIMETypes.PDF); + imageLoader.addAcceptedFormat(MIMETypes.JPEG); + } + else if (config.getBackend()==LaTeXConfig.DVIPS) { + imageLoader.setDefaultFormat(MIMETypes.EPS); + } + // Other values: keep original format + + // Inject user sequence names for tables and figures into OfficeReader + if (config.getTableSequenceName().length()>0) { + ofr.addTableSequenceName(config.getTableSequenceName()); + } + if (config.getFigureSequenceName().length()>0) { + ofr.addFigureSequenceName(config.getFigureSequenceName()); + } + + // Create helpers + if (config.getBackend()!=LaTeXConfig.XETEX) { + i18n = new ClassicI18n(ofr,config,this); + } + else { + i18n = new XeTeXI18n(ofr,config,this); + } + colorCv = new ColorConverter(ofr,config,this); + charSc = new CharStyleConverter(ofr,config,this); + listSc = new ListStyleConverter(ofr,config,this); + pageSc = new PageStyleConverter(ofr,config,this); + blockCv = new BlockConverter(ofr,config,this); + parCv = new ParConverter(ofr,config,this); + headingCv = new HeadingConverter(ofr,config,this); + indexCv = new IndexConverter(ofr,config,this); + bibCv = new BibConverter(ofr,config,this); + sectionCv = new SectionConverter(ofr,config,this); + tableCv = new TableConverter(ofr,config,this); + noteCv = new NoteConverter(ofr,config,this); + captionCv = new CaptionConverter(ofr,config,this); + inlineCv = new InlineConverter(ofr,config,this); + fieldCv = new FieldConverter(ofr,config,this); + drawCv = new DrawConverter(ofr,config,this); + mathmlCv = new MathmlConverter(ofr,config,this); + info = new Info(ofr,config,this); + + // Create master document and add this + this.texDoc = new LaTeXDocument(sTargetFileName,config.getWrapLinesAfter()); + if (config.getBackend()!=LaTeXConfig.XETEX) { + texDoc.setEncoding(ClassicI18n.writeJavaEncoding(config.getInputencoding())); + } + else { + texDoc.setEncoding("UTF-8"); + + } + convertData.addDocument(texDoc); + + // Create other data + globalOptions = new CSVList(','); + + // Setup context. + // The default language is specified in the default paragraph style: + mainContext = new Context(); + mainContext.resetFormattingFromStyle(ofr.getDefaultParStyle()); + mainContext.setInMulticols(pageSc.isTwocolumn()); + + // Create main LaTeXDocumentPortions + LaTeXDocumentPortion packages = new LaTeXDocumentPortion(false); + LaTeXDocumentPortion declarations = new LaTeXDocumentPortion(false); + LaTeXDocumentPortion body = new LaTeXDocumentPortion(true); + + // Traverse the content + Element content = ofr.getContent(); + blockCv.traverseBlockText(content,body,mainContext); + noteCv.insertEndnotes(body); + + // Add declarations from our helpers + i18n.appendDeclarations(packages,declarations); + colorCv.appendDeclarations(packages,declarations); + charSc.appendDeclarations(packages,declarations); + headingCv.appendDeclarations(packages,declarations); + parCv.appendDeclarations(packages,declarations); + listSc.appendDeclarations(packages,declarations); + pageSc.appendDeclarations(packages,declarations); + blockCv.appendDeclarations(packages,declarations); + indexCv.appendDeclarations(packages,declarations); + bibCv.appendDeclarations(packages,declarations); + sectionCv.appendDeclarations(packages,declarations); + tableCv.appendDeclarations(packages,declarations); + noteCv.appendDeclarations(packages,declarations); + captionCv.appendDeclarations(packages,declarations); + inlineCv.appendDeclarations(packages,declarations); + fieldCv.appendDeclarations(packages,declarations); + drawCv.appendDeclarations(packages,declarations); + mathmlCv.appendDeclarations(packages,declarations); + + // Add custom preamble + LinkedList customPreamble = config.getCustomPreamble(); + int nCPLen = customPreamble.size(); + for (int i=0; iThis class handles draw elements.
+ */ +public class DrawConverter extends ConverterHelper { + + private boolean bNeedGraphicx = false; + private boolean bNeedOOoLaTeXPreamble = false; + + // Keep track of floating frames (images, textboxes...) + private Stack floatingFramesStack = new Stack(); + + private Element getFrame(Element onode) { + if (ofr.isOpenDocument()) return (Element) onode.getParentNode(); + else return onode; + } + + public DrawConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { + super(ofr,config,palette); + floatingFramesStack.push(new LinkedList()); + } + + public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { + if (bNeedGraphicx) { + pack.append("\\usepackage"); + if (config.getBackend()==LaTeXConfig.PDFTEX) pack.append("[pdftex]"); + //else if (config.getBackend()==LaTeXConfig.XETEX) pack.append("[xetex]"); + else if (config.getBackend()==LaTeXConfig.DVIPS) pack.append("[dvips]"); + pack.append("{graphicx}").nl(); + } + if (bNeedOOoLaTeXPreamble) { + // The preamble may be stored in the description + String sDescription = palette.getMetaData().getDescription(); + int nStart = sDescription.indexOf("%%% OOoLatex Preamble %%%%%%%%%%%%%%"); + int nEnd = sDescription.indexOf("%%% End OOoLatex Preamble %%%%%%%%%%%%"); + if (nStart>-1 && nEnd>nStart) { + decl.append("% OOoLaTeX preamble").nl() + .append(sDescription.substring(nStart+37,nEnd)); + } + // TODO: Otherwise try the user settings... + } + } + + public void handleCaption(Element node, LaTeXDocumentPortion ldp, Context oc) { + // Floating frames should be positioned *above* the label, hence + // we use a separate ldp for the paragraphs and add this later + LaTeXDocumentPortion capLdp = new LaTeXDocumentPortion(true); + + // Convert the caption + if (oc.isInFigureFloat()) { // float + capLdp.append("\\caption"); + palette.getCaptionCv().handleCaptionBody(node,capLdp,oc,false); + } + else { // nonfloat + capLdp.append("\\captionof{figure}"); + palette.getCaptionCv().handleCaptionBody(node,capLdp,oc,true); + } + + flushFloatingFrames(ldp,oc); + ldp.append(capLdp); + } + + public void handleDrawElement(Element node, LaTeXDocumentPortion ldp, Context oc) { + // node must be an elment in the draw namespace + String sName = node.getTagName(); + if (sName.equals(XMLString.DRAW_OBJECT)) { + handleDrawObject(node,ldp,oc); + } + else if (sName.equals(XMLString.DRAW_OBJECT_OLE)) { + handleDrawObject(node,ldp,oc); + } + else if ((!oc.isInHeaderFooter()) && sName.equals(XMLString.DRAW_IMAGE)) { + handleDrawImage(node,ldp,oc); + } + else if ((!oc.isInHeaderFooter()) && sName.equals(XMLString.DRAW_TEXT_BOX)) { + handleDrawTextBox(node,ldp,oc); + } + else if (sName.equals(XMLString.DRAW_A)) { + // we handle this like text:a + palette.getFieldCv().handleAnchor(node,ldp,oc); + } + else if (sName.equals(XMLString.DRAW_FRAME)) { + // OpenDocument: Get the actual draw element in the frame + handleDrawElement(Misc.getFirstChildElement(node),ldp,oc); + } + else { + // Other drawing objects (eg. shapes) are currently not supported + ldp.append("[Warning: Draw object ignored]"); + } + } + + //----------------------------------------------------------------- + // handle draw:object elements (OOo objects such as Chart, Math,...) + + private void handleDrawObject(Element node, LaTeXDocumentPortion ldp, Context oc) { + String sHref = Misc.getAttribute(node,XMLString.XLINK_HREF); + + if (sHref!=null) { // Embedded object in package or linked object + if (ofr.isInPackage(sHref)) { // Embedded object in package + if (sHref.startsWith("#")) { sHref=sHref.substring(1); } + if (sHref.startsWith("./")) { sHref=sHref.substring(2); } + EmbeddedObject object = palette.getEmbeddedObject(sHref); + if (object!=null) { + if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula! + try { + Document settings = ((EmbeddedXMLObject) object).getSettingsDOM(); + Document formuladoc = ((EmbeddedXMLObject) object).getContentDOM(); + Element formula = Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH); + ldp.append(" $") + .append(palette.getMathmlCv().convert(settings,formula)) + .append("$"); + if (Character.isLetterOrDigit(OfficeReader.getNextChar(node))) { ldp.append(" "); } + } + catch (org.xml.sax.SAXException e) { + e.printStackTrace(); + } + catch (java.io.IOException e) { + e.printStackTrace(); + } + } + else { // unsupported object + boolean bIgnore = true; + if (ofr.isOpenDocument()) { // look for replacement image + Element replacementImage = Misc.getChildByTagName(getFrame(node),XMLString.DRAW_IMAGE); + if (replacementImage!=null) { + handleDrawImage(replacementImage,ldp,oc); + bIgnore = false; + } + } + if (bIgnore) { + ldp.append("[Warning: object ignored]"); + } + } + + } + } + } + else { // flat xml, object is contained in node + Element formula = Misc.getChildByTagName(node,XMLString.MATH_MATH); + if (formula!=null) { + ldp.append(" $") + .append(palette.getMathmlCv().convert(null,formula)) + .append("$"); + if (Character.isLetterOrDigit(OfficeReader.getNextChar(node))) { ldp.append(" "); } + } + else { // unsupported object + boolean bIgnore = true; + if (ofr.isOpenDocument()) { // look for replacement image + Element replacementImage = Misc.getChildByTagName(getFrame(node),XMLString.DRAW_IMAGE); + if (replacementImage!=null) { + handleDrawImage(replacementImage,ldp,oc); + bIgnore = false; + } + } + if (bIgnore) { + ldp.append("[Warning: object ignored]"); + } + } + + } + + } + + //-------------------------------------------------------------------------- + // Create float environment + private void applyFigureFloat(BeforeAfter ba, Context oc) { + // todo: check context... + if (config.floatFigures() && !oc.isInFrame() && !oc.isInTable()) { + if (oc.isInMulticols()) { + ba.add("\\begin{figure*}","\\end{figure*}\n"); + } + else { + ba.add("\\begin{figure}","\\end{figure}\n"); + } + if (config.getFloatOptions().length()>0) { + ba.add("["+config.getFloatOptions()+"]",""); + } + ba.add("\n",""); + oc.setInFigureFloat(true); + } + if (!oc.isInFrame() && config.alignFrames()) { + // Avoid nesting center environment + ba.add("\\begin{center}\n","\n\\end{center}\n"); + } + + } + + //-------------------------------------------------------------------------- + // Handle draw:image elements + + private void handleDrawImage(Element node, LaTeXDocumentPortion ldp, Context oc) { + // Include graphics if allowed by the configuration + switch (config.imageContent()) { + case LaTeXConfig.IGNORE: + // Ignore graphics silently + return; + case LaTeXConfig.WARNING: + System.err.println("Warning: Images are not allowed"); + return; + case LaTeXConfig.ERROR: + ldp.append("% Error in document: An image was ignored"); + return; + } + + Element frame = getFrame(node); + //String sName = frame.getAttribute(XMLString.DRAW_NAME); + palette.getFieldCv().addTarget(frame,"|graphics",ldp); + String sAnchor = frame.getAttribute(XMLString.TEXT_ANCHOR_TYPE); + + // TODO: Recognize Jex equations (needs further testing of Jex) + /*Element desc = Misc.getChildByTagName(frame,XMLString.SVG_DESC); + if (desc!=null) { + String sDesc = Misc.getPCDATA(desc); + if (sDesc.startsWith("jex149$tex={") && sDesc.endsWith("}")) { + String sTeX = sDesc.substring(12,sDesc.length()-1); + if (sTeX.length()>0) { + // Succesfully extracted Jex equation! + ldp.append("$"+sTeX+"$"); + return; + } + } + }*/ + + // Recognize OOoLaTeX equation + // The LaTeX code is embedded in a custom style attribute: + StyleWithProperties style = ofr.getFrameStyle( + Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME)); + if (style!=null) { + String sOOoLaTeX = style.getProperty("OOoLatexArgs"); + // The content of the attribute isAppend declarations needed by the FieldConverter
to
+ * the preamble.
LaTeXDocumentPortion
to which
+ * declarations of packages should be added (\\usepackage
).
+ * @param decl the LaTeXDocumentPortion
to which
+ * other declarations should be added.
+ */
+ public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
+ // use lastpage.sty
+ if (bUsesPageCount) {
+ pack.append("\\usepackage{lastpage}").nl();
+ }
+
+ // use titleref.sty
+ if (bUsesTitleref) {
+ pack.append("\\usepackage{titleref}").nl();
+ }
+
+ // use oooref.sty
+ if (bUsesOooref) {
+ pack.append("\\usepackage[");
+ HeadingMap hm = config.getHeadingMap();
+ CSVList opt = new CSVList(",");
+ for (int i=0; i<=hm.getMaxLevel(); i++) { opt.addValue(hm.getName(i)); }
+ pack.append(opt.toString()).append("]{oooref}").nl();
+ }
+
+ // use hyperref.sty
+ if (bUseHyperref){
+ pack.append("\\usepackage{hyperref}").nl();
+ pack.append("\\hypersetup{");
+ if (config.getBackend()==LaTeXConfig.PDFTEX) pack.append("pdftex, ");
+ else if (config.getBackend()==LaTeXConfig.DVIPS) pack.append("dvips, ");
+ //else pack.append("hypertex");
+ pack.append("colorlinks=true, linkcolor=blue, citecolor=blue, filecolor=blue, urlcolor=blue");
+ if (config.getBackend()==LaTeXConfig.PDFTEX) {
+ pack.append(createPdfMeta("pdftitle",palette.getMetaData().getTitle()));
+ if (config.metadata()) {
+ pack.append(createPdfMeta("pdfauthor",palette.getMetaData().getCreator()))
+ .append(createPdfMeta("pdfsubject",palette.getMetaData().getSubject()))
+ .append(createPdfMeta("pdfkeywords",palette.getMetaData().getKeywords()));
+ }
+ }
+ pack.append("}").nl();
+ }
+
+ // Export sequence declarations
+ // The number format is fetched from the first occurence of the
+ // sequence in the text, while the outline level and the separation
+ // character are fetched from the declaration
+ Enumeration names = seqFirst.keys();
+ while (names.hasMoreElements()) {
+ // Get first text:sequence element
+ String sName = (String) names.nextElement();
+ Element first = (Element) seqFirst.get(sName);
+ // Collect data
+ String sNumFormat = Misc.getAttribute(first,XMLString.STYLE_NUM_FORMAT);
+ if (sNumFormat==null) { sNumFormat="1"; }
+ int nLevel = 0;
+ String sSepChar = ".";
+ if (seqDecl.containsKey(sName)) {
+ Element sdecl = (Element) seqDecl.get(sName);
+ nLevel = Misc.getPosInteger(sdecl.getAttribute(XMLString.TEXT_DISPLAY_OUTLINE_LEVEL),0);
+ if (sdecl.hasAttribute(XMLString.TEXT_SEPARATION_CHARACTER)) {
+ sSepChar = palette.getI18n().convert(
+ sdecl.getAttribute(XMLString.TEXT_SEPARATION_CHARACTER),
+ false,palette.getMainContext().getLang());
+ }
+ }
+ // Create counter
+ decl.append("\\newcounter{")
+ .append(seqnames.getExportName(sName))
+ .append("}");
+ String sPrefix = "";
+ if (nLevel>0) {
+ HeadingMap hm = config.getHeadingMap();
+ int nUsedLevel = nLevel<=hm.getMaxLevel() ? nLevel : hm.getMaxLevel();
+ if (nUsedLevel>0) {
+ decl.append("[").append(hm.getName(nUsedLevel)).append("]");
+ sPrefix = "\\the"+hm.getName(nUsedLevel)+sSepChar;
+ }
+ }
+ decl.nl()
+ .append("\\renewcommand\\the")
+ .append(seqnames.getExportName(sName))
+ .append("{").append(sPrefix)
+ .append(ListStyleConverter.numFormat(sNumFormat))
+ .append("{").append(seqnames.getExportName(sName))
+ .append("}}").nl();
+ }
+ }
+
+ /** Process sequence declarations
+ * @param node the text:sequence-decls node + */ + public void handleSequenceDecls(Element node) { + Node child = node.getFirstChild(); + while (child!=null) { + if (Misc.isElement(child,XMLString.TEXT_SEQUENCE_DECL)) { + // Don't process the declaration, but store a reference + seqDecl.put(((Element)child).getAttribute(XMLString.TEXT_NAME),child); + } + child = child.getNextSibling(); + } + } + + /**Process a sequence field (text:sequence tag)
+ * @param node The element containing the sequence field + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleSequence(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sName = Misc.getAttribute(node,XMLString.TEXT_NAME);
+ String sRefName = Misc.getAttribute(node,XMLString.TEXT_REF_NAME);
+ String sFormula = Misc.getAttribute(node,XMLString.TEXT_FORMULA);
+ if (sFormula==null) {
+ // If there's no formula, we must use the content as formula
+ // The parser below requires a namespace, so we add that..
+ sFormula = "ooow:"+Misc.getPCDATA(node);
+ }
+ if (sName!=null) {
+ if (ofr.isFigureSequenceName(sName) || ofr.isTableSequenceName(sName)) {
+ // Export \label only, assuming the number is generated by \caption
+ if (sRefName!=null && ofr.hasSequenceRefTo(sRefName)) {
+ ldp.append("\\label{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ }
+ }
+ else {
+ // General purpose sequence -> export as counter
+ if (!seqFirst.containsKey(sName)) {
+ // Save first occurence -> used to determine number format
+ seqFirst.put(sName,node);
+ }
+ if (sRefName!=null && ofr.hasSequenceRefTo(sRefName)) {
+ // Export as {\refstepcounter{name}\thename\label{refname}}
+ ldp.append("{").append(changeCounter(sName,sFormula,true))
+ .append("\\the").append(seqnames.getExportName(sName))
+ .append("\\label{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}}");
+ }
+ else {
+ // Export as \stepcounter{name}{\thename}
+ ldp.append(changeCounter(sName,sFormula,false))
+ .append("{\\the")
+ .append(seqnames.getExportName(sName))
+ .append("}");
+ }
+ }
+ }
+ }
+
+ /** Create label for a sequence field (text:sequence tag)
+ * @param node The element containing the sequence field + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ */
+ public void handleSequenceLabel(Element node, LaTeXDocumentPortion ldp) {
+ String sRefName = Misc.getAttribute(node,XMLString.TEXT_REF_NAME);
+ if (sRefName!=null && ofr.hasSequenceRefTo(sRefName)) {
+ ldp.append("\\label{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ }
+ }
+
+ // According to the spec for OpenDocument, the formula is application
+ // specific, prefixed with a namespace. OOo uses the namespace ooow, and
+ // we accept the formulas ooow:Process a sequence reference (text:sequence-ref tag)
+ * @param node The element containing the sequence reference + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleSequenceRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sRefName = Misc.getAttribute(node,XMLString.TEXT_REF_NAME);
+ String sFormat = Misc.getAttribute(node,XMLString.TEXT_REFERENCE_FORMAT);
+ String sName = ofr.getSequenceFromRef(sRefName);
+ if (sRefName!=null) {
+ if (sFormat==null || "page".equals(sFormat)) {
+ ldp.append("\\pageref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ }
+ else if ("value".equals(sFormat)) {
+ ldp.append("\\ref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ }
+ else if ("category-and-value".equals(sFormat)) {
+ // Export as Name~\\ref{refname}
+ if (sName!=null) {
+ if (ofr.isFigureSequenceName(sName)) {
+ ldp.append("\\figurename~");
+ }
+ else if (ofr.isTableSequenceName(sName)) {
+ ldp.append("\\tablename~");
+ }
+ else {
+ ldp.append(sName).append("~");
+ }
+ }
+ ldp.append("\\ref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ }
+ else if ("chapter".equals(sFormat) && config.useOooref()) {
+ ldp.append("\\chapterref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ bUsesOooref = true;
+ }
+ else if ("caption".equals(sFormat) && config.useTitleref() &&
+ (ofr.isFigureSequenceName(sName) || ofr.isTableSequenceName(sName))) {
+ ldp.append("\\titleref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ bUsesTitleref = true;
+ }
+ else if ("text".equals(sFormat) && config.useTitleref() &&
+ (ofr.isFigureSequenceName(sName) || ofr.isTableSequenceName(sName))) {
+ // This is a combination of "category-and-value" and "caption"
+ // Export as \\figurename~\ref{refname}:~\titleref{refname}
+ if (ofr.isFigureSequenceName(sName)) {
+ ldp.append("\\figurename");
+ }
+ else if (ofr.isTableSequenceName(sName)) {
+ ldp.append("\\tablename");
+ }
+ ldp.append("~\\ref{seq:")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}:~\\titleref{")
+ .append(seqrefnames.getExportName(sRefName))
+ .append("}");
+ bUsesTitleref = true;
+ }
+ else { // use current value
+ palette.getInlineCv().traversePCDATA(node,ldp,oc);
+ }
+ }
+ }
+
+
+ /** Process a reference mark (text:reference-mark tag)
+ * @param node The element containing the reference mark + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleReferenceMark(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (!oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim()) {
+ // Note: Always include \label here, even when it's not used
+ String sName = node.getAttribute(XMLString.TEXT_NAME);
+ if (sName!=null) {
+ ldp.append("\\label{ref:"+refnames.getExportName(sName)+"}");
+ }
+ }
+ else {
+ // Reference marks should not appear within \section or \caption
+ postponedReferenceMarks.add(node);
+ }
+ }
+
+ /** Process a reference (text:reference-ref tag)
+ * @param node The element containing the reference + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleReferenceRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sFormat = node.getAttribute(XMLString.TEXT_REFERENCE_FORMAT);
+ String sName = node.getAttribute(XMLString.TEXT_REF_NAME);
+ if (("page".equals(sFormat) || "".equals(sFormat)) && sName!=null) {
+ ldp.append("\\pageref{ref:"+refnames.getExportName(sName)+"}");
+ }
+ else if ("chapter".equals(sFormat) && ofr.referenceMarkInHeading(sName)) {
+ // This is safe if the reference mark is contained in a heading
+ ldp.append("\\ref{ref:"+refnames.getExportName(sName)+"}");
+ }
+ else { // use current value
+ palette.getInlineCv().traversePCDATA(node,ldp,oc);
+ }
+ }
+
+ /** Process a bookmark (text:bookmark tag)
+ *A bookmark may be the target for either a hyperlink or a reference,
+ * so this will generate a \\hyperref
and/or a \\label
LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleBookmark(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (!oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim()) {
+ String sName = node.getAttribute(XMLString.TEXT_NAME);
+ if (sName!=null) {
+ // A bookmark may be used as a target for a hyperlink as well as
+ // for a reference. We export whatever is actually used:
+ addTarget(node,"",ldp);
+ if (ofr.hasBookmarkRefTo(sName)) {
+ ldp.append("\\label{bkm:"+bookmarknames.getExportName(sName)+"}");
+ }
+ }
+ }
+ else {
+ // Bookmarks should not appear within \section or \caption
+ postponedBookmarks.add(node);
+ }
+ }
+
+ /** Process a bookmark reference (text:bookmark-ref tag).
+ * @param node The element containing the bookmark reference + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleBookmarkRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sFormat = node.getAttribute(XMLString.TEXT_REFERENCE_FORMAT);
+ String sName = node.getAttribute(XMLString.TEXT_REF_NAME);
+ if (("page".equals(sFormat) || "".equals(sFormat)) && sName!=null) {
+ ldp.append("\\pageref{bkm:"+bookmarknames.getExportName(sName)+"}");
+ }
+ else if ("chapter".equals(sFormat) && ofr.bookmarkInHeading(sName)) {
+ // This is safe if the bookmark is contained in a heading
+ ldp.append("\\ref{bkm:"+bookmarknames.getExportName(sName)+"}");
+ }
+ else { // use current value
+ palette.getInlineCv().traversePCDATA(node,ldp,oc);
+ }
+ }
+
+ /** Process pending reference marks and bookmarks (which may have been + * postponed within sections, captions or verbatim text.
+ * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void flushReferenceMarks(LaTeXDocumentPortion ldp, Context oc) {
+ // We may still be in a context with no reference marks
+ if (!oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim()) {
+ // Type out all postponed reference marks
+ int n = postponedReferenceMarks.size();
+ for (int i=0; iLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleAnchor(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sHref = node.getAttribute(XMLString.XLINK_HREF);
+ if (sHref!=null) {
+ if (sHref.startsWith("#")) {
+ // TODO: hyperlinks to headings (?) and objects
+ if (bUseHyperref) {
+ ldp.append("\\hyperlink{")
+ .append(targets.getExportName(Misc.urlDecode(sHref.substring(1))))
+ .append("}{");
+ // ignore text style (let hyperref.sty handle the decoration):
+ palette.getInlineCv().traverseInlineText(node,ldp,oc);
+ ldp.append("}");
+ }
+ else { // user don't want to include hyperlinks
+ palette.getInlineCv().handleTextSpan(node,ldp,oc);
+ }
+ }
+ else {
+ if (bUseHyperref) {
+ if (ofr.getTextContent(node).trim().equals(sHref)) {
+ // The link text equals the url
+ ldp.append("\\url{")
+ .append(oc.isInFootnote() ? escapeHref(Misc.urlDecode(sHref)) : Misc.urlDecode(sHref))
+ .append("}");
+ }
+ else {
+ ldp.append("\\href{")
+ .append(oc.isInFootnote() ? escapeHref(Misc.urlDecode(sHref)) : Misc.urlDecode(sHref))
+ .append("}{");
+ // ignore text style (let hyperref.sty handle the decoration):
+ palette.getInlineCv().traverseInlineText(node,ldp,oc);
+ ldp.append("}");
+ }
+ }
+ else { // user don't want to include hyperlinks
+ palette.getInlineCv().handleTextSpan(node,ldp,oc);
+ }
+ }
+ }
+ else {
+ palette.getInlineCv().handleTextSpan(node,ldp,oc);
+ }
+ }
+
+ /** Add a \\hypertarget
LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ */
+ public void addTarget(Element node, String sSuffix, LaTeXDocumentPortion ldp) {
+ // TODO: Remove this and use addTarget by name only
+ String sName = node.getAttribute(XMLString.TEXT_NAME);
+ if (sName == null) { sName = node.getAttribute(XMLString.TABLE_NAME); }
+ if (sName == null || !bUseHyperref) { return; }
+ if (!ofr.hasLinkTo(sName+sSuffix)) { return; }
+ ldp.append("\\hypertarget{")
+ .append(targets.getExportName(sName+sSuffix))
+ .append("}{}");
+ }
+
+ /** Add a \\hypertarget
LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ */
+ public void addTarget(String sName, String sSuffix, LaTeXDocumentPortion ldp) {
+ if (sName!=null && bUseHyperref && ofr.hasLinkTo(sName+sSuffix)) {
+ ldp.append("\\hypertarget{")
+ .append(targets.getExportName(sName+sSuffix))
+ .append("}{}");
+ }
+ }
+
+ /** Process a page number field (text:page-number tag)
+ * @param node The element containing the page number field + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handlePageNumber(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // TODO: Obey attributes!
+ ldp.append("\\thepage{}");
+ }
+
+ /** Process a page count field (text:page-count tag)
+ * @param node The element containing the page count field + * @param ldp theLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handlePageCount(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // TODO: Obey attributes!
+ // Note: Actually LastPage refers to the page number of the last page, not the number of pages
+ if (config.useLastpage()) {
+ bUsesPageCount = true;
+ ldp.append("\\pageref{LastPage}");
+ }
+ else {
+ ldp.append("?");
+ }
+ }
+
+ // Helpers:
+
+ private String createPdfMeta(String sName, String sValue) {
+ if (sValue==null) { return ""; }
+ // Replace commas with semicolons (the keyval package doesn't like commas):
+ sValue = sValue.replace(',', ';');
+ // Meta data is assumed to be in the default language:
+ return ", "+sName+"="+palette.getI18n().convert(sValue,false,palette.getMainContext().getLang());
+ }
+
+ // For href within footnote, we have to escape the #
+ private String escapeHref(String s) {
+ StringBuffer buf = new StringBuffer();
+ for (int i=0; iignore_all
+ * ignore_most
+ * convert_basic
+ * convert_most
+ * convert_all
+ * HeadingConverter
.
+ */
+ public HeadingConverter(OfficeReader ofr, LaTeXConfig config,
+ ConverterPalette palette) {
+ super(ofr,config,palette);
+ }
+
+ public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
+ appendHeadingStyles(decl);
+ }
+
+ /** Process a heading
+ * @param node The text:h element node containing the heading
+ * @param ldp The LaTeXDocumentPortion to add LaTeX code to
+ * @param oc The current context
+ */
+ public void handleHeading(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // Get the level, the heading map and the style name
+ int nLevel = ofr.isOpenDocument() ?
+ Misc.getPosInteger(Misc.getAttribute(node, XMLString.TEXT_OUTLINE_LEVEL),1) :
+ Misc.getPosInteger(Misc.getAttribute(node, XMLString.TEXT_LEVEL),1);
+ HeadingMap hm = config.getHeadingMap();
+ String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
+
+ if (nLevel<=hm.getMaxLevel()) {
+ // Always push the font used
+ palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getParStyle(sStyleName)));
+
+ Context ic = (Context) oc.clone();
+ ic.setInSection(true);
+ // Footnotes with more than one paragraph are not allowed within
+ // sections. To be safe, we disallow all footnotes
+ ic.setNoFootnotes(true);
+
+ // Apply style
+ BeforeAfter baHardPage = new BeforeAfter();
+ BeforeAfter baHardChar = new BeforeAfter();
+ applyHardHeadingStyle(nLevel, sStyleName,
+ baHardPage, baHardChar, ic);
+
+ // Export the heading
+ ldp.append(baHardPage.getBefore());
+ ldp.append("\\"+hm.getName(nLevel));
+ // If this heading contains formatting, add optional argument:
+ if (baHardChar.getBefore().length()>0 || containsElements(node)) {
+ ldp.append("[");
+ palette.getInlineCv().traversePlainInlineText(node,ldp,ic);
+ ldp.append("]");
+ }
+ ldp.append("{").append(baHardChar.getBefore());
+ palette.getInlineCv().traverseInlineText(node,ldp,ic);
+ ldp.append(baHardChar.getAfter()).append("}").nl();
+ ldp.append(baHardPage.getAfter());
+
+ // Include pending index marks, labels, footnotes & floating frames
+ palette.getFieldCv().flushReferenceMarks(ldp,oc);
+ palette.getIndexCv().flushIndexMarks(ldp,oc);
+ palette.getNoteCv().flushFootnotes(ldp,oc);
+ palette.getDrawCv().flushFloatingFrames(ldp,ic);
+
+ // Pop the font name
+ palette.getI18n().popSpecialTable();
+ }
+ else { // beyond supported headings - export as ordinary paragraph
+ palette.getParCv().handleParagraph(node,ldp,oc,false);
+ }
+ }
+
+
+ /** Use a paragraph style on a heading. If hard paragraph formatting
+ * is applied to a heading, page break and font is converted - other
+ * hard formatting is ignored.
+ * This method also collects name of heading style
+ * @param nLevel
The level of this heading
+ * @param sStyleName
the name of the paragraph style to use
+ * @param baPage
a BeforeAfter
to put page break code into
+ * @param baText
a BeforeAfter
to put character formatting code into
+ * @param context
the current context. This method will use and update the formatting context
+ */
+ private void applyHardHeadingStyle(int nLevel, String sStyleName,
+ BeforeAfter baPage, BeforeAfter baText, Context context) {
+
+ // Get the style
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ if (style==null) { return; }
+
+ // Register heading style
+ if (sHeadingStyles[nLevel]==null) {
+ sHeadingStyles[nLevel] = style.isAutomatic() ? style.getParentName() : sStyleName;
+ }
+
+ // Do conversion
+ if (style.isAutomatic()) {
+ palette.getPageSc().applyPageBreak(style,false,baPage);
+ palette.getCharSc().applyHardCharFormatting(style,baText);
+ }
+
+ // Update context
+ context.updateFormattingFromStyle(style);
+ }
+
+
+ /** Convert heading styles and outline numbering to LaTeX.
+ * An array of stylenames to use is required: The OOo writer file format
+ * allows different paragraph styles to be applied to individual headings,
+ * so this is not included in the styles.
+ * LaTeX (and OOo Writer!) usually uses the same format for all headings.
+ * @param ldp the LaTeXDocumentPortion to add definitions to.
+ */
+ // TODO: use method from ListStyleConverter to create labels
+ private void appendHeadingStyles(LaTeXDocumentPortion ldp) {
+ // The user may not want to convert the formatting of headings
+ if (config.formatting()<=LaTeXConfig.IGNORE_MOST) { return; }
+
+ HeadingMap hm = config.getHeadingMap();
+
+ // OK, we are going to convert. First find the max level for headings
+ int nMaxLevel = 0;
+ for (int i=1; i<=5; i++) { if (sHeadingStyles[i]!=null) { nMaxLevel=i; } }
+ if (nMaxLevel==0) { return; } // no headings, nothing to do!
+ if (nMaxLevel>hm.getMaxLevel()) { nMaxLevel = hm.getMaxLevel(); }
+
+ boolean bOnlyNum = config.formatting()==LaTeXConfig.CONVERT_BASIC;
+ if (bOnlyNum) {
+ ldp.append("% Outline numbering").nl();
+ }
+ else {
+ ldp.append("% Headings and outline numbering").nl()
+ .append("\\makeatletter").nl();
+ }
+
+ // Paragraph style for headings:
+ if (!bOnlyNum) {
+ for (int i=1; i<=nMaxLevel; i++) {
+ if (sHeadingStyles[i]!=null) {
+ StyleWithProperties style = ofr.getParStyle(sHeadingStyles[i]);
+ if (style!=null) {
+ BeforeAfter decl = new BeforeAfter();
+ BeforeAfter comm = new BeforeAfter();
+
+ palette.getPageSc().applyPageBreak(style,true,decl);
+
+ palette.getCharSc().applyNormalFont(decl);
+ palette.getCharSc().applyFont(style,true,true,decl,new Context());
+ palette.getParCv().applyAlignment(style,false,true,decl);
+
+ palette.getI18n().applyLanguage(style,false,true,comm);
+ palette.getCharSc().applyFontEffects(style,true,comm);
+
+ String sMarginTop = style.getAbsoluteLength(XMLString.FO_MARGIN_TOP);
+ String sMarginBottom = style.getAbsoluteLength(XMLString.FO_MARGIN_BOTTOM);
+ String sMarginLeft = style.getAbsoluteLength(XMLString.FO_MARGIN_LEFT);
+
+ String sSecName = hm.getName(i);
+ if (!comm.isEmpty()) { // have to create a cs for this heading
+ ldp.append("\\newcommand\\cs").append(sSecName).append("[1]{")
+ .append(comm.getBefore()).append("#1").append(comm.getAfter())
+ .append("}").nl();
+ }
+ ldp.append("\\renewcommand\\").append(sSecName)
+ .append("{\\@startsection{").append(sSecName).append("}{"+hm.getLevel(i))
+ .append("}{"+sMarginLeft+"}{");
+ // Suppress indentation after heading? currently not..
+ // ldp.append("-");
+ ldp.append(sMarginTop)
+ .append("}{").append(sMarginBottom).append("}{");
+ // Note: decl.getAfter() may include a page break after, which we ignore
+ ldp.append(decl.getBefore());
+ if (!comm.isEmpty()) {
+ ldp.append("\\cs").append(sSecName);
+ }
+ ldp.append("}}").nl();
+ }
+ }
+ }
+ }
+
+ // redefine formatting of section counters
+ // simplified if the user wants to ignore formatting
+ if (!bOnlyNum) {
+ ldp.append("\\renewcommand\\@seccntformat[1]{")
+ .append("\\csname @textstyle#1\\endcsname{\\csname the#1\\endcsname}")
+ .append("\\csname @distance#1\\endcsname}").nl();
+ }
+
+ // Collect numbering styles and set secnumdepth
+ int nSecnumdepth = nMaxLevel;
+ ListStyle outline = ofr.getOutlineStyle();
+ String[] sNumFormat = new String[6];
+ for (int i=nMaxLevel; i>=1; i--) {
+ sNumFormat[i] = ListStyleConverter.numFormat(outline.getLevelProperty(i,
+ XMLString.STYLE_NUM_FORMAT));
+ if (sNumFormat[i]==null || "".equals(sNumFormat[i])) {
+ nSecnumdepth = i-1;
+ }
+ }
+ ldp.append("\\setcounter{secnumdepth}{"+nSecnumdepth+"}").nl();
+
+ for (int i=1; i<=nMaxLevel; i++) {
+ if (sNumFormat[i]==null || "".equals(sNumFormat[i])) {
+ // no numbering at this level
+ if (!bOnlyNum) {
+ ldp.append("\\newcommand\\@distance")
+ .append(hm.getName(i)).append("{}").nl()
+ .append("\\newcommand\\@textstyle")
+ .append(hm.getName(i)).append("[1]{#1}").nl();
+ }
+ }
+ else {
+ if (!bOnlyNum) {
+ // Distance between label and text:
+ String sDistance = outline.getLevelStyleProperty(i,XMLString.TEXT_MIN_LABEL_DISTANCE);
+ ldp.append("\\newcommand\\@distance")
+ .append(hm.getName(i)).append("{");
+ if (sDistance!=null) {
+ ldp.append("\\hspace{").append(sDistance).append("}");
+ }
+ ldp.append("}").nl();
+ // Label width and alignment
+ String sLabelWidth = outline.getLevelStyleProperty(i,XMLString.TEXT_MIN_LABEL_WIDTH);
+ String sTextAlign = outline.getLevelStyleProperty(i,XMLString.FO_TEXT_ALIGN);
+ String sAlignmentChar = "l"; // start (or left) is default
+ if (sTextAlign!=null) {
+ if ("end".equals(sTextAlign)) { sAlignmentChar="r"; }
+ else if ("right".equals(sTextAlign)) { sAlignmentChar="r"; }
+ else if ("center".equals(sTextAlign)) { sAlignmentChar="c"; }
+ }
+ // Textstyle to use for label:
+ String sStyleName = outline.getLevelProperty(i,XMLString.TEXT_STYLE_NAME);
+ // Prefix and suffix text to decorate the label
+ String sPrefix = outline.getLevelProperty(i,XMLString.STYLE_NUM_PREFIX);
+ String sSuffix = outline.getLevelProperty(i,XMLString.STYLE_NUM_SUFFIX);
+ // TODO is this correct?? todo: space-before??? start value???
+ BeforeAfter baText = new BeforeAfter();
+ if (!bOnlyNum) {palette.getCharSc().applyTextStyle(sStyleName,baText,new Context()); }
+ ldp.append("\\newcommand\\@textstyle")
+ .append(hm.getName(i)).append("[1]{");
+ if (!bOnlyNum && sLabelWidth!=null) {
+ ldp.append("\\makebox[").append(sLabelWidth).append("][").append(sAlignmentChar).append("]{");
+ }
+ ldp.append(baText.getBefore())
+ .append(sPrefix!=null ? sPrefix : "")
+ .append("#1")
+ .append(sSuffix!=null ? sSuffix : "")
+ .append(baText.getAfter());
+ if (!bOnlyNum && sLabelWidth!=null) {
+ ldp.append("}");
+ }
+ ldp.append("}").nl();
+ }
+
+ // The label:
+ int nLevels = Misc.getPosInteger(outline.getLevelProperty(i,
+ XMLString.TEXT_DISPLAY_LEVELS),1);
+ ldp.append("\\renewcommand\\the")
+ .append(hm.getName(i))
+ .append("{");
+ for (int j=i-nLevels+1; jThis class handles indexes (table of contents, list of tables, list of
+ * illustrations, object index, user index, alphabetical index)
+ * as well as their associated index marks.
+ */
+public class IndexConverter extends ConverterHelper {
+
+ private boolean bContainsAlphabeticalIndex = false;
+
+ private Vector postponedIndexMarks = new Vector();
+
+ /** Construct a new IndexConverter
.
+ * @param config the configuration to use
+ * @param palette the ConverterPalette
to link to
+ * if such a document is created by the IndexConverter
+ */
+ public IndexConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
+ super(ofr,config,palette);
+ }
+
+ /**
Append declarations needed by the IndexConverter
to
+ * the preamble.
+ * @param pack the LaTeXDocumentPortion
to which
+ * declarations of packages should be added (\\usepackage
).
+ * @param decl the LaTeXDocumentPortion
to which
+ * other declarations should be added.
+ */
+ public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
+ if (bContainsAlphabeticalIndex) {
+ pack.append("\\usepackage{makeidx}").nl();
+ decl.append("\\makeindex").nl();
+ }
+ }
+
+ /** Process Table of Contents (text:table-of-content tag)
+ * @param node The element containing the Table of Contents
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleTOC (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ /* TODO: Apply more formatting by modfification of \l@section etc.
+ Something like this:
+ \newcommand\l@section[2]{\@dottedtocline{1}{1.5em}{2.3em}{\textbf{#1}}{\textit{#2}}
+ Textformatting is trivial; see article.cls for examples of more complicated
+ formatting. Note: The section number can't be formatted indivdually.*/
+
+ Element source = Misc.getChildByTagName(node,XMLString.TEXT_TABLE_OF_CONTENT_SOURCE);
+ if (source!=null) {
+ if ("chapter".equals(source.getAttribute(XMLString.TEXT_INDEX_SOURCE))) {
+ ldp.append("[Warning: Table of content (for this chapter) ignored!]").nl().nl();
+ }
+ else {
+ int nLevel = Misc.getPosInteger(source.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
+ ldp.append("\\setcounter{tocdepth}{"+nLevel+"}").nl();
+ Element title = Misc.getChildByTagName(source,XMLString.TEXT_INDEX_TITLE_TEMPLATE);
+ if (title!=null) {
+ ldp.append("\\renewcommand\\contentsname{");
+ palette.getInlineCv().traversePCDATA(title,ldp,oc);
+ ldp.append("}").nl();
+ }
+ }
+ }
+ ldp.append("\\tableofcontents").nl();
+ }
+
+ /** Process List of Illustrations (text:list-of-illustrations tag)
+ * @param node The element containing the List of Illustrations
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleLOF (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ ldp.append("\\listoffigures").nl();
+ }
+
+ /** Process List of Tables (text:list-of-tables tag)
+ * @param node The element containing the List of Tables
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleLOT (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ ldp.append("\\listoftables").nl();
+ }
+
+ /** Process Object Index (text:object index tag)
+ * @param node The element containing the Object Index
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleObjectIndex (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ ldp.append("[Warning: Object index ignored]").nl().nl();
+ }
+
+ /** Process User Index (text:user-index tag)
+ * @param node The element containing the User Index
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleUserIndex (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ ldp.append("[Warning: User index ignored]").nl().nl();
+ }
+
+
+ /** Process Alphabetical Index (text:alphabetical-index tag)
+ * @param node The element containing the Alphabetical Index
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleAlphabeticalIndex (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (config.noIndex()) { return; }
+ ldp.append("\\printindex").nl();
+ bContainsAlphabeticalIndex = true;
+ }
+
+
+ /** Process an Alphabetical Index Mark (text:alphabetical-index-mark{-start} tag)
+ * @param node The element containing the Mark
+ * @param ldp the LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleAlphabeticalIndexMark(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (!oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim()) {
+ String sValue = IndexMark.getIndexValue(node);
+ if (sValue!=null) {
+ ldp.append("\\index{");
+ String sKey1 = IndexMark.getKey1(node);
+ if (sKey1!=null) {
+ writeIndexText(sKey1.trim(),ldp,oc);
+ ldp.append("!");
+ }
+ String sKey2 = IndexMark.getKey2(node);
+ if (sKey2!=null) {
+ writeIndexText(sKey2.trim(),ldp,oc);
+ ldp.append("!");
+ }
+ writeIndexText(sValue.trim(),ldp,oc);
+ ldp.append("}");
+ }
+ }
+ else {
+ // Index marks should not appear within \section or \caption
+ postponedIndexMarks.add(node);
+ }
+ }
+
+ public void flushIndexMarks(LaTeXDocumentPortion ldp, Context oc) {
+ // We may still be in a context with no index marks
+ if (!oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim()) {
+ // Type out all postponed index marks
+ int n = postponedIndexMarks.size();
+ for (int i=0; i
Constructs a new LaTeX Document.
+ * + *This new document is empty. Document data must added to the preamble and + * the body using appropriate methods.
+ * + * @param sName The name of theLaTeXDocument
.
+ * @param nWrap Lines should be wrapped after this position
+ */
+ public LaTeXDocument(String sName,int nWrap) {
+ this.nWrap = nWrap;
+ this.sName = trimDocumentName(sName);
+ contents = new LaTeXDocumentPortion(true);
+ }
+
+ /**
+ * This method is supposed to read byte
data from the InputStream.
+ * Currently it does nothing, since we don't need it.
Returns the Document
name with no file extension.
Document
name with no file extension.
+ */
+ public String getName() {
+ return sName;
+ }
+
+
+ /**
+ * Returns the Document
name with file extension.
Document
name with file extension.
+ */
+ public String getFileName() {
+ return new String(sName + FILE_EXTENSION);
+ }
+
+
+ /**
+ * Writes out the Document
content to the specified
+ * OutputStream
.
This method may not be thread-safe. + * Implementations may or may not synchronize this + * method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.
+ * + * @param osOutputStream
to write out the
+ * Document
content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ OutputStreamWriter osw = new OutputStreamWriter(os,sEncoding);
+ contents.write(osw,nWrap,"\n");
+ osw.flush();
+ osw.close();
+ }
+
+ /**
+ * Set the output encoding to use when writing the document.
+ */ + public void setEncoding(String sEncoding) { this.sEncoding = sEncoding; } + + /** + *Returns the LaTeXDocumentPortion
, that contains the
+ * contents of the document.
LaTeXDocumentPortion
.
+ */
+ public LaTeXDocumentPortion getContents(){
+ return contents;
+ }
+
+ /*
+ * Utility method to make sure the document name is stripped of any file
+ * extensions before use.
+ */
+ private String trimDocumentName(String name) {
+ String temp = name.toLowerCase();
+
+ if (temp.endsWith(FILE_EXTENSION)) {
+ // strip the extension
+ int nlen = name.length();
+ int endIndex = nlen - FILE_EXTENSION.length();
+ name = name.substring(0,endIndex);
+ }
+
+ return name;
+ }
+}
+
\ No newline at end of file
diff --git a/source/java/writer2latex/latex/LaTeXDocumentPortion.java b/source/java/writer2latex/latex/LaTeXDocumentPortion.java
new file mode 100644
index 0000000..32d7ed0
--- /dev/null
+++ b/source/java/writer2latex/latex/LaTeXDocumentPortion.java
@@ -0,0 +1,214 @@
+/************************************************************************
+ *
+ * LaTeXDocumentPortion.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2006 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2007-10-02)
+ *
+ */
+
+package writer2latex.latex;
+
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.util.Vector;
+
+import writer2latex.util.Misc;
+
+/** This class represents a portion of a LaTeX document. A portion is any
+number of lines, and may include subportions. */
+public class LaTeXDocumentPortion {
+
+ private Vector nodes; // The collection of all nodes in this portion
+
+ private StringBuffer curText; // The currently active node (always the last node)
+ private boolean bEmpty; // Is the active node empty?
+
+ private boolean bWrap; // Do we allow line wrap in this portion?
+
+ public LaTeXDocumentPortion(boolean bWrap){
+ this.bWrap = bWrap;
+ nodes = new Vector();
+ curText = new StringBuffer();
+ bEmpty = true;
+ }
+
+ /** Add another portion to the end of this portion */
+ public LaTeXDocumentPortion append(LaTeXDocumentPortion ldp) {
+ if (!bEmpty) {
+ // add the current node to the node list and create new current node
+ nodes.add(curText);
+ curText = new StringBuffer();
+ bEmpty = true;
+ }
+ nodes.add(ldp);
+ return this;
+ }
+
+ /** Add a string to the end of this portion */
+ public LaTeXDocumentPortion append(String s){
+ curText.append(s);
+ bEmpty = false; // even if this is the empty string!
+ return this;
+ }
+
+ /** Add a newline to the end of this portion */
+ public LaTeXDocumentPortion nl(){
+ curText.append("\n");
+ bEmpty = false;
+ return this;
+ }
+
+ /** write a segment of text (eg. a word) to the output */
+ private void writeSegment(String s, int nStart, int nEnd, OutputStreamWriter osw) throws IOException {
+ for (int i=nStart; iConstructs a new ListStyleConverter
.
Apply a list style to an ordered or unordered list.
*/ + public void applyListStyle(String sStyleName, int nLevel, boolean bOrdered, + boolean bContinue, BeforeAfter ba) { + // Step 1. We may have a style map, this always takes precedence + String sDisplayName = ofr.getListStyles().getDisplayName(sStyleName); + if (config.getListStyleMap().contains(sDisplayName)) { + ba.add(config.getListStyleMap().getBefore(sDisplayName), + config.getListStyleMap().getAfter(sDisplayName)); + return; + } + // Step 2: The list style may not exist, or the user wants to ignore it. + // In this case we create default lists + ListStyle style = ofr.getListStyle(sStyleName); + if (style==null || config.formatting()<=LaTeXConfig.IGNORE_MOST) { + if (nLevel<=4) { + if (bOrdered) { + ba.add("\\begin{enumerate}","\\end{enumerate}"); + } + else { + ba.add("\\begin{itemize}","\\end{itemize}"); + } + } + return; + } + // Step 3: Export as default lists, but redefine labels + if (config.formatting()==LaTeXConfig.CONVERT_BASIC) { + if (nLevel==1) { + if (!styleNames.containsName(getDisplayName(sStyleName))) { + createListStyleLabels(sStyleName); + } + ba.add("\\liststyle"+styleNames.getExportName(getDisplayName(sStyleName))+"\n",""); + } + if (nLevel<=4) { + String sCounterName = ((String[]) listStyleLevelNames.get(sStyleName))[nLevel]; + if (bContinue && style.isNumber(nLevel)) { + bNeedSaveEnumCounter = true; + ba.add("\\setcounter{saveenum}{\\value{"+sCounterName+"}}\n",""); + } + if (bOrdered) { + ba.add("\\begin{enumerate}","\\end{enumerate}"); + } + else { + ba.add("\\begin{itemize}","\\end{itemize}"); + } + if (bContinue && style.isNumber(nLevel)) { + ba.add("\n\\setcounter{"+sCounterName+"}{\\value{saveenum}}",""); + } + } + return; + } + // Step 4: Export with formatting, as "Writer style" custom lists + if (nLevel<=4) { // TODO: Max level should not be fixed + if (!styleNames.containsName(getDisplayName(sStyleName))) { + createListStyle(sStyleName); + } + String sTeXName="list"+styleNames.getExportName(getDisplayName(sStyleName)) + +"level"+Misc.int2roman(nLevel); + if (!bContinue && style.isNumber(nLevel)) { + int nStartValue = Misc.getPosInteger(style.getLevelProperty(nLevel,XMLString.TEXT_START_VALUE),1)-1; + ba.add("\\setcounter{"+sTeXName+"}{"+Integer.toString(nStartValue)+"}\n",""); + } + ba.add("\\begin{"+sTeXName+"}","\\end{"+sTeXName+"}"); + } + } + + /**Apply a list style to a list item.
*/ + public void applyListItemStyle(String sStyleName, int nLevel, boolean bHeader, + boolean bRestart, int nStartValue, BeforeAfter ba) { + // Step 1. We may have a style map, this always takes precedence + String sDisplayName = ofr.getListStyles().getDisplayName(sStyleName); + if (config.getListItemStyleMap().contains(sDisplayName)) { + ba.add(config.getListItemStyleMap().getBefore(sDisplayName), + config.getListItemStyleMap().getAfter(sDisplayName)); + return; + } + // Step 2: The list style may not exist, or the user wants to ignore it. + // In this case we create default lists + ListStyle style = ofr.getListStyle(sStyleName); + if (style==null || config.formatting()<=LaTeXConfig.IGNORE_MOST) { + if (nLevel<=4) { + if (bHeader) { ba.add("\\item[] ",""); } + else { ba.add("\\item ",""); } + } + return; + } + // Step 3: Export as default lists (with redefined labels) + if (config.formatting()==LaTeXConfig.CONVERT_BASIC) { + if (nLevel<=4) { + if (bHeader) { + ba.add("\\item[] ",""); + } + else if (bRestart && style.isNumber(nLevel)) { + ba.add("\n\\setcounter{enum"+Misc.int2roman(nLevel) + +"}{"+(nStartValue-1)+"}\n\\item ",""); + } + else { + ba.add("\\item ",""); + } + } + return; + } + // Step 4: Export with formatting, as "Writer style" custom lists + if (nLevel<=4 && !bHeader) { // TODO: Max level should not be fixed + String sTeXName="list"+styleNames.getExportName(getDisplayName(sStyleName)) + +"level"+Misc.int2roman(nLevel); + if (bRestart && style.isNumber(nLevel)) { + ba.add("\\setcounter{"+sTeXName+"}{"+(nStartValue-1)+"}\n",""); + } + ba.add("\\item ",""); + } + } + + + /**Create labels for default lists (enumerate/itemize) based on + * a List Style + */ + private void createListStyleLabels(String sStyleName) { + String sTeXName = styleNames.getExportName(getDisplayName(sStyleName)); + declarations.append("\\newcommand\\liststyle") + .append(sTeXName).append("{%").nl(); + ListStyle style = ofr.getListStyle(sStyleName); + int nEnum = 0; + int nItem = 0; + String sName[] = new String[5]; + for (int i=1; i<=4; i++) { + if (style.isNumber(i)) { sName[i]="enum"+Misc.int2roman(++nEnum); } + else { sName[i]="item"+Misc.int2roman(++nItem); } + } + listStyleLevelNames.put(sStyleName, sName); + createLabels(style, sName, 4, false, true, false, declarations); + declarations.append("}").nl(); + } + + /**
Create "Writer style" lists based on a List Style. +
A list in writer is really a sequence of numbered paragraphs, so + this is also how we implement it in LaTeX. + The enivronment + redefined \item defines three hooks: + \writerlistleftskip, \writerlistparindent, \writerlistlabel + which are used by exported paragraph styles to apply numbering. + */ + private void createListStyle(String sStyleName) { + ListStyle style = ofr.getListStyle(sStyleName); + + // Create labels + String sTeXName = styleNames.getExportName(getDisplayName(sStyleName)); + String[] sLevelName = new String[5]; + for (int i=1; i<=4; i++) { + sLevelName[i]="list"+sTeXName+"level"+Misc.int2roman(i); + } + createLabels(style,sLevelName,4,true,false,true,declarations); + + // Create environments + for (int i=1; i<=4; i++) { + String sSpaceBefore = getLength(style,i,XMLString.TEXT_SPACE_BEFORE); + String sLabelWidth = getLength(style,i,XMLString.TEXT_MIN_LABEL_WIDTH); + String sLabelDistance = getLength(style,i,XMLString.TEXT_MIN_LABEL_DISTANCE); + String sTextAlign = style.getLevelStyleProperty(i,XMLString.FO_TEXT_ALIGN); + String sAlignmentChar = "l"; // start (or left) is default + if (sTextAlign!=null) { + if ("end".equals(sTextAlign)) { sAlignmentChar="r"; } + else if ("right".equals(sTextAlign)) { sAlignmentChar="r"; } + else if ("center".equals(sTextAlign)) { sAlignmentChar="c"; } + } + declarations + .append("\\newenvironment{") + .append(sLevelName[i]).append("}{") + .append("\\def\\writerlistleftskip{\\addtolength\\leftskip{") + .append(Misc.add(sSpaceBefore,sLabelWidth)).append("}}") + .append("\\def\\writerlistparindent{}") + .append("\\def\\writerlistlabel{}"); + // Redefine \item + declarations + .append("\\def\\item{") + .append("\\def\\writerlistparindent{\\setlength\\parindent{") + .append("-").append(sLabelWidth).append("}}") + .append("\\def\\writerlistlabel{"); + if (style.isNumber(i)) { + declarations.append("\\stepcounter{") + .append(sLevelName[i]).append("}"); + } + declarations + .append("\\makebox[").append(sLabelWidth).append("][") + .append(sAlignmentChar).append("]{") + .append("\\label").append(sLevelName[i]).append("}") + .append("\\hspace{").append(sLabelDistance).append("}") + .append("\\writerlistremovelabel}}}{}").nl(); + } + } + + /**
Create LaTeX list labels from an OOo list style. Examples:
+ *Bullets:
+ *\newcommand\labelliststylei{\textbullet} + * \newcommand\labelliststyleii{*} + * \newcommand\labelliststyleiii{\textstylebullet{>}}+ *
Numbering:
+ *\newcounter{liststylei} + * \newcounter{liststyleii}[liststylei] + * \newcounter{liststyleiii}[liststyleii] + * \renewcommand\theliststylei{\Roman{liststylei}} + * \renewcommand\theliststyleii{\Roman{liststylei}.\arabic{liststyleii}} + * \renewcommand\theliststyleiii{\alph{liststyleiii}} + * \newcommand\labelliststylei{\textstylelabel{\theliststylei .}} + * \newcommand\labelliststyleii{\textstylelabel{\theliststyleii .}} + * \newcommand\labelliststyleiii{\textstylelabel{\theliststyleiii )}}+ * + * @param
style
the OOo list style to use
+ * @param sName
an array of label basenames to use
+ * @param nMaxLevel
the highest level in this numbering
+ * @param bDeclareCounters
true if counters should be declared (they may
+ * exist already, eg. "section", "subsection"... or "enumi", "enumii"...
+ * @param bRenewLabels
true if labels should be defined with \renewcommand
+ * @param bUseTextStyle
true if labels should be formatted with the associated text style
+ * (rather than \newcommand).
+ * @param ldp
the LaTeXDocumentPortion
to add LaTeX code to.
+ */
+ private void createLabels(ListStyle style, String[] sName, int nMaxLevel,
+ boolean bDeclareCounters, boolean bRenewLabels,
+ boolean bUseTextStyle, LaTeXDocumentPortion ldp) {
+ // Declare counters if required (eg. "\newcounter{countername1}[countername2]")
+ if (bDeclareCounters) {
+ int j = 0;
+ for (int i=1; i<=nMaxLevel; i++) {
+ if (style.isNumber(i)) {
+ ldp.append("\\newcounter{").append(sName[i]).append("}");
+ if (j>0) { ldp.append("[").append(sName[j]).append("]"); }
+ ldp.nl();
+ j = i;
+ }
+ }
+ }
+ // Create numbering for each level (eg. "\arabic{countername}")
+ String[] sNumFormat = new String[nMaxLevel+1];
+ for (int i=1; i<=nMaxLevel; i++) {
+ String s = numFormat(style.getLevelProperty(i,XMLString.STYLE_NUM_FORMAT));
+ if (s==null) { sNumFormat[i]=""; }
+ else { sNumFormat[i] = s + "{" + sName[i] + "}"; }
+ }
+ // Create numberings (ie. define "\thecountername"):
+ for (int i=1; i<=nMaxLevel; i++) {
+ if (style.isNumber(i)) {
+ ldp.append("\\renewcommand\\the").append(sName[i]).append("{");
+ int nLevels = Misc.getPosInteger(style.getLevelProperty(i,XMLString.TEXT_DISPLAY_LEVELS),1);
+ for (int j=i-nLevels+1; jLaTeX
+ // XSL transformation could be used here. (Potential problem:
+ // OOo uses MathML 1.01, not MathML 2)
+ return "\\text{Warning: No StarMath annotation}";
+ }
+
+ // Data for display equations
+ private Element theEquation = null;
+ private Element theSequence = null;
+
+ /**Try to convert a paragraph as a display equation:
+ * A paragraph which contains exactly one formula + at most one sequence
+ * number is treated as a display equation. Other content must be brackets
+ * or whitespace (possible with formatting).
+ * @param node the paragraph
+ * @param ldp the LaTeXDocumentPortion to contain the converted equation
+ * @return true if the conversion was succesful, false if the paragraph
+ * did not contain a display equation
+ */
+ public boolean handleDisplayEquation(Element node, LaTeXDocumentPortion ldp) {
+ theEquation = null;
+ theSequence = null;
+ if (parseDisplayEquation(node) && theEquation!=null) {
+ if (theSequence!=null) {
+ // Numbered equation
+ ldp.append("\\begin{equation}");
+ palette.getFieldCv().handleSequenceLabel(theSequence,ldp);
+ ldp.nl()
+ .append(convert(null,theEquation)).nl()
+ .append("\\end{equation}").nl();
+ }
+ else {
+ // Unnumbered equation
+ ldp.append("\\begin{equation*}").nl()
+ .append(convert(null,theEquation)).nl()
+ .append("\\end{equation*}").nl();
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private boolean parseDisplayEquation(Node node) {
+ Node child = node.getFirstChild();
+ while (child!=null) {
+ Node equation = getFormula(child);
+ if (equation!=null) {
+ if (theEquation==null) {
+ theEquation = (Element) equation;
+ }
+ else { // two or more equations -> not a display
+ return false;
+ }
+ }
+ else if (Misc.isElement(child)) {
+ String sName = child.getNodeName();
+ if (XMLString.TEXT_SEQUENCE.equals(sName)) {
+ if (theSequence==null) {
+ theSequence = (Element) child;
+ }
+ else { // two sequence numbers -> not a display
+ return false;
+ }
+ }
+ else if (XMLString.TEXT_SPAN.equals(sName)) {
+ if (!parseDisplayEquation(child)) {
+ return false;
+ }
+ }
+ else if (XMLString.TEXT_S.equals(sName)) {
+ // Spaces are allowed
+ }
+ else if (XMLString.TEXT_TAB.equals(sName)) {
+ // Tab stops are allowed
+ }
+ else if (XMLString.TEXT_TAB_STOP.equals(sName)) { // old
+ // Tab stops are allowed
+ }
+ else {
+ // Other elements -> not a display
+ return false;
+ }
+ }
+ else if (Misc.isText(child)) {
+ String s = child.getNodeValue();
+ int nLen = s.length();
+ for (int i=0; iThis class handles conversion of footnotes and endnotes, including
+ * references. It takes advantage of the packages endnotes.sty
+ * and perpage.sty
if allowed in the configuration.
Append declarations needed by the NoteConverter
to
+ * the preamble.
+ * @param pack the LaTeXDocumentPortion
to which
+ * declarations of packages should be added (\\usepackage
).
+ * @param decl the LaTeXDocumentPortion
to which
+ * other declarations should be added.
+ */
+ public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
+ if (bContainsEndnotes) { pack.append("\\usepackage{endnotes}").nl(); }
+ if (bContainsFootnotes) convertFootnotesConfiguration(decl);
+ if (bContainsEndnotes) convertEndnotesConfiguration(decl);
+ }
+
+ /**
Process a footnote (text:footnote tag)
+ * @param node The element containing the footnote
+ * @param ldp the Insert the endnotes into the documents.
+ * @param ldp the Process a note reference (text:note-ref tag, oasis)
+ * @param node The element containing the note reference
+ * @param ldp the Process a footnote reference (text:footnote-ref tag)
+ * @param node The element containing the footnote reference
+ * @param ldp the Process an endnote reference (text:endnote-ref tag)
+ * @param node The element containing the endnote reference
+ * @param ldp the Add a footnote name. The method Add an endnote name. The method This package contains LaTeX specific code. It contains a Since version 1.0 you can build Writer2LaTeX without this package if you
+don't need LaTeX support (in this case you can exclude writer2latex.bibtex as
+well). Constructs a new Apply page break properties from a style. Use a Master Page (pagestyle in LaTeX) This class converts OpenDocument paragraphs ( Export of formatting depends on the option "formatting": TODO: Captions and {foot|end}notes should also use this class
+ */
+public class ParConverter extends StyleConverter {
+
+ private boolean bNeedArrayBslash = false;
+
+ /** Constructs a new Process a text:p tag Use a paragraph style in LaTeX. Convert a paragraph style to LaTeX. A soft style is declared in A hard style is used by applying LaTeX code directly Apply line spacing from a style. Helper: Create a horizontal border. Currently unused Apply margin+alignment properties from a style. Apply all paragraph properties. This class creates LaTeX code from OOo sections.
+ * Sections are converted to multicols environments using Constructs a new Process a section (text:section tag) This is an abstract superclass for style converters. This class converts OpenDocument tables to LaTeX. The following LaTeX packages are used; some of them are optional array.sty, longtable.sty, supertabular.sty, tabulary.sty, hhline.sty,
+ * colortbl.sty. Options: Constructs a new Process a table (table:table or table:sub-table tag) In OOo the table style is distributed on table, column and cell styles.
+ * In LaTeX we have to rearrange this information slightly, so this class
+ * takes care of that. Constructor: Create from a TableReader.LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleFootnote(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ Context ic = (Context) oc.clone();
+ ic.setInFootnote(true);
+
+ String sId = node.getAttribute(XMLString.TEXT_ID);
+ Element fntbody = Misc.getChildByTagName(node,XMLString.TEXT_FOOTNOTE_BODY);
+ if (fntbody==null) { // try oasis
+ fntbody = Misc.getChildByTagName(node,XMLString.TEXT_NOTE_BODY);
+ }
+ if (fntbody != null) {
+ bContainsFootnotes = true;
+ if (ic.isNoFootnotes()) {
+ ldp.append("\\footnotemark{}");
+ postponedFootnotes.add(fntbody);
+ }
+ else {
+ ldp.append("\\footnote");
+ ldp.append("{");
+ if (sId != null && ofr.hasFootnoteRefTo(sId)) {
+ ldp.append("\\label{fnt:"+footnotenames.getExportName(sId)+"}");
+ }
+ traverseNoteBody(fntbody,ldp,ic);
+ ldp.append("}");
+ }
+ }
+ }
+
+ /** Flush the queue of postponed footnotes */
+ public void flushFootnotes(LaTeXDocumentPortion ldp, Context oc) {
+ // We may still be in a context with no footnotes
+ if (oc.isNoFootnotes()) { return; }
+ // Type out all postponed footnotes:
+ Context ic = (Context) oc.clone();
+ ic.setInFootnote(true);
+ int n = postponedFootnotes.size();
+ if (n==1) {
+ ldp.append("\\footnotetext{");
+ traverseNoteBody((Element) postponedFootnotes.get(0),ldp,ic);
+ ldp.append("}").nl();
+ postponedFootnotes.clear();
+ }
+ else if (n>1) {
+ // Several footnotes; have to adjust the footnote counter
+ ldp.append("\\addtocounter{footnote}{-"+n+"}").nl();
+ for (int i=0; iLaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleEndnote(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ Context ic = (Context) oc.clone();
+ ic.setInFootnote(true);
+
+ String sId = node.getAttribute(XMLString.TEXT_ID);
+ Element entbody = Misc.getChildByTagName(node,XMLString.TEXT_ENDNOTE_BODY);
+ if (entbody==null) { // try oasis
+ entbody = Misc.getChildByTagName(node,XMLString.TEXT_NOTE_BODY);
+ }
+ if (entbody != null) {
+ if (ic.isNoFootnotes() && !config.useEndnotes()) {
+ ldp.append("\\footnotemark()");
+ postponedFootnotes.add(entbody);
+ }
+ else {
+ if (config.useEndnotes()) {
+ ldp.append("\\endnote");
+ bContainsEndnotes = true;
+ }
+ else {
+ ldp.append("\\footnote");
+ bContainsFootnotes = true;
+ }
+ ldp.append("{");
+ if (sId != null && ofr.hasEndnoteRefTo(sId)) {
+ ldp.append("\\label{ent:"+endnotenames.getExportName(sId)+"}");
+ }
+ traverseNoteBody(entbody,ldp,ic);
+ ldp.append("}");
+ }
+ }
+ }
+
+ /** LaTeXDocumentPortion
to which
+ * the endnotes should be added.
+ */
+ public void insertEndnotes(LaTeXDocumentPortion ldp) {
+ if (bContainsEndnotes) {
+ ldp.append("\\clearpage").nl()
+ .append("\\theendnotes").nl();
+ }
+ }
+
+
+
+ /** LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleNoteRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sClass=node.getAttribute(XMLString.TEXT_NOTE_CLASS);
+ if (sClass.equals("footnote")) { handleFootnoteRef(node,ldp,oc); }
+ else if (sClass.equals("endnote")) { handleEndnoteRef(node,ldp,oc); }
+ }
+
+ /** LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleFootnoteRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sFormat = node.getAttribute(XMLString.TEXT_REFERENCE_FORMAT);
+ String sName = node.getAttribute(XMLString.TEXT_REF_NAME);
+ if (("page".equals(sFormat) || "".equals(sFormat)) && sName!=null) {
+ ldp.append("\\pageref{fnt:"+footnotenames.getExportName(sName)+"}");
+ }
+ else if ("text".equals(sFormat) && sName!=null) {
+ ldp.append("\\ref{fnt:"+footnotenames.getExportName(sName)+"}");
+ }
+ else { // use current value
+ palette.getInlineCv().traversePCDATA(node,ldp,oc);
+ }
+ }
+
+ /** LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleEndnoteRef(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ String sFormat = node.getAttribute(XMLString.TEXT_REFERENCE_FORMAT);
+ String sName = node.getAttribute(XMLString.TEXT_REF_NAME);
+ if (("page".equals(sFormat) || "".equals(sFormat)) && sName!=null) {
+ ldp.append("\\pageref{ent:"+endnotenames.getExportName(sName)+"}");
+ }
+ else if ("text".equals(sFormat) && sName!=null) {
+ ldp.append("\\ref{ent:"+endnotenames.getExportName(sName)+"}");
+ }
+ else { // use current value
+ palette.getInlineCv().traversePCDATA(node,ldp,oc);
+ }
+ }
+
+ /** handleFootnote
includes
+ * a \label
only if the footnote name is already known to the
+ * NoteConverter
. Hence this method is invoked by the prepass
+ * for each footnote reference. The end result is, that only necessary
+ * labels will be included.
+ * @param sName the name (id) of the footnote
+ */
+ public void addFootnoteName(String sName) { footnotenames.addName(sName); }
+
+ /** handleEndnote
includes
+ * a \label
only if the endnote name is already known to the
+ * NoteConverter
. Hence this method is invoked by the prepass
+ * for each endnote reference. The end result is, that only necessary
+ * labels will be included.
+ * @param sName the name (id) of the endnote
+ */
+ public void addEndnoteName(String sName) { endnotenames.addName(sName); }
+
+ /*
+ * Process the contents of a footnote or endnote
+ * TODO: Merge with BlockConverter.traverseBlockText?
+ */
+ private void traverseNoteBody (Element node, LaTeXDocumentPortion ldp, Context oc) {
+ if (node.hasChildNodes()) {
+ NodeList nList = node.getChildNodes();
+ int len = nList.getLength();
+
+ for (int i = 0; i < len; i++) {
+ Node childNode = nList.item(i);
+
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element child = (Element)childNode;
+ String nodeName = child.getTagName();
+
+ palette.getInfo().addDebugInfo(child,ldp);
+
+ if (nodeName.equals(XMLString.TEXT_H)) {
+ palette.getHeadingCv().handleHeading(child,ldp,oc);
+ }
+
+ if (nodeName.equals(XMLString.TEXT_P)) {
+ palette.getInlineCv().traverseInlineText(child,ldp,oc);
+ if (iwriterlatex.api.Converter
implementation for
+conversion into LaTeX.PageStyleConverter
.BeforeAfter
to put code into
+ */
+ public void applyPageBreak(StyleWithProperties style, boolean bInherit, BeforeAfter ba) {
+ if (style==null) { return; }
+ if (style.isAutomatic() && config.ignoreHardPageBreaks()) { return; }
+ // A page break can be a simple page break before or after...
+ String s = style.getProperty(XMLString.FO_BREAK_BEFORE,bInherit);
+ if ("page".equals(s)) { ba.add("\\clearpage",""); }
+ s = style.getProperty(XMLString.FO_BREAK_AFTER,bInherit);
+ if ("page".equals(s)) { ba.add("","\\clearpage"); }
+ // ...or it can be a new master page
+ String sMasterPage = style.getMasterPageName();
+ if (sMasterPage==null || sMasterPage.length()==0) { return; }
+ ba.add("\\clearpage","");
+ String sPageNumber=style.getProperty(XMLString.STYLE_PAGE_NUMBER);
+ if (sPageNumber!=null) {
+ int nPageNumber = Misc.getPosInteger(sPageNumber,1);
+ ba.add("\\setcounter{page}{"+nPageNumber+"}","");
+ }
+ applyMasterPage(sMasterPage,ba);
+ }
+
+ /** BeforeAfter
to add code to.
+ */
+ private void applyMasterPage(String sName, BeforeAfter ba) {
+ if (config.pageFormatting()==LaTeXConfig.IGNORE_ALL) return;
+ MasterPage style = ofr.getMasterPage(sName);
+ if (style==null) { return; }
+ String sNextName = style.getProperty(XMLString.STYLE_NEXT_STYLE_NAME);
+ MasterPage nextStyle = ofr.getMasterPage(sNextName);
+ if (style==nextStyle || nextStyle==null) {
+ ba.add("\\pagestyle{"+styleNames.getExportName(getDisplayName(sName))+"}\n", "");
+ }
+ else {
+ ba.add("\\pagestyle{"+styleNames.getExportName(getDisplayName(sNextName))+"}\n"+
+ "\\thispagestyle{"+styleNames.getExportName(getDisplayName(sName))+"}\n","");
+ }
+ // todo: should warn the user if next master also contains a next-style-name;
+ // LaTeX's page style mechanism cannot handle that
+ }
+
+ /*
+ * Process header or footer contents
+ */
+ private void convertMasterPages(LaTeXDocumentPortion ldp) {
+ if (config.pageFormatting()==LaTeXConfig.IGNORE_ALL) { return; }
+
+ Context context = new Context();
+ context.resetFormattingFromStyle(ofr.getDefaultParStyle());
+ context.setInHeaderFooter(true);
+
+
+ Enumeration styles = ofr.getMasterPages().getStylesEnumeration();
+ ldp.append("% Pages styles").nl();
+ if (!config.useFancyhdr()) {
+ ldp.append("\\makeatletter").nl();
+ }
+ while (styles.hasMoreElements()) {
+ MasterPage style = (MasterPage) styles.nextElement();
+ String sName = style.getName();
+ if (styleNames.containsName(getDisplayName(sName))) {
+ sChapterField1 = null;
+ sChapterField2 = null;
+
+ String sPageLayout = style.getPageLayoutName();
+ PageLayout pageLayout = ofr.getPageLayout(sPageLayout);
+
+ if (config.useFancyhdr()) {
+ ldp.append("\\fancypagestyle{")
+ .append(styleNames.getExportName(getDisplayName(sName)))
+ .append("}{\\fancyhf{}").nl();
+ // Header - odd or both
+ ldp.append(" \\fancyhead[")
+ .append(getParAlignment(style.getHeader()))
+ .append(style.getHeaderLeft()!=null ? "O" : "")
+ .append("]{");
+ traverseHeaderFooter((Element)style.getHeader(),ldp,context);
+ ldp.append("}").nl();
+ // Header - even
+ if (style.getHeaderLeft()!=null) {
+ ldp.append(" \\fancyhead[")
+ .append(getParAlignment(style.getHeaderLeft()))
+ .append("E]{");
+ traverseHeaderFooter((Element)style.getHeaderLeft(),ldp,context);
+ ldp.append("}").nl();
+ }
+ // Footer - odd or both
+ ldp.append(" \\fancyfoot[")
+ .append(getParAlignment(style.getFooter()))
+ .append(style.getFooterLeft()!=null ? "O" : "")
+ .append("]{");
+ traverseHeaderFooter((Element)style.getFooter(),ldp,context);
+ ldp.append("}").nl();
+ // Footer - even
+ if (style.getFooterLeft()!=null) {
+ ldp.append(" \\fancyfoot[")
+ .append(getParAlignment(style.getFooterLeft()))
+ .append("E]{");
+ traverseHeaderFooter((Element)style.getFooterLeft(),ldp,context);
+ ldp.append("}").nl();
+ }
+ // Rules
+ ldp.append(" \\renewcommand\\headrulewidth{")
+ .append(getBorderWidth(pageLayout,true))
+ .append("}").nl()
+ .append(" \\renewcommand\\footrulewidth{")
+ .append(getBorderWidth(pageLayout,false))
+ .append("}").nl();
+ }
+ else { // use low-level page styles
+ ldp.append("\\newcommand\\ps@")
+ .append(styleNames.getExportName(getDisplayName(sName)))
+ .append("{").nl();
+ // Header
+ ldp.append(" \\renewcommand\\@oddhead{");
+ traverseHeaderFooter((Element)style.getHeader(),ldp,context);
+ ldp.append("}").nl();
+ ldp.append(" \\renewcommand\\@evenhead{");
+ if (style.getHeaderLeft()!=null) {
+ traverseHeaderFooter((Element)style.getHeaderLeft(),ldp,context);
+ }
+ else if (style.getHeader()!=null) {
+ ldp.append("\\@oddhead");
+ }
+ ldp.append("}").nl();
+ // Footer
+ ldp.append(" \\renewcommand\\@oddfoot{");
+ traverseHeaderFooter((Element)style.getFooter(),ldp,context);
+ ldp.append("}").nl();
+ ldp.append(" \\renewcommand\\@evenfoot{");
+ if (style.getFooterLeft()!=null) {
+ traverseHeaderFooter((Element)style.getFooterLeft(),ldp,context);
+ }
+ else if (style.getFooter()!=null) {
+ ldp.append("\\@oddfoot");
+ }
+ ldp.append("}").nl();
+ }
+
+ // Sectionmark and subsectionmark
+ if (sChapterField1!=null) {
+ ldp.append(" \\def\\sectionmark##1{\\markboth{");
+ if ("name".equals(sChapterField1)) { ldp.append("##1"); }
+ else if ("number".equals(sChapterField1) || "plain-number".equals(sChapterField1)) {
+ ldp.append("\\thesection");
+ }
+ else { ldp.append("\\thesection\\ ##1"); }
+ ldp.append("}{}}").nl();
+ }
+ if (sChapterField2!=null) {
+ if (sChapterField1==null) {
+ ldp.append(" \\def\\sectionmark##1{\\markboth{}{}}").nl();
+ }
+ ldp.append(" \\def\\subsectionmark##1{\\markright{");
+ if ("name".equals(sChapterField2)) { ldp.append("##1"); }
+ else if ("number".equals(sChapterField2) || "plain-number".equals(sChapterField1)) {
+ ldp.append("\\thesubsection");
+ }
+ else { ldp.append("\\thesubsection\\ ##1"); }
+ ldp.append("}{}}").nl();
+ }
+ // Page number (this is the only part of the page master used in each page style)
+ if (pageLayout!=null) {
+ String sNumFormat = pageLayout.getProperty(XMLString.STYLE_NUM_FORMAT);
+ if (sNumFormat!=null) {
+ ldp.append(" \\renewcommand\\thepage{")
+ .append(ListStyleConverter.numFormat(sNumFormat))
+ .append("{page}}").nl();
+ }
+ String sPageNumber = pageLayout.getProperty(XMLString.STYLE_FIRST_PAGE_NUMBER);
+ if (sPageNumber!=null && !sPageNumber.equals("continue")) {
+ ldp.append(" \\setcounter{page}{")
+ .append(Integer.toString(Misc.getPosInteger(sPageNumber,0)))
+ .append("}").nl();
+ }
+ }
+
+ ldp.append("}").nl();
+ }
+ }
+ if (!config.useFancyhdr()) {
+ ldp.append("\\makeatother").nl();
+ }
+ }
+
+ // Get alignment of first paragraph in node
+ private String getParAlignment(Node node) {
+ String sAlign = "L";
+ if (node!=null) {
+ Element par = Misc.getChildByTagName(node,XMLString.TEXT_P);
+ if (par!=null) {
+ String sStyleName = Misc.getAttribute(par,XMLString.TEXT_STYLE_NAME);
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ if (style!=null) {
+ String s = style.getProperty(XMLString.FO_TEXT_ALIGN);
+ if ("center".equals(s)) { sAlign = "C"; }
+ else if ("end".equals(s)) { sAlign = "R"; }
+ }
+ }
+ }
+ return sAlign;
+ }
+
+ // Get border width from header/footer style
+ private String getBorderWidth(PageLayout style, boolean bHeader) {
+ if (style==null) { return "0pt"; }
+ String sBorder;
+ if (bHeader) {
+ sBorder = style.getHeaderProperty(XMLString.FO_BORDER_BOTTOM);
+ if (sBorder==null) {
+ sBorder = style.getHeaderProperty(XMLString.FO_BORDER);
+ }
+ }
+ else {
+ sBorder = style.getFooterProperty(XMLString.FO_BORDER_TOP);
+ if (sBorder==null) {
+ sBorder = style.getFooterProperty(XMLString.FO_BORDER);
+ }
+ }
+ if (sBorder!=null && !sBorder.equals("none")) {
+ return sBorder.substring(0,sBorder.indexOf(' '));
+ }
+ else {
+ return "0pt";
+ }
+ }
+
+ private void traverseHeaderFooter(Element node, LaTeXDocumentPortion ldp, Context context) {
+ if (node==null) { return; }
+ // get first paragraph; all other content is ignored
+ Element par = Misc.getChildByTagName(node,XMLString.TEXT_P);
+ if (par==null) { return; }
+
+ String sStyleName = par.getAttribute(XMLString.TEXT_STYLE_NAME);
+ BeforeAfter ba = new BeforeAfter();
+ // Temp solution: Ignore hard formatting in header/footer (name clash problem)
+ // only in package format. TODO: Find a better solution!
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ if (style!=null && (!ofr.isPackageFormat() || !style.isAutomatic())) {
+ palette.getCharSc().applyHardCharFormatting(style,ba);
+ }
+
+ if (par.hasChildNodes()) {
+ ldp.append(ba.getBefore());
+ palette.getInlineCv().traverseInlineText(par,ldp,context);
+ ldp.append(ba.getAfter());
+ }
+
+ }
+
+ // TODO: Reenable several geometries per document??
+ private void convertPageMasterGeometry(LaTeXDocumentPortion pack, LaTeXDocumentPortion ldp) {
+ if (config.pageFormatting()!=LaTeXConfig.CONVERT_ALL) { return; }
+ if (mainPageLayout==null) { return; }
+
+ // Set global document options
+ if ("mirrored".equals(mainPageLayout.getPageUsage())) {
+ palette.addGlobalOption("twoside");
+ }
+ if (isTwocolumn()) {
+ palette.addGlobalOption("twocolumn");
+ }
+
+ // Collect all page geometry
+ // 1. Page size
+ String sPaperHeight = mainPageLayout.getAbsoluteProperty(XMLString.FO_PAGE_HEIGHT);
+ String sPaperWidth = mainPageLayout.getAbsoluteProperty(XMLString.FO_PAGE_WIDTH);
+ // 2. Margins
+ String sMarginTop = mainPageLayout.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
+ String sMarginBottom = mainPageLayout.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
+ String sMarginLeft = mainPageLayout.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
+ String sMarginRight = mainPageLayout.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
+ // 3. Header+footer dimensions
+ String sHeadHeight = "0cm";
+ String sHeadSep = "0cm";
+ String sFootHeight = "0cm";
+ String sFootSep = "0cm";
+ boolean bIncludeHead = false;
+ boolean bIncludeFoot = false;
+ // Look through all applied page layouts and use largest heights
+ Enumeration masters = ofr.getMasterPages().getStylesEnumeration();
+ while (masters.hasMoreElements()) {
+ MasterPage master = (MasterPage) masters.nextElement();
+ if (styleNames.containsName(getDisplayName(master.getName()))) {
+ PageLayout layout = ofr.getPageLayout(master.getPageLayoutName());
+ if (layout!=null) {
+ if (layout.hasHeaderStyle()) {
+ String sThisHeadHeight = layout.getHeaderProperty(XMLString.FO_MIN_HEIGHT);
+ if (sThisHeadHeight!=null && Misc.isLessThan(sHeadHeight,sThisHeadHeight)) {
+ sHeadHeight = sThisHeadHeight;
+ }
+ String sThisHeadSep = layout.getHeaderProperty(XMLString.FO_MARGIN_BOTTOM);
+ if (sThisHeadSep!=null && Misc.isLessThan(sHeadSep,sThisHeadSep)) {
+ sHeadSep = sThisHeadSep;
+ }
+ bIncludeHead = true;
+ }
+ if (layout.hasFooterStyle()) {
+ String sThisFootHeight = layout.getFooterProperty(XMLString.FO_MIN_HEIGHT);
+ if (sThisFootHeight!=null && Misc.isLessThan(sFootHeight,sThisFootHeight)) {
+ sFootHeight = sThisFootHeight;
+ }
+ String sThisFootSep = layout.getFooterProperty(XMLString.FO_MARGIN_TOP);
+ if (sThisFootSep!=null && Misc.isLessThan(sFootSep,sThisFootSep)) {
+ sFootSep = sThisFootSep;
+ }
+ bIncludeFoot = true;
+ }
+ }
+ }
+ }
+ // Define 12pt as minimum height (the source may specify 0pt..)
+ if (bIncludeHead && Misc.isLessThan(sHeadHeight,"12pt")) {
+ sHeadHeight = "12pt";
+ }
+ if (bIncludeFoot && Misc.isLessThan(sFootHeight,"12pt")) {
+ sFootHeight = "12pt";
+ }
+
+ String sFootSkip = Misc.add(sFootHeight,sFootSep);
+
+ if (config.useGeometry()) {
+ // Set up options for geometry.sty
+ CSVList props = new CSVList(",");
+ if (!standardPaperSize(sPaperWidth,sPaperHeight)) {
+ props.addValue("paperwidth="+sPaperWidth);
+ props.addValue("paperheight="+sPaperHeight);
+ }
+ props.addValue("top="+sMarginTop);
+ props.addValue("bottom="+sMarginBottom);
+ props.addValue("left="+sMarginLeft);
+ props.addValue("right="+sMarginRight);
+ if (bIncludeHead) {
+ props.addValue("includehead");
+ props.addValue("head="+sHeadHeight);
+ props.addValue("headsep="+sHeadSep);
+ }
+ else {
+ props.addValue("nohead");
+ }
+ if (bIncludeFoot) {
+ props.addValue("includefoot");
+ props.addValue("foot="+sFootHeight);
+ props.addValue("footskip="+sFootSkip);
+ }
+ else {
+ props.addValue("nofoot");
+ }
+ // Use the package
+ pack.append("\\usepackage[").append(props.toString()).append("]{geometry}").nl();
+
+ }
+ else {
+ // Calculate text height and text width
+ String sTextHeight = Misc.sub(sPaperHeight,sMarginTop);
+ sTextHeight = Misc.sub(sTextHeight,sHeadHeight);
+ sTextHeight = Misc.sub(sTextHeight,sHeadSep);
+ sTextHeight = Misc.sub(sTextHeight,sFootSkip);
+ sTextHeight = Misc.sub(sTextHeight,sMarginBottom);
+ String sTextWidth = Misc.sub(sPaperWidth,sMarginLeft);
+ sTextWidth = Misc.sub(sTextWidth,sMarginRight);
+
+ ldp.append("% Page layout (geometry)").nl();
+
+ // Page dimensions
+ if (!standardPaperSize(sPaperWidth,sPaperHeight)) {
+ ldp.append("\\setlength\\paperwidth{").append(sPaperWidth).append("}").nl()
+ .append("\\setlength\\paperheight{").append(sPaperHeight).append("}").nl();
+ }
+
+ // PDF page dimensions, only if hyperref.sty is not loaded
+ if (config.getBackend()==LaTeXConfig.PDFTEX && !config.useHyperref()) {
+ ldp.append("\\setlength\\pdfpagewidth{").append(sPaperWidth).append("}").nl()
+ .append("\\setlength\\pdfpageheight{").append(sPaperHeight).append("}").nl();
+ }
+
+ // Page starts in upper left corner of paper!!
+ ldp.append("\\setlength\\voffset{-1in}").nl()
+ .append("\\setlength\\hoffset{-1in}").nl();
+
+ // Margins
+ ldp.append("\\setlength\\topmargin{").append(sMarginTop).append("}").nl()
+ .append("\\setlength\\oddsidemargin{").append(sMarginLeft).append("}").nl();
+ // Left margin for even (left) pages; only for mirrored page master
+ if ("mirrored".equals(mainPageLayout.getPageUsage())) {
+ ldp.append("\\setlength\\evensidemargin{").append(sMarginRight).append("}").nl();
+ }
+
+ // Text size (sets bottom and right margins indirectly)
+ ldp.append("\\setlength\\textheight{").append(sTextHeight).append("}").nl();
+ ldp.append("\\setlength\\textwidth{").append(sTextWidth).append("}").nl();
+
+ // Header and footer
+ ldp.append("\\setlength\\footskip{").append(sFootSkip).append("}").nl();
+ ldp.append("\\setlength\\headheight{").append(sHeadHeight).append("}").nl();
+ ldp.append("\\setlength\\headsep{").append(sHeadSep).append("}").nl();
+ }
+
+ // Footnote rule
+ // TODO: Support alignment.
+ String sAdjustment = mainPageLayout.getFootnoteProperty(XMLString.STYLE_ADJUSTMENT);
+ String sBefore = mainPageLayout.getFootnoteProperty(XMLString.STYLE_DISTANCE_BEFORE_SEP);
+ if (sBefore==null) { sBefore = "1mm"; }
+ String sAfter = mainPageLayout.getFootnoteProperty(XMLString.STYLE_DISTANCE_AFTER_SEP);
+ if (sAfter==null) { sAfter = "1mm"; }
+ String sHeight = mainPageLayout.getFootnoteProperty(XMLString.STYLE_WIDTH);
+ if (sHeight==null) { sHeight = "0.2mm"; }
+ String sWidth = mainPageLayout.getFootnoteProperty(XMLString.STYLE_REL_WIDTH);
+ if (sWidth==null) { sWidth = "25%"; }
+ sWidth=Float.toString(Misc.getFloat(sWidth.substring(0,sWidth.length()-1),1)/100);
+ BeforeAfter baColor = new BeforeAfter();
+ String sColor = mainPageLayout.getFootnoteProperty(XMLString.STYLE_COLOR);
+ palette.getColorCv().applyColor(sColor,false,baColor,new Context());
+
+ String sSkipFootins = Misc.add(sBefore,sHeight);
+
+ ldp.append("% Footnote rule").nl()
+ .append("\\setlength{\\skip\\footins}{").append(sSkipFootins).append("}").nl()
+ .append("\\renewcommand\\footnoterule{\\vspace*{-").append(sHeight)
+ .append("}");
+ if ("right".equals(sAdjustment)) {
+ ldp.append("\\setlength\\leftskip{0pt plus 1fil}\\setlength\\rightskip{0pt}");
+ }
+ else if ("center".equals(sAdjustment)) {
+ ldp.append("\\setlength\\leftskip{0pt plus 1fil}\\setlength\\rightskip{0pt plus 1fil}");
+ }
+ else { // default left
+ ldp.append("\\setlength\\leftskip{0pt}\\setlength\\rightskip{0pt plus 1fil}");
+ }
+ ldp.append("\\noindent")
+ .append(baColor.getBefore()).append("\\rule{").append(sWidth)
+ .append("\\columnwidth}{").append(sHeight).append("}")
+ .append(baColor.getAfter())
+ .append("\\vspace*{").append(sAfter).append("}}").nl();
+ }
+
+ private boolean standardPaperSize(String sWidth, String sHeight) {
+ if (standardPaperSize1(sWidth,sHeight)) {
+ return true;
+ }
+ else if (standardPaperSize1(sHeight,sWidth)) {
+ palette.addGlobalOption("landscape");
+ return true;
+ }
+ return false;
+ }
+
+ private boolean standardPaperSize1(String sWidth, String sHeight) {
+ // The list of known paper sizes in LaTeX's standard classes is rather short
+ if (compare(sWidth, "210mm", "0.5mm") && compare(sHeight, "297mm", "0.5mm")) {
+ palette.addGlobalOption("a4paper");
+ return true;
+ }
+ else if (compare(sWidth, "148mm", "0.5mm") && compare(sHeight, "210mm", "0.5mm")) {
+ palette.addGlobalOption("a5paper");
+ return true;
+ }
+ else if (compare(sWidth, "176mm", "0.5mm") && compare(sHeight, "250mm", "0.5mm")) {
+ palette.addGlobalOption("b5paper");
+ return true;
+ }
+ else if (compare(sWidth, "8.5in", "0.02in") && compare(sHeight, "11in", "0.02in")) {
+ palette.addGlobalOption("letterpaper");
+ return true;
+ }
+ else if (compare(sWidth, "8.5in", "0.02in") && compare(sHeight, "14in", "0.02in")) {
+ palette.addGlobalOption("legalpaper");
+ return true;
+ }
+ else if (compare(sWidth, "7.25in", "0.02in") && compare(sHeight, "10.5in", "0.02in")) {
+ palette.addGlobalOption("executivepaper");
+ return true;
+ }
+ return false;
+ }
+
+ private boolean compare(String sLength1, String sLength2, String sTolerance) {
+ return Misc.isLessThan(Misc.abs(Misc.sub(sLength1,sLength2)),sTolerance);
+ }
+
+ /* Helper: Get display name, or original name if it doesn't exist */
+ private String getDisplayName(String sName) {
+ String sDisplayName = ofr.getMasterPages().getDisplayName(sName);
+ return sDisplayName!=null ? sDisplayName : sName;
+ }
+
+
+
+}
diff --git a/source/java/writer2latex/latex/ParConverter.java b/source/java/writer2latex/latex/ParConverter.java
new file mode 100644
index 0000000..d16e991
--- /dev/null
+++ b/source/java/writer2latex/latex/ParConverter.java
@@ -0,0 +1,546 @@
+/************************************************************************
+ *
+ * ParConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.latex;
+
+//import java.util.Hashtable;
+
+import org.w3c.dom.Element;
+//import org.w3c.dom.Node;
+//import org.w3c.dom.NodeList;
+
+import writer2latex.util.*;
+import writer2latex.office.*;
+import writer2latex.latex.util.BeforeAfter;
+import writer2latex.latex.util.Context;
+//import writer2latex.latex.util.HeadingMap;
+import writer2latex.latex.util.StyleMap;
+
+/* text:p
) and
+ * paragraph styles/formatting into LaTeX
+ *
+ * ignore_all
+ * ignore_most
+ * convert_basic
+ * convert_most
+ * convert_all
+ * ParConverter
.LaTeXDocumentPortion
to add LaTeX code to
+ * @param oc The current context
+ * @param bLastInBlock If this is true, the paragraph is the
+ * last one in a block, and we need no trailing blank line (eg. right before
+ * \end{enumerate}).
+ */
+ public void handleParagraph(Element node, LaTeXDocumentPortion ldp, Context oc, boolean bLastInBlock) {
+ if (palette.getMathmlCv().handleDisplayEquation(node,ldp)) { return; }
+
+ // Get the style name for this paragraph
+ String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
+ String sDisplayName = ofr.getParStyles().getDisplayName(sStyleName);
+
+
+ // Check for strict handling of styles
+ if (config.otherStyles()!=LaTeXConfig.ACCEPT && !config.getParStyleMap().contains(sDisplayName)) {
+ if (config.otherStyles()==LaTeXConfig.WARNING) {
+ System.err.println("Warning: A paragraph with style "+sDisplayName+" was ignored");
+ }
+ else if (config.otherStyles()==LaTeXConfig.ERROR) {
+ ldp.append("% Error in source document: A paragraph with style ")
+ .append(palette.getI18n().convert(sDisplayName,false,oc.getLang()))
+ .append(" was ignored").nl();
+ }
+ // Ignore this paragraph:
+ return;
+ }
+
+ // Empty paragraphs are often (mis)used to achieve vertical spacing in WYSIWYG
+ // word processors. Hence we translate an empty paragraph to \bigskip.
+ // This also solves the problem that LaTeX ignores empty paragraphs, Writer doesn't.
+ // In a well-structured document, an empty paragraph is probably a mistake,
+ // hence the configuration can specify that it should be ignored.
+ // Note: Don't use \bigskip in tables (this can lead to strange results)
+ if (OfficeReader.isWhitespaceContent(node)) {
+ // Always add page break; other formatting is ignored
+ BeforeAfter baPage = new BeforeAfter();
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ palette.getPageSc().applyPageBreak(style,true,baPage);
+ if (!oc.isInTable()) { ldp.append(baPage.getBefore()); }
+ if (!config.ignoreEmptyParagraphs()) {
+ if (!oc.isInTable()) {
+ ldp.nl().append("\\bigskip").nl();
+ }
+ else {
+ ldp.append("~").nl();
+ }
+ if (!bLastInBlock) { ldp.nl(); }
+ }
+ if (!oc.isInTable()) { ldp.append(baPage.getAfter()); }
+ return;
+ }
+
+ Context ic = (Context) oc.clone();
+
+ // Always push the font used
+ palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getParStyle(sStyleName)));
+
+ // Apply the style
+ BeforeAfter ba = new BeforeAfter();
+ if (oc.isInTable()) {
+ applyCellParStyle(sStyleName,ba,ic,OfficeReader.getCharacterCount(node)==0,bLastInBlock);
+ }
+ else {
+ applyParStyle(sStyleName,ba,ic,OfficeReader.getCharacterCount(node)==0);
+ }
+
+ // Do conversion
+ ldp.append(ba.getBefore());
+ palette.getInlineCv().traverseInlineText(node,ldp,ic);
+ ldp.append(ba.getAfter());
+ // Add a blank line except within verbatim and last in a block:
+ if (!bLastInBlock && !ic.isVerbatim() && !ic.isInSimpleTable()) { ldp.nl(); }
+
+ // Flush any pending index marks, reference marks and floating frames
+ palette.getFieldCv().flushReferenceMarks(ldp,oc);
+ palette.getIndexCv().flushIndexMarks(ldp,oc);
+ palette.getDrawCv().flushFloatingFrames(ldp,oc);
+
+ // pop the font name
+ palette.getI18n().popSpecialTable();
+ }
+
+ private void applyCellParStyle(String sName, BeforeAfter ba, Context context, boolean bNoTextPar, boolean bLastInBlock) {
+ // Paragraph formatting for paragraphs within table cells
+ // We always use simple par styles here
+
+ // Add newline if *between* paragraphs
+ if (!bLastInBlock) { ba.add("","\n"); }
+
+ if (context.isInSimpleTable()) {
+ if (config.formatting()!=LaTeXConfig.IGNORE_ALL) {
+ // only character formatting!
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style!=null) {
+ palette.getI18n().applyLanguage(style,true,true,ba);
+ palette.getCharSc().applyFont(style,true,true,ba,context);
+ if (ba.getBefore().length()>0) { ba.add(" ",""); }
+ }
+ }
+ }
+ else if (bNoTextPar && (config.formatting()==LaTeXConfig.CONVERT_BASIC || config.formatting()==LaTeXConfig.IGNORE_MOST) ) {
+ // only alignment!
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style!=null) {
+ // Apply hard formatting attributes
+ // Note: Left justified text is exported as full justified text!
+ palette.getPageSc().applyPageBreak(style,false,ba);
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true);
+ if (bLastInBlock && context.isInLastTableColumn()) { // no grouping needed, but need to fix problem with \\
+ if ("center".equals(sTextAlign)) { ba.add("\\centering\\arraybslash ",""); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft\\arraybslash ",""); }
+ bNeedArrayBslash = true;
+ }
+ else if (bLastInBlock) { // no grouping needed
+ if ("center".equals(sTextAlign)) { ba.add("\\centering ",""); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft ",""); }
+ }
+ else {
+ if ("center".equals(sTextAlign)) { ba.add("{\\centering ","\\par}"); }
+ else if ("end".equals(sTextAlign)) { ba.add("{\\raggedleft ","\\par}"); }
+ }
+ }
+ }
+ else {
+ // Export character formatting + alignment only
+ BeforeAfter baText = new BeforeAfter();
+
+ // Apply hard formatting attributes
+ // Note: Left justified text is exported as full justified text!
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style!=null) {
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true);
+ if (bLastInBlock && context.isInLastTableColumn()) { // no grouping needed, but need to fix problem with \\
+ if ("center".equals(sTextAlign)) { ba.add("\\centering\\arraybslash ",""); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft\\arraybslash ",""); }
+ bNeedArrayBslash = true;
+ }
+ else if (bLastInBlock) { // no \par needed
+ if ("center".equals(sTextAlign)) { ba.add("\\centering ",""); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft ",""); }
+ }
+ else {
+ if ("center".equals(sTextAlign)) { ba.add("\\centering ","\\par"); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft ","\\par"); }
+ }
+ palette.getI18n().applyLanguage(style,true,true,baText);
+ palette.getCharSc().applyFont(style,true,true,baText,context);
+ }
+
+ // Assemble the bits. If there is any hard character formatting
+ // or alignment we must group the contents.
+ if (!baText.isEmpty() && !bLastInBlock) { ba.add("{","}"); }
+ ba.add(baText.getBefore(),baText.getAfter());
+ if (baText.getBefore().length()>0) { ba.add(" ",""); }
+ }
+
+ // Update context
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style==null) { return; }
+ context.updateFormattingFromStyle(style);
+ context.setVerbatim(styleMap.getVerbatim(sName));
+ }
+
+
+ /** sName
the name of the text style
+ * @param ba
a BeforeAfter
to put code into
+ * @param context
the current context. This method will use and update the formatting context
+ * @param bNoTextPar
true if this paragraph has no text content (hence character formatting is not needed)
+ */
+ private void applyParStyle(String sName, BeforeAfter ba, Context context, boolean bNoTextPar) {
+ applyParStyle(sName,ba,context,bNoTextPar,true);
+ }
+
+ private void applyParStyle(String sName, BeforeAfter ba, Context context, boolean bNoTextPar, boolean bBreakInside) {
+ // No style specified?
+ if (sName==null) { return; }
+
+ if (context.isInSimpleTable()) {
+ if (config.formatting()!=LaTeXConfig.IGNORE_ALL) {
+ // only character formatting!
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style!=null) {
+ palette.getI18n().applyLanguage(style,true,true,ba);
+ palette.getCharSc().applyFont(style,true,true,ba,context);
+ if (ba.getBefore().length()>0) { ba.add(" ",""); }
+ }
+ }
+ }
+ else if (bNoTextPar && (config.formatting()==LaTeXConfig.CONVERT_BASIC || config.formatting()==LaTeXConfig.IGNORE_MOST) ) {
+ // Always end with a line break
+ ba.add("","\n");
+ // only alignment!
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style!=null) {
+ // Apply hard formatting attributes
+ // Note: Left justified text is exported as full justified text!
+ palette.getPageSc().applyPageBreak(style,false,ba);
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true);
+ if ("center".equals(sTextAlign)) { ba.add("{\\centering ","\\par}"); }
+ else if ("end".equals(sTextAlign)) { ba.add("{\\raggedleft ","\\par}"); }
+ }
+ }
+ else {
+ // Always end with a line break
+ ba.add("","\n");
+ // Apply the style
+ if (!styleMap.contains(sName)) { createParStyle(sName); }
+ String sBefore = styleMap.getBefore(sName);
+ String sAfter = styleMap.getAfter(sName);
+ ba.add(sBefore,sAfter);
+ // Add line breaks inside?
+ if (bBreakInside && styleMap.getLineBreak(sName)) {
+ if (sBefore.length()>0) { ba.add("\n",""); }
+ if (sAfter.length()>0 && !"}".equals(sAfter)) { ba.add("","\n"); }
+ }
+ }
+
+ // Update context
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style==null) { return; }
+ context.updateFormattingFromStyle(style);
+ context.setVerbatim(styleMap.getVerbatim(sName));
+ }
+
+ /** styleDeclarations
as
+ * \newenvironment...
sName
the OOo name of the style
+ */
+ private void createParStyle(String sName) {
+ // A paragraph style should always be created relative to main context
+ Context context = (Context) palette.getMainContext().clone();
+ // The style may already be declared in the configuration:
+ String sDisplayName = ofr.getParStyles().getDisplayName(sName);
+ StyleMap sm = config.getParStyleMap();
+ if (sm.contains(sDisplayName)) {
+ styleMap.put(sName,sm.getBefore(sDisplayName),sm.getAfter(sDisplayName),
+ sm.getLineBreak(sDisplayName),sm.getVerbatim(sDisplayName));
+ return;
+ }
+ // Does the style exist?
+ StyleWithProperties style = ofr.getParStyle(sName);
+ if (style==null) {
+ styleMap.put(sName,"","");
+ return;
+ }
+ // Convert the style!
+ switch (config.formatting()) {
+ case LaTeXConfig.CONVERT_MOST:
+ if (style.isAutomatic()) {
+ createAutomaticParStyle(style,context);
+ return;
+ }
+ case LaTeXConfig.CONVERT_ALL:
+ createSoftParStyle(style,context);
+ return;
+ case LaTeXConfig.CONVERT_BASIC:
+ case LaTeXConfig.IGNORE_MOST:
+ createSimpleParStyle(style,context);
+ return;
+ case LaTeXConfig.IGNORE_ALL:
+ default:
+ styleMap.put(sName,"","");
+ }
+ }
+
+ private void createAutomaticParStyle(StyleWithProperties style, Context context) {
+ // Hard paragraph formatting from this style should be ignored
+ // (because the user wants to ignore hard paragraph formatting
+ // or there is a style map for the parent.)
+ BeforeAfter ba = new BeforeAfter();
+ BeforeAfter baPar = new BeforeAfter();
+ BeforeAfter baText = new BeforeAfter();
+
+ // Apply paragraph formatting from parent
+ // If parent is verbatim, this is all
+ String sParentName = style.getParentName();
+ if (styleMap.getVerbatim(sParentName)) {
+ styleMap.put(style.getName(),styleMap.getBefore(sParentName),styleMap.getAfter(sParentName),
+ styleMap.getLineBreak(sParentName),styleMap.getVerbatim(sParentName));
+ return;
+ }
+ applyParStyle(sParentName,baPar,context,false,false);
+
+ // Apply hard formatting properties:
+ palette.getPageSc().applyPageBreak(style,false,ba);
+ palette.getI18n().applyLanguage(style,true,false,baText);
+ palette.getCharSc().applyFont(style,true,false,baText,context);
+
+ // Assemble the bits. If there is any hard character formatting
+ // we must group the contents.
+ if (baPar.isEmpty() && !baText.isEmpty()) { ba.add("{","}"); }
+ else { ba.add(baPar.getBefore(),baPar.getAfter()); }
+ ba.add(baText.getBefore(),baText.getAfter());
+ boolean bLineBreak = styleMap.getLineBreak(sParentName);
+ if (!bLineBreak && !baText.isEmpty()) { ba.add(" ",""); }
+ styleMap.put(style.getName(),ba.getBefore(),ba.getAfter(),bLineBreak,false);
+ }
+
+ private void createSimpleParStyle(StyleWithProperties style, Context context) {
+ // Export character formatting + alignment only
+ if (style.isAutomatic() && config.getParStyleMap().contains(ofr.getParStyles().getDisplayName(style.getParentName()))) {
+ createAutomaticParStyle(style,context);
+ return;
+ }
+
+ BeforeAfter ba = new BeforeAfter();
+ BeforeAfter baText = new BeforeAfter();
+
+ // Apply hard formatting attributes
+ // Note: Left justified text is exported as full justified text!
+ palette.getPageSc().applyPageBreak(style,false,ba);
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true);
+ if ("center".equals(sTextAlign)) { baText.add("\\centering","\\par"); }
+ else if ("end".equals(sTextAlign)) { baText.add("\\raggedleft","\\par"); }
+ palette.getI18n().applyLanguage(style,true,true,baText);
+ palette.getCharSc().applyFont(style,true,true,baText,context);
+
+ // Assemble the bits. If there is any hard character formatting
+ // or alignment we must group the contents.
+ if (!baText.isEmpty()) { ba.add("{","}"); }
+ ba.add(baText.getBefore(),baText.getAfter());
+ styleMap.put(style.getName(),ba.getBefore(),ba.getAfter());
+ }
+
+ private void createSoftParStyle(StyleWithProperties style, Context context) {
+ // This style should be converted to an enviroment, except if
+ // it's automatic and there is a config style map for the parent
+ if (style.isAutomatic() && config.getParStyleMap().contains(ofr.getParStyles().getDisplayName(style.getParentName()))) {
+ createAutomaticParStyle(style,context);
+ }
+
+ BeforeAfter ba = new BeforeAfter();
+ applyParProperties(style,ba);
+ ba.add("\\writerlistparindent\\writerlistleftskip","");
+ palette.getI18n().applyLanguage(style,true,true,ba);
+ ba.add("\\leavevmode","");
+ palette.getCharSc().applyNormalFont(ba);
+ palette.getCharSc().applyFont(style,true,true,ba,context);
+ ba.add("\\writerlistlabel","");
+ ba.add("\\ignorespaces","");
+ // Declare the paragraph style (\newenvironment)
+ String sTeXName = "style" + styleNames.getExportName(style.getDisplayName());
+ styleMap.put(style.getName(),"\\begin{"+sTeXName+"}","\\end{"+sTeXName+"}");
+ declarations.append("\\newenvironment{").append(sTeXName)
+ .append("}{").append(ba.getBefore()).append("}{")
+ .append(ba.getAfter()).append("}").nl();
+ }
+
+ // Remaining methods are private helpers
+
+ /** style
the paragraph style to use
+ * @param ba
a BeforeAfter
to put code into
+ */
+ private void applyLineSpacing(StyleWithProperties style, BeforeAfter ba) {
+ if (style==null) { return; }
+ String sLineHeight = style.getProperty(XMLString.FO_LINE_HEIGHT);
+ if (sLineHeight==null || !sLineHeight.endsWith("%")) { return; }
+ float fPercent=Misc.getFloat(sLineHeight.substring(0,sLineHeight.length()-1),100);
+ // Do not allow less that 120% (LaTeX default)
+ if (fPercent<120) { fPercent = 120; }
+ ba.add("\\renewcommand\\baselinestretch{"+fPercent/120+"}","");
+ }
+
+ /** style
the paragraph style to use
+ * @param ba
a BeforeAfter
to put code into
+ */
+ private void applyMargins(StyleWithProperties style, BeforeAfter ba) {
+ // Read padding/margin/indentation properties:
+ //String sPaddingTop = style.getAbsoluteLength(XMLString.FO_PADDING_TOP);
+ //String sPaddingBottom = style.getAbsoluteLength(XMLString.FO_PADDING_BOTTOM);
+ //String sPaddingLeft = style.getAbsoluteLength(XMLString.FO_PADDING_LEFT);
+ //String sPaddingRight = style.getAbsoluteLength(XMLString.FO_PADDING_RIGHT);
+ String sMarginTop = style.getAbsoluteLength(XMLString.FO_MARGIN_TOP);
+ String sMarginBottom = style.getAbsoluteLength(XMLString.FO_MARGIN_BOTTOM);
+ String sMarginLeft = style.getAbsoluteLength(XMLString.FO_MARGIN_LEFT);
+ String sMarginRight = style.getAbsoluteLength(XMLString.FO_MARGIN_RIGHT);
+ String sTextIndent;
+ if ("true".equals(style.getProperty(XMLString.STYLE_AUTO_TEXT_INDENT))) {
+ sTextIndent = "2em";
+ }
+ else {
+ sTextIndent = style.getAbsoluteLength(XMLString.FO_TEXT_INDENT);
+ }
+ // Read alignment properties:
+ boolean bRaggedLeft = false; // add 1fil to \leftskip
+ boolean bRaggedRight = false; // add 1fil to \rightskip
+ boolean bParFill = false; // add 1fil to \parfillskip
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN);
+ if ("center".equals(sTextAlign)) {
+ bRaggedLeft = true; bRaggedRight = true; // centered paragraph
+ }
+ else if ("start".equals(sTextAlign)) {
+ bRaggedRight = true; bParFill = true; // left aligned paragraph
+ }
+ else if ("end".equals(sTextAlign)) {
+ bRaggedLeft = true; // right aligned paragraph
+ }
+ else if (!"justify".equals(style.getProperty(XMLString.FO_TEXT_ALIGN_LAST))) {
+ bParFill = true; // justified paragraph with ragged last line
+ }
+ // Create formatting:
+ String sRubberMarginTop = Misc.multiply("10%",sMarginTop);
+ if (Misc.length2px(sRubberMarginTop).equals("0")) { sRubberMarginTop="1pt"; }
+ String sRubberMarginBottom = Misc.multiply("10%",sMarginBottom);
+ if (Misc.length2px(sRubberMarginBottom).equals("0")) { sRubberMarginBottom="1pt"; }
+ ba.add("\\setlength\\leftskip{"+sMarginLeft+(bRaggedLeft?" plus 1fil":"")+"}","");
+ ba.add("\\setlength\\rightskip{"+sMarginRight+(bRaggedRight?" plus 1fil":"")+"}","");
+ ba.add("\\setlength\\parindent{"+sTextIndent+"}","");
+ ba.add("\\setlength\\parfillskip{"+(bParFill?"0pt plus 1fil":"0pt")+"}","");
+ ba.add("\\setlength\\parskip{"+sMarginTop+" plus "+sRubberMarginTop+"}",
+ "\\unskip\\vspace{"+sMarginBottom+" plus "+sRubberMarginBottom+"}");
+ }
+
+ public void applyAlignment(StyleWithProperties style, boolean bIsSimple, boolean bInherit, BeforeAfter ba) {
+ if (bIsSimple || style==null) { return; }
+ String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,bInherit);
+ if ("center".equals(sTextAlign)) { ba.add("\\centering",""); }
+ else if ("start".equals(sTextAlign)) { ba.add("\\raggedright",""); }
+ else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft",""); }
+ }
+
+
+ /** style
the paragraph style to use
+ * @param ba
a BeforeAfter
to put code into
+ */
+ private void applyParProperties(StyleWithProperties style, BeforeAfter ba) {
+ palette.getPageSc().applyPageBreak(style,true,ba);
+ ba.add("","\\par");
+ applyLineSpacing(style,ba);
+ applyMargins(style,ba);
+ }
+
+}
diff --git a/source/java/writer2latex/latex/SectionConverter.java b/source/java/writer2latex/latex/SectionConverter.java
new file mode 100644
index 0000000..f695d9d
--- /dev/null
+++ b/source/java/writer2latex/latex/SectionConverter.java
@@ -0,0 +1,135 @@
+/************************************************************************
+ *
+ * SectionConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-17)
+ *
+ */
+
+package writer2latex.latex;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import writer2latex.util.*;
+import writer2latex.office.*;
+import writer2latex.latex.i18n.ClassicI18n;
+import writer2latex.latex.util.BeforeAfter;
+import writer2latex.latex.util.Context;
+
+/** multicol.sty
+ */
+public class SectionConverter extends ConverterHelper {
+
+ // Do we need multicols.sty?
+ private boolean bNeedMulticol = false;
+
+ // Filenames for external sections
+ private ExportNameCollection fileNames = new ExportNameCollection(true);
+
+ /** SectionStyleConverter
.LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleSection(Element node, LaTeXDocumentPortion ldp, Context oc) {
+ // We may need a hyperlink target, add this first
+ palette.getFieldCv().addTarget(node,"|region",ldp);
+
+ // Create new document, if desired
+ String sFileName = null;
+ Element source = Misc.getChildByTagName(node,XMLString.TEXT_SECTION_SOURCE);
+ if (config.splitLinkedSections() && source!=null) {
+ sFileName = fileNames.getExportName(Misc.removeExtension(Misc.urlDecode(source.getAttribute(XMLString.XLINK_HREF))));
+ }
+ else if (config.splitToplevelSections() && isToplevel(node)) {
+ //sFileName = fileNames.getExportName(palette.getOutFileName()+node.getAttribute(XMLString.TEXT_NAME));
+ sFileName = fileNames.getExportName(node.getAttribute(XMLString.TEXT_NAME));
+ }
+
+ LaTeXDocumentPortion sectionLdp = ldp;
+ if (sFileName!=null) {
+ LaTeXDocument newDoc = new LaTeXDocument(sFileName,config.getWrapLinesAfter());
+ if (config.getBackend()!=LaTeXConfig.XETEX) {
+ newDoc.setEncoding(ClassicI18n.writeJavaEncoding(config.getInputencoding()));
+ }
+ else {
+ newDoc.setEncoding("UTF-8");
+ }
+ palette.addDocument(newDoc);
+ sectionLdp = newDoc.getContents();
+ }
+
+ // Apply the style
+ String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
+ BeforeAfter ba = new BeforeAfter();
+ Context ic = (Context) oc.clone();
+ applySectionStyle(sStyleName,ba,ic);
+
+ // Do conversion
+ ldp.append(ba.getBefore());
+ if (sFileName!=null) {
+ ldp.append("\\input{").append(sFileName).append("}").nl();
+ }
+ palette.getBlockCv().traverseBlockText(node,sectionLdp,ic);
+ if (sectionLdp!=ldp) { sectionLdp.append("\\endinput").nl(); }
+ ldp.append(ba.getAfter());
+ }
+
+ // Create multicols environment as needed
+ private void applySectionStyle(String sStyleName, BeforeAfter ba, Context context) {
+ StyleWithProperties style = ofr.getSectionStyle(sStyleName);
+ // Don't nest multicols and require at least 2 columns
+ if (context.isInMulticols() || style==null || style.getColCount()<2) { return; }
+ int nCols = style.getColCount();
+ bNeedMulticol = true;
+ context.setInMulticols(true);
+ ba.add("\\begin{multicols}{"+(nCols>10 ? 10 : nCols)+"}\n", "\\end{multicols}\n");
+ }
+
+ // return true if this node is *not* contained in a text:section element
+ private boolean isToplevel(Node node) {
+ Node parent = node.getParentNode();
+ if (XMLString.TEXT_SECTION.equals(parent.getNodeName())) {
+ return false;
+ }
+ else if (XMLString.OFFICE_BODY.equals(parent.getNodeName())) {
+ return true;
+ }
+ return isToplevel(parent);
+ }
+
+
+
+}
diff --git a/source/java/writer2latex/latex/StarMathConverter.java b/source/java/writer2latex/latex/StarMathConverter.java
new file mode 100644
index 0000000..2eb6a50
--- /dev/null
+++ b/source/java/writer2latex/latex/StarMathConverter.java
@@ -0,0 +1,1618 @@
+/************************************************************************
+ *
+ * StarMathConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * Version 1.0 (2009-02-17)
+ *
+ * All Rights Reserved.
+ */
+
+package writer2latex.latex;
+
+import java.util.Hashtable;
+import writer2latex.util.*;
+import writer2latex.latex.i18n.ClassicI18n;
+import writer2latex.latex.i18n.I18n;
+import writer2latex.latex.LaTeXDocumentPortion;
+
+/* TO DO:
+ * better font handling, currently nested font attributes (eg. italic font fixed) don't work
+ * text inherits font from text surrounding formula - should this be changed?
+ * implement implicit left alignment of expressions starting with text
+ * improve subsup: \sideset should possibly be replaced by \multiscripts
+ * \multiscripts should only be used when absolutely neccessary
+ * maybe \leftidx should also be used sometimes
+ * alignment: how to make stack{{alignr x} % xxx} work??
+ * alignment: fractions and binoms?
+ * ...
+ */
+
+//////////////////////////////////////////////////////////////////
+/* The converted formula requires LaTeX2e with the packages
+ * amsmath.sty, amssymb.sty, amsfonts.sty and (optionally) color.sty.
+ * Also the following control sequences must be defined for starmath symbols
+ * and constructions that are not provided by standard LaTeX2e+amsmath:
+ * \defeq, \lambdabar, \ddotsup, \multimapdotbothA, \multimapdotbothB,
+ * \llbracket, \rrbracket, \oiint, \oiiint,
+ * \mathoverstrike, \wideslash, \widebslash, \boldsubformula,
+ * \normalsubformula.
+ * These should be declared in the preamble.
+ * Some are defined in the packages stmaryrd.sty, pxfonts.sty, txfonts.sty,
+ * but fallback definitions are provided in ooomath.sty if these packages are
+ * not used. More info in the documentation on ooomath.sty.
+ */
+
+//////////////////////////////////////////////////////////////////
+// Helper Classes
+
+// Some Character classifications
+class CharClasses{
+
+ static final char[] aDelimiterTable =
+ { ' ', '\t' , '\n', '\r', '+', '-', '*', '/', '=', '#',
+ '%', '\\', '"', '~', '`', '>', '<', '&', '|', '(',
+ ')', '{', '}', '[', ']', '^', '_', '\0'};
+
+ static boolean isDelimiter(char cChar){
+ // return true iff cChar is '\0' or a delimiter
+ if (cChar=='\0') return false;
+ int i=0;
+ for (i=0;aDelimiterTable[i]!='\0';i++)
+ if (aDelimiterTable[i]==cChar)
+ break;
+ return aDelimiterTable[i]!='\0';
+ }
+
+ static boolean isEndOrLineEnd(char cChar){
+ switch (cChar){
+ case '\0':
+ case '\n':
+ case '\r':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static boolean isDigitOrDot(char cChar){
+ return (cChar>='0' && cChar<='9') || cChar=='.' || cChar==',';
+ }
+}
+
+// enumerate Tokens
+class Token{
+ public static final Token END=new Token();
+ public static final Token LGROUP=new Token();
+ public static final Token RGROUP=new Token();
+ public static final Token LPARENT=new Token();
+ public static final Token RPARENT=new Token();
+ public static final Token LBRACKET=new Token();
+ public static final Token RBRACKET=new Token();
+ public static final Token PLUS=new Token();
+ public static final Token MINUS=new Token();
+ public static final Token MULTIPLY=new Token();
+ public static final Token DIVIDEBY=new Token();
+ public static final Token ASSIGN=new Token();
+ public static final Token POUND=new Token();
+ public static final Token SPECIAL=new Token();
+ public static final Token SLASH=new Token();
+ public static final Token BACKSLASH=new Token();
+ public static final Token BLANK=new Token();
+ public static final Token SBLANK=new Token();
+ public static final Token RSUB=new Token();
+ public static final Token RSUP=new Token();
+ public static final Token CSUB=new Token();
+ public static final Token CSUP=new Token();
+ public static final Token LSUB=new Token();
+ public static final Token LSUP=new Token();
+ public static final Token GT=new Token();
+ public static final Token LT=new Token();
+ public static final Token AND=new Token();
+ public static final Token OR=new Token();
+ public static final Token INTERSECT=new Token();
+ public static final Token UNION=new Token();
+ public static final Token NEWLINE=new Token();
+ public static final Token BINOM=new Token();
+ public static final Token FROM=new Token();
+ public static final Token TO=new Token();
+ public static final Token INT=new Token();
+ public static final Token SUM=new Token();
+ public static final Token OPER=new Token();
+ public static final Token ABS=new Token();
+ public static final Token SQRT=new Token();
+ public static final Token FACT=new Token();
+ public static final Token NROOT=new Token();
+ public static final Token OVER=new Token();
+ public static final Token TIMES=new Token();
+ public static final Token GE=new Token();
+ public static final Token LE=new Token();
+ public static final Token GG=new Token();
+ public static final Token LL=new Token();
+ public static final Token DOTSAXIS=new Token();
+ public static final Token DOTSLOW=new Token();
+ public static final Token DOTSVERT=new Token();
+ public static final Token DOTSDIAG=new Token();
+ public static final Token DOTSUP=new Token();
+ public static final Token DOTSDOWN=new Token();
+ public static final Token ACUTE=new Token();
+ public static final Token BAR=new Token();
+ public static final Token BREVE=new Token();
+ public static final Token CHECK=new Token();
+ public static final Token CIRCLE=new Token();
+ public static final Token DOT=new Token();
+ public static final Token DDOT=new Token();
+ public static final Token DDDOT=new Token();
+ public static final Token GRAVE=new Token();
+ public static final Token HAT=new Token();
+ public static final Token TILDE=new Token();
+ public static final Token VEC=new Token();
+ public static final Token UNDERLINE=new Token();
+ public static final Token OVERLINE=new Token();
+ public static final Token OVERSTRIKE=new Token();
+ public static final Token ITALIC=new Token();
+ public static final Token NITALIC=new Token();
+ public static final Token BOLD=new Token();
+ public static final Token NBOLD=new Token();
+ public static final Token PHANTOM=new Token();
+ public static final Token FONT=new Token();
+ public static final Token SIZE=new Token();
+ public static final Token COLOR=new Token();
+ public static final Token ALIGNL=new Token();
+ public static final Token ALIGNC=new Token();
+ public static final Token ALIGNR=new Token();
+ public static final Token LEFT=new Token();
+ public static final Token RIGHT=new Token();
+ public static final Token LANGLE=new Token();
+ public static final Token LBRACE=new Token();
+ public static final Token LLINE=new Token();
+ public static final Token LDLINE=new Token();
+ public static final Token LCEIL=new Token();
+ public static final Token LFLOOR=new Token();
+ public static final Token NONE=new Token();
+ public static final Token MLINE=new Token();
+ public static final Token RANGLE=new Token();
+ public static final Token RBRACE=new Token();
+ public static final Token RLINE=new Token();
+ public static final Token RDLINE=new Token();
+ public static final Token RCEIL=new Token();
+ public static final Token RFLOOR=new Token();
+ public static final Token SIN=new Token();
+ public static final Token COS=new Token();
+ public static final Token TAN=new Token();
+ public static final Token COT=new Token();
+ public static final Token FUNC=new Token();
+ public static final Token STACK=new Token();
+ public static final Token MATRIX=new Token();
+ public static final Token DPOUND=new Token();
+ public static final Token PLACE=new Token();
+ public static final Token TEXT=new Token();
+ public static final Token NUMBER=new Token();
+ public static final Token CHARACTER=new Token();
+ public static final Token IDENT=new Token();
+ public static final Token NEQ=new Token();
+ public static final Token EQUIV=new Token();
+ public static final Token DEF=new Token();
+ public static final Token PROP=new Token();
+ public static final Token SIM=new Token();
+ public static final Token SIMEQ=new Token();
+ public static final Token APPROX=new Token();
+ public static final Token PARALLEL=new Token();
+ public static final Token ORTHO=new Token();
+ public static final Token IN=new Token();
+ public static final Token NOTIN=new Token();
+ public static final Token SUBSET=new Token();
+ public static final Token SUBSETEQ=new Token();
+ public static final Token SUPSET=new Token();
+ public static final Token SUPSETEQ=new Token();
+ public static final Token PLUSMINUS=new Token();
+ public static final Token MINUSPLUS=new Token();
+ public static final Token OPLUS=new Token();
+ public static final Token OMINUS=new Token();
+ public static final Token DIV=new Token();
+ public static final Token OTIMES=new Token();
+ public static final Token ODIVIDE=new Token();
+ public static final Token TRANSL=new Token();
+ public static final Token TRANSR=new Token();
+ public static final Token IINT=new Token();
+ public static final Token IIINT=new Token();
+ public static final Token LINT=new Token();
+ public static final Token LLINT=new Token();
+ public static final Token LLLINT=new Token();
+ public static final Token PROD=new Token();
+ public static final Token COPROD=new Token();
+ public static final Token FORALL=new Token();
+ public static final Token EXISTS=new Token();
+ public static final Token LIM=new Token();
+ public static final Token NABLA=new Token();
+ public static final Token TOWARD=new Token();
+ public static final Token SINH=new Token();
+ public static final Token COSH=new Token();
+ public static final Token TANH=new Token();
+ public static final Token COTH=new Token();
+ public static final Token ASIN=new Token();
+ public static final Token ACOS=new Token();
+ public static final Token ATAN=new Token();
+ public static final Token LN=new Token();
+ public static final Token LOG=new Token();
+ public static final Token UOPER=new Token();
+ public static final Token BOPER=new Token();
+ public static final Token BLACK=new Token();
+ public static final Token WHITE=new Token();
+ public static final Token RED=new Token();
+ public static final Token GREEN=new Token();
+ public static final Token BLUE=new Token();
+ public static final Token CYAN=new Token();
+ public static final Token MAGENTA=new Token();
+ public static final Token YELLOW=new Token();
+ public static final Token FIXED=new Token();
+ public static final Token SANS=new Token();
+ public static final Token SERIF=new Token();
+ public static final Token POINT=new Token();
+ public static final Token ASINH=new Token();
+ public static final Token ACOSH=new Token();
+ public static final Token ATANH=new Token();
+ public static final Token ACOTH=new Token();
+ public static final Token ACOT=new Token();
+ public static final Token EXP=new Token();
+ public static final Token CDOT=new Token();
+ public static final Token ODOT=new Token();
+ public static final Token LESLANT=new Token();
+ public static final Token GESLANT=new Token();
+ public static final Token NSUBSET=new Token();
+ public static final Token NSUPSET=new Token();
+ public static final Token NSUBSETEQ=new Token();
+ public static final Token NSUPSETEQ=new Token();
+ public static final Token PARTIAL=new Token();
+ public static final Token NEG=new Token();
+ public static final Token NI=new Token();
+ public static final Token BACKEPSILON=new Token();
+ public static final Token ALEPH=new Token();
+ public static final Token IM=new Token();
+ public static final Token RE=new Token();
+ public static final Token WP=new Token();
+ public static final Token EMPTYSET=new Token();
+ public static final Token INFINITY=new Token();
+ public static final Token ESCAPE=new Token();
+ public static final Token LIMSUP=new Token();
+ public static final Token LIMINF=new Token();
+ public static final Token NDIVIDES=new Token();
+ public static final Token DRARROW=new Token();
+ public static final Token DLARROW=new Token();
+ public static final Token DLRARROW=new Token();
+ public static final Token UNDERBRACE=new Token();
+ public static final Token OVERBRACE=new Token();
+ public static final Token CIRC=new Token();
+ //public static final Token TOP=new Token();
+ public static final Token HBAR=new Token();
+ public static final Token LAMBDABAR=new Token();
+ public static final Token LEFTARROW=new Token();
+ public static final Token RIGHTARROW=new Token();
+ public static final Token UPARROW=new Token();
+ public static final Token DOWNARROW=new Token();
+ public static final Token DIVIDES=new Token();
+ public static final Token SETN=new Token();
+ public static final Token SETZ=new Token();
+ public static final Token SETQ=new Token();
+ public static final Token SETR=new Token();
+ public static final Token SETC=new Token();
+ public static final Token WIDEVEC=new Token();
+ public static final Token WIDETILDE=new Token();
+ public static final Token WIDEHAT=new Token();
+ public static final Token WIDESLASH=new Token();
+ public static final Token WIDEBACKSLASH=new Token();
+ public static final Token LDBRACKET=new Token();
+ public static final Token RDBRACKET=new Token();
+ public static final Token UNKNOWN=new Token();
+}
+
+// enumerate Token groups
+class TGroup{
+ public static final TGroup NONE=new TGroup();
+ public static final TGroup OPER=new TGroup();
+ public static final TGroup RELATION=new TGroup();
+ public static final TGroup SUM=new TGroup();
+ public static final TGroup PRODUCT=new TGroup();
+ public static final TGroup UNOPER=new TGroup();
+ public static final TGroup POWER =new TGroup();
+ public static final TGroup ATTRIBUT=new TGroup();
+ public static final TGroup ALIGN =new TGroup();
+ public static final TGroup FUNCTION=new TGroup();
+ public static final TGroup BLANK =new TGroup();
+ public static final TGroup LBRACES=new TGroup();
+ public static final TGroup RBRACES=new TGroup();
+ public static final TGroup COLOR =new TGroup();
+ public static final TGroup FONT=new TGroup();
+ public static final TGroup STANDALONE=new TGroup();
+ public static final TGroup LIMIT=new TGroup();
+ public static final TGroup FONTATTR=new TGroup();
+}
+
+// Token tables
+class SmTokenTableEntry{ // This is simply a struct
+ String sIdent;
+ Token eType;
+ String sLaTeX;
+ TGroup eGroup1, eGroup2;
+ int nLevel;
+
+ SmTokenTableEntry(String sIdent, Token eType, String sLaTeX,
+ TGroup eGroup1, TGroup eGroup2, int nLevel){
+ this.sIdent=sIdent;
+ this.eType=eType;
+ this.sLaTeX=sLaTeX;
+ this.eGroup1=eGroup1;
+ this.eGroup2=eGroup2;
+ this.nLevel=nLevel;
+ }
+
+ SmTokenTableEntry(String sIdent, Token eType, String sLaTeX,
+ TGroup eGroup1, int nLevel){
+ this(sIdent,eType,sLaTeX,eGroup1,TGroup.NONE,nLevel);
+ }
+
+ SmTokenTableEntry(String sIdent, Token eType, String sLaTeX,
+ int nLevel){
+ this(sIdent,eType,sLaTeX,TGroup.NONE,TGroup.NONE,nLevel);
+ }
+}
+
+class SmTokenTable{
+ private SmTokenTableEntry[] table;
+
+ SmTokenTable(SmTokenTableEntry[] table){this.table=table;}
+
+ boolean lookup(String sIdent, boolean bIgnoreCase, SmToken token){
+ for (int i=0; i
+ *
+ *
+ */
+public class TableConverter extends ConverterHelper {
+
+ private boolean bNeedLongtable = false;
+ private boolean bNeedSupertabular = false;
+ private boolean bNeedTabulary = false;
+ private boolean bNeedColortbl = false;
+ private boolean bContainsTables = false;
+
+ /** TableConverter
.LaTeXDocumentPortion
to which
+ * LaTeX code should be added
+ * @param oc the current context
+ */
+ public void handleTable(Element node, Element caption, boolean bCaptionAbove,
+ LaTeXDocumentPortion ldp, Context oc) {
+
+ // Export table, if allowed by the configuration
+ switch (config.tableContent()) {
+ case LaTeXConfig.ACCEPT:
+ new SingleTableConverter().handleTable(node,caption,bCaptionAbove,ldp,oc);
+ bContainsTables = true;
+ break;
+ case LaTeXConfig.IGNORE:
+ // Ignore table silently
+ break;
+ case LaTeXConfig.WARNING:
+ System.err.println("Warning: Tables are not allowed");
+ break;
+ case LaTeXConfig.ERROR:
+ ldp.append("% Error in document: A table was ignored");
+ }
+ }
+
+ // Inner class to convert a single table
+ private class SingleTableConverter {
+ private TableReader table;
+ private TableFormatter formatter;
+ private Element caption;
+ private boolean bCaptionAbove;
+ private BeforeAfter baTable;
+ private BeforeAfter baTableAlign;
+
+ private void handleTable(Element node, Element caption, boolean bCaptionAbove,
+ LaTeXDocumentPortion ldp, Context oc) {
+ // Store the caption
+ this.caption = caption;
+ this.bCaptionAbove = bCaptionAbove;
+
+ // Read the table
+ table = ofr.getTableReader(node);
+
+ // Get formatter and update flags according to formatter
+ formatter = new TableFormatter(ofr,config,palette,table,!oc.isInMulticols(),oc.isInTable());
+ bContainsTables = true;
+ bNeedLongtable |= formatter.isLongtable();
+ bNeedSupertabular |= formatter.isSupertabular();
+ bNeedTabulary |= formatter.isTabulary();
+ bNeedColortbl |= formatter.isColortbl();
+
+ // Update the context
+ Context ic = (Context) oc.clone();
+ ic.setInTable(true);
+ ic.setInSimpleTable(formatter.isSimple());
+ // Never allow footnotes in tables
+ // (longtable.sty *does* allow footnotes in body, but not in head -
+ // only consistent solution is to disallow all footnotes)
+ ic.setNoFootnotes(true);
+
+ // Get table declarations
+ baTable = new BeforeAfter();
+ baTableAlign = new BeforeAfter();
+ formatter.applyTableStyle(baTable,baTableAlign);
+
+ // Convert table
+ if (formatter.isSupertabular()) {
+ handleSupertabular(ldp,ic);
+ }
+ else if (formatter.isLongtable()) {
+ handleLongtable(ldp,ic);
+ }
+ else if (config.floatTables() && !ic.isInFrame() && !table.isSubTable()) {
+ handleTableFloat(ldp,ic);
+ }
+ else {
+ handleTabular(ldp,ic);
+ }
+
+ // Insert any pending footnotes
+ palette.getNoteCv().flushFootnotes(ldp,oc);
+ }
+
+ private void handleSupertabular(LaTeXDocumentPortion ldp, Context oc) {
+ ldp.append(baTableAlign.getBefore());
+
+ // Caption
+ if (caption!=null) {
+ handleCaption(bCaptionAbove ? "\\topcaption" : "\\bottomcaption",
+ ldp,oc);
+ }
+
+ // Table head
+ ldp.append("\\tablehead{");
+ handleHeaderRows(ldp,oc);
+ ldp.append("}");
+
+ // The table
+ handleHyperTarget(ldp);
+ ldp.append(baTable.getBefore()).nl();
+ handleBodyRows(ldp,oc);
+ ldp.append(baTable.getAfter()).nl();
+
+ ldp.append(baTableAlign.getAfter());
+ }
+
+ private void handleLongtable(LaTeXDocumentPortion ldp, Context oc) {
+ handleHyperTarget(ldp);
+ ldp.append(baTable.getBefore()).nl();
+
+ // Caption above
+ if (caption!=null && bCaptionAbove) {
+ handleCaption("\\caption",ldp,oc);
+ ldp.append("\\\\").nl();
+ handleHeaderRows(ldp,oc);
+ ldp.nl().append("\\endfirsthead").nl();
+ }
+
+ // Table head
+ if (table.getFirstBodyRow()>0) {
+ handleHeaderRows(ldp,oc);
+ ldp.nl().append("\\endhead").nl();
+ }
+
+ // Caption below
+ if (caption!=null && !bCaptionAbove) {
+ handleCaption("\\caption",ldp,oc);
+ ldp.append("\\endlastfoot").nl();
+ }
+
+ // Table body
+ handleBodyRows(ldp,oc);
+
+ ldp.append(baTable.getAfter()).nl();
+ }
+
+ private void handleTableFloat(LaTeXDocumentPortion ldp, Context oc) {
+ ldp.append("\\begin{table}");
+ if (config.getFloatOptions().length()>0) {
+ ldp.append("[").append(config.getFloatOptions()).append("]");
+ }
+ ldp.nl();
+
+ ldp.append(baTableAlign.getBefore());
+
+ // Caption above
+ if (caption!=null && bCaptionAbove) {
+ handleCaption("\\caption",ldp,oc);
+ }
+
+ // The table
+ handleHyperTarget(ldp);
+ ldp.append(baTable.getBefore()).nl();
+ handleHeaderRows(ldp,oc);
+ ldp.nl();
+ handleBodyRows(ldp,oc);
+ ldp.append(baTable.getAfter()).nl();
+
+ // Caption below
+ if (caption!=null && !bCaptionAbove) {
+ handleCaption("\\caption",ldp,oc);
+ }
+
+ ldp.append(baTableAlign.getAfter());
+
+ ldp.append("\\end{table}").nl();
+ }
+
+ private void handleTabular(LaTeXDocumentPortion ldp, Context oc) {
+ ldp.append(baTableAlign.getBefore());
+
+ // Caption above
+ if (caption!=null && bCaptionAbove) {
+ TableConverter.this.handleCaption(caption,ldp,oc);
+ }
+
+ // The table
+ handleHyperTarget(ldp);
+ ldp.append(baTable.getBefore()).nl();
+ if (table.getFirstBodyRow()>0) {
+ handleHeaderRows(ldp,oc);
+ ldp.nl();
+ }
+ handleBodyRows(ldp,oc);
+ ldp.append(baTable.getAfter()).nl();
+
+ // Caption below
+ if (caption!=null && !bCaptionAbove) {
+ TableConverter.this.handleCaption(caption,ldp,oc);
+ }
+
+ ldp.append(baTableAlign.getAfter());
+ }
+
+ private void handleCaption(String sCommand, LaTeXDocumentPortion ldp, Context oc) {
+ ldp.append(sCommand);
+ palette.getCaptionCv().handleCaptionBody(caption,ldp,oc,false);
+ }
+
+ private void handleHyperTarget(LaTeXDocumentPortion ldp) {
+ // We may need a hyperlink target
+ if (!table.isSubTable()) {
+ palette.getFieldCv().addTarget(table.getTableName(),"|table",ldp);
+ }
+ }
+
+ private void handleHeaderRows(LaTeXDocumentPortion ldp, Context oc) {
+ // Note: does *not* add newline after last row
+ if (table.getFirstBodyRow()>0) {
+
+ // Add interrow material before first row:
+ String sInter = formatter.getInterrowMaterial(0);
+ if (sInter.length()>0) {
+ ldp.append(sInter).nl();
+ }
+
+ // Add header rows
+ handleRows(0,table.getFirstBodyRow(),ldp,oc);
+ }
+ }
+
+ private void handleBodyRows(LaTeXDocumentPortion ldp, Context oc) {
+ if (table.getFirstBodyRow()==0) {
+ // No head, add interrow material before first row:
+ String sInter = formatter.getInterrowMaterial(0);
+ if (sInter.length()>0) {
+ ldp.append(sInter).nl();
+ }
+ }
+
+ // Add body rows
+ handleRows(table.getFirstBodyRow(),table.getRowCount(),ldp,oc);
+ ldp.nl();
+ }
+
+ private void handleRows(int nStart, int nEnd, LaTeXDocumentPortion ldp, Context oc) {
+ int nColCount = table.getColCount();
+ for (int nRow=nStart; nRow
Returns eg. "\begin{longtable}{m{2cm}|m{4cm}}", "\end{longtable}".
+ */ + public void applyTableStyle(BeforeAfter ba, BeforeAfter baAlign) { + // Read formatting info from table style + // Only supported properties are alignment and may-break-between-rows. + String sStyleName = table.getTableStyleName(); + StyleWithProperties style = ofr.getTableStyle(sStyleName); + char cAlign = 'c'; + if (style!=null && !table.isSubTable()) { + String s = style.getProperty(XMLString.TABLE_ALIGN); + if ("left".equals(s)) { cAlign='l'; } + else if ("right".equals(s)) { cAlign='r'; } + } + String sAlign="center"; + switch (cAlign) { + case 'c': sAlign="center"; break; + case 'r': sAlign="flushright"; break; + case 'l': sAlign="flushleft"; + } + + // Create table alignment (for supertabular, tabular and tabulary) + if (!bIsLongtable && !table.isSubTable()) { + baAlign.add("\\begin{"+sAlign+"}\n","\\end{"+sAlign+"}\n"); + } + + // Create table declaration + if (bIsLongtable) { + ba.add("\\begin{longtable}["+cAlign+"]", "\\end{longtable}"); + } + else if (bIsSupertabular) { + ba.add("\\begin{supertabular}","\\end{supertabular}"); + } + else if (bIsTabulary) { + ba.add("\\begin{tabulary}{"+table.getTableWidth()+"}","\\end{tabulary}"); + } + else if (!table.isSubTable()) { + ba.add("\\begin{tabular}","\\end{tabular}"); + } + else { // subtables should occupy the entire width, including padding! + ba.add("\\hspace*{-\\tabcolsep}\\begin{tabular}", + "\\end{tabular}\\hspace*{-\\tabcolsep}"); + } + + // columns + ba.add("{",""); + if (bGlobalVBorder[0]) { ba.add("|",""); } + int nColCount = table.getColCount(); + for (int nCol=0; nColBeforeAfter
to add LaTeX code to.
+ */
+ public void applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba) {
+ if (!bAlwaysUseDefaultLang && style!=null) {
+ String sISOLang = style.getProperty(XMLString.FO_LANGUAGE,bInherit);
+ if (sISOLang!=null) {
+ languages.add(sISOLang);
+ String sLang = getBabelLanguage(sISOLang);
+ if (sLang!=null) {
+ if (bDecl) {
+ ba.add("\\selectlanguage{"+sLang+"}","");
+ //ba.add("\\begin{otherlanguage}{"+sLang+"}","\\end{otherlanguage}");
+ }
+ else {
+ ba.add("\\foreignlanguage{"+sLang+"}{","}");
+ }
+ }
+ }
+ }
+ }
+
+ /** Push a font to the font stack
+ * @param sName the name of the font
+ */
+ public void pushSpecialTable(String sName) {
+ // If no name is specified we should keep the current table
+ // Otherwise try to find the table, and use root if it's not available
+ if (sName!=null) {
+ table = (UnicodeTable) tableSet.get(sName);
+ if (table==null) { table = (UnicodeTable) tableSet.get("root"); }
+ }
+ tableStack.push(table);
+ }
+
+ /** Pop a font from the font stack
+ */
+ public void popSpecialTable() {
+ tableStack.pop();
+ table = (UnicodeTable) tableStack.peek();
+ }
+
+ /** Get the number of characters defined in the current table
+ * (for informational purposes only)
+ * @return the number of characters
+ */
+ public int getCharCount() { return table.getCharCount(); }
+
+ /** Convert a string of characters into LaTeX
+ * @param s the source string
+ * @param bMathMode true if the string should be rendered in math mode
+ * @param sLang the iso language of the string
+ * @return the LaTeX string
+ */
+ public String convert(String s, boolean bMathMode, String sLang){
+ if (!bAlwaysUseDefaultLang && sLang!=null) { languages.add(sLang); }
+ StringBuffer buf=new StringBuffer();
+ int nFontenc = bAlwaysUseDefaultLang ? nDefaultFontenc : getFontenc(sLang);
+ int nLen = s.length();
+ int i = 0;
+ int nStart = i;
+ while (iBeforeAfter
to add LaTeX code to.
+ */
+ public abstract void applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba);
+
+ /** Push a font to the font stack
+ * @param sName the name of the font
+ */
+ public abstract void pushSpecialTable(String sName);
+
+ /** Pop a font from the font stack
+ */
+ public abstract void popSpecialTable();
+
+ /** Convert a string of characters into LaTeX
+ * @param s the source string
+ * @param bMathMode true if the string should be rendered in math mode
+ * @param sLang the iso language of the string
+ * @return the LaTeX string
+ */
+ public abstract String convert(String s, boolean bMathMode, String sLang);
+}
diff --git a/source/java/writer2latex/latex/i18n/Package.html b/source/java/writer2latex/latex/i18n/Package.html
new file mode 100644
index 0000000..2995355
--- /dev/null
+++ b/source/java/writer2latex/latex/i18n/Package.html
@@ -0,0 +1,16 @@
+
+
+
+
+ This package takes care of i18n for LaTeX.
+In LaTeX, i18n is a mixture of inputencodings, fontencodings + and babel languages. In particualar, the package provides a Unicode->LaTeX + translation that can handle different inputencodings and fontencodings.
+The pacakge could (with modification) in theory be used in other programs + that convert unicode to LaTeX.
+ + diff --git a/source/java/writer2latex/latex/i18n/ReplacementTrie.java b/source/java/writer2latex/latex/i18n/ReplacementTrie.java new file mode 100644 index 0000000..b09b324 --- /dev/null +++ b/source/java/writer2latex/latex/i18n/ReplacementTrie.java @@ -0,0 +1,56 @@ +/************************************************************************ + * + * ReplacementTrie.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2006 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2006-11-02) + * + */ + +package writer2latex.latex.i18n; + +/** This class contains a trie of string -> LaTeX code replacements +*/ +public class ReplacementTrie extends ReplacementTrieNode { + + public ReplacementTrie() { + super('*',0); + } + + public ReplacementTrieNode get(String sInput) { + return get(sInput,0,sInput.length()); + } + + public ReplacementTrieNode get(String sInput, int nStart, int nEnd) { + if (sInput.length()==0) { return null; } + else { return super.get(sInput,nStart,nEnd); } + } + + public void put(String sInput, String sLaTeXCode, int nFontencs) { + if (sInput.length()==0) { return; } + else { super.put(sInput,sLaTeXCode,nFontencs); } + } + + public String[] getInputStrings() { + return null; //TODO + } + + +} diff --git a/source/java/writer2latex/latex/i18n/ReplacementTrieNode.java b/source/java/writer2latex/latex/i18n/ReplacementTrieNode.java new file mode 100644 index 0000000..1e6a05f --- /dev/null +++ b/source/java/writer2latex/latex/i18n/ReplacementTrieNode.java @@ -0,0 +1,127 @@ +/************************************************************************ + * + * ReplacementTrieNode.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2006 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2006-11-02) + * + */ + +package writer2latex.latex.i18n; + +/** This class contains a node in a trie of string -> LaTeX code replacements +*/ +public class ReplacementTrieNode { + + private char cLetter; + private int nInputLength; + private String sLaTeXCode = null; + private int nFontencs = 0; + private ReplacementTrieNode son = null; + private ReplacementTrieNode brother = null; + + public ReplacementTrieNode(char cLetter, int nInputLength) { + this.cLetter = cLetter; + this.nInputLength = nInputLength; + } + + public char getLetter() { return this.cLetter; } + + public int getInputLength() { return this.nInputLength; } + + public String getLaTeXCode() { return this.sLaTeXCode; } + + public int getFontencs() { return this.nFontencs; } + + protected void setLaTeXCode(String sLaTeXCode) { + this.sLaTeXCode = sLaTeXCode; + } + + protected void setFontencs(int nFontencs) { + this.nFontencs = nFontencs; + } + + protected ReplacementTrieNode getFirstChild() { + return this.son; + } + + protected ReplacementTrieNode getNextSibling() { + return this.brother; + } + + protected ReplacementTrieNode getChildByLetter(char cLetter) { + ReplacementTrieNode child = this.getFirstChild(); + while (child!=null) { + if (cLetter==child.getLetter()) { return child; } + child = child.getNextSibling(); + } + return null; + } + + protected void appendChild(ReplacementTrieNode node) { + if (son==null) { son = node; } + else { son.appendSibling(node); } + } + + protected void appendSibling(ReplacementTrieNode node) { + if (brother==null) { brother = node; } + else { brother.appendSibling(node); } + } + + protected ReplacementTrieNode get(String sInput, int nStart, int nEnd) { + if (nStart>=nEnd) { return null; } + char c = sInput.charAt(nStart); + ReplacementTrieNode child = this.getFirstChild(); + while (child!=null) { + if (child.getLetter()==c) { + if (child.getLaTeXCode()!=null) { return child; } + else { return child.get(sInput,nStart+1,nEnd); } + } + child = child.getNextSibling(); + } + return null; + } + + protected void put(String sInput, String sLaTeXCode, int nFontencs) { + char c = sInput.charAt(0); + ReplacementTrieNode child = this.getChildByLetter(c); + if (child==null) { + child = new ReplacementTrieNode(c,this.getInputLength()+1); + this.appendChild(child); + } + if (sInput.length()>1) { + child.put(sInput.substring(1),sLaTeXCode,nFontencs); + } + else { + child.setLaTeXCode(sLaTeXCode); + child.setFontencs(nFontencs); + } + } + + public String toString() { + String s = Character.toString(cLetter); + if (brother!=null) { s+=brother.toString(); } + if (son!=null) { s+="\nInputLength "+(nInputLength+1)+", "+son.toString(); } + else { s+="\n"; } + return s; + } + + +} diff --git a/source/java/writer2latex/latex/i18n/UnicodeCharacter.java b/source/java/writer2latex/latex/i18n/UnicodeCharacter.java new file mode 100644 index 0000000..7e8217e --- /dev/null +++ b/source/java/writer2latex/latex/i18n/UnicodeCharacter.java @@ -0,0 +1,52 @@ +/************************************************************************ + * + * UnicodeCharacter.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-07-24) + * + */ + +package writer2latex.latex.i18n; + +// Helper class: A struct to hold the LaTeX representations of a unicode character +class UnicodeCharacter implements Cloneable { + final static int NORMAL = 0; // this is a normal character + final static int COMBINING = 1; // this character should be ignored + final static int IGNORE = 2; // this is a combining character + final static int UNKNOWN = 3; // this character is unknown + + int nType; // The type of character + String sMath; // LaTeX representation in math mode + String sText; // LaTeX representation in text mode + int nFontencs; // Valid font encoding(s) for the text mode representation + boolean bDashes; // This character is represented by dashes (-,--,---) + + protected Object clone() { + UnicodeCharacter uc = new UnicodeCharacter(); + uc.nType = this.nType; + uc.sMath = this.sMath; + uc.sText = this.sText; + uc.nFontencs = this.nFontencs; + uc.bDashes = this.bDashes; + return uc; + } +} + diff --git a/source/java/writer2latex/latex/i18n/UnicodeRow.java b/source/java/writer2latex/latex/i18n/UnicodeRow.java new file mode 100644 index 0000000..d051c2f --- /dev/null +++ b/source/java/writer2latex/latex/i18n/UnicodeRow.java @@ -0,0 +1,43 @@ +/************************************************************************ + * + * UnicodeRow.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-07-24) + * + */ + +package writer2latex.latex.i18n; + +// Helper class: A row of 256 unicode characters +class UnicodeRow implements Cloneable { + UnicodeCharacter[] entries; + UnicodeRow(){ entries=new UnicodeCharacter[256]; } + + protected Object clone() { + UnicodeRow ur = new UnicodeRow(); + for (int i=0; i<256; i++) { + if (this.entries[i]!=null) { + ur.entries[i] = (UnicodeCharacter) this.entries[i].clone(); + } + } + return ur; + } +} diff --git a/source/java/writer2latex/latex/i18n/UnicodeStringParser.java b/source/java/writer2latex/latex/i18n/UnicodeStringParser.java new file mode 100644 index 0000000..1a7b037 --- /dev/null +++ b/source/java/writer2latex/latex/i18n/UnicodeStringParser.java @@ -0,0 +1,79 @@ +/************************************************************************ + * + * UnicodeStringParser.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-07-24) + * + */ + +package writer2latex.latex.i18n; + +// Helper class: Parse a unicode string. +// Note: Some 8-bit fonts have additional "spacer" characters that are used +// for manual placement of accents. These are ignored between the base character +// and the combining character, thus we are parsing according to the rule +//BeforeAfter
to add LaTeX code to.
+ */
+ public void applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba) {
+ // TODO (polyglossia)
+ }
+
+ /** Push a font to the font stack
+ * @param sName the name of the font
+ */
+ public void pushSpecialTable(String sName) {
+ // TODO
+ }
+
+ /** Pop a font from the font stack
+ */
+ public void popSpecialTable() {
+ // TODO
+ }
+
+ /** Convert a string of characters into LaTeX
+ * @param s the source string
+ * @param bMathMode true if the string should be rendered in math mode
+ * @param sLang the iso language of the string
+ * @return the LaTeX string
+ */
+ public String convert(String s, boolean bMathMode, String sLang){
+ StringBuffer buf = new StringBuffer();
+ int nLen = s.length();
+ char c;
+ for (int i=0; iAdd data to the BeforeAfter
The new data will be be added "inside", thus for example
+ *add("\textsf{","}");
+ * add("\textit{","}");
will create the pair \textsf{\textit{
, }}
BeforeAfter
contains any data
+ * @return true if there is data in at least one part
+ */
+ public boolean isEmpty() { return sBefore.length()==0 && sAfter.length()==0; }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/latex/util/Context.java b/source/java/writer2latex/latex/util/Context.java
new file mode 100644
index 0000000..d963e37
--- /dev/null
+++ b/source/java/writer2latex/latex/util/Context.java
@@ -0,0 +1,310 @@
+/************************************************************************
+ *
+ * Context.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2007 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2007-11-23)
+ *
+ */
+
+package writer2latex.latex.util;
+
+import writer2latex.office.XMLString;
+import writer2latex.office.StyleWithProperties;
+
+/** LaTeX code is in general very context dependent. This class tracks the + * current context, which is the used by the converter to create valid and + * optimal LaTeX code.
+ */ +public class Context { + + // *** Formatting Info (current values in the source OOo document) *** + + // Current list style + private String sListStyleName = null; + + // Current background color + private String sBgColor = null; + + // Current character formatting attributes + private String sFontName = null; + private String sFontStyle = null; + private String sFontVariant = null; + private String sFontWeight = null; + private String sFontSize = null; + private String sFontColor = null; + private String sLang = null; + private String sCountry = null; + + // *** Structural Info (identifies contructions in the LaTeX document) *** + + // within the header or footer of a pagestyle + private boolean bInHeaderFooter = false; + + // within a table cell + private boolean bInTable = false; // any column + private boolean bInLastTableColumn = false; // last column + private boolean bInSimpleTable = false; // l, c or r-column + + // within a multicols environment + private boolean bInMulticols = false; + + // within a list of this level + private int nListLevel = 0; + + // within a section command + private boolean bInSection = false; + + // within a caption + private boolean bInCaption = false; + + // within a floating figure (figure environment) + private boolean bInFigureFloat = false; + + // within a floating table (table envrionment) + private boolean bInTableFloat = false; + + // within a minipage environment + private boolean bInFrame = false; + + // within a \footnote or \endnote + private boolean bInFootnote = false; + + // in verbatim mode + private boolean bVerbatim = false; + + // in math mode + private boolean bMathMode = false; + + // *** Special Info *** + + // Inside (inline) verbatim text, where line breaks are disallowed + private boolean bNoLineBreaks = false; + + // Inside a construction, where footnotes are disallowed + private boolean bNoFootnotes = false; + + // Inside an area, where lists are ignored + private boolean bIgnoreLists = false; + + // *** Accessor Methods *** + + public void setBgColor(String sBgColor) { this.sBgColor = sBgColor; } + + public String getBgColor() { return sBgColor; } + + public void setListStyleName(String sListStyleName) { this.sListStyleName = sListStyleName; } + + public String getListStyleName() { return sListStyleName; } + + public void setFontName(String sFontName) { this.sFontName = sFontName; } + + public String getFontName() { return sFontName; } + + public void setFontStyle(String sFontStyle) { this.sFontStyle = sFontStyle; } + + public String getFontStyle() { return sFontStyle; } + + public void setFontVariant(String sFontVariant) { this.sFontVariant = sFontVariant; } + + public String getFontVariant() { return sFontVariant; } + + public void setFontWeight(String sFontWeight) { this.sFontWeight = sFontWeight; } + + public String getFontWeight() { return sFontWeight; } + + public void setFontSize(String sFontSize) { this.sFontSize = sFontSize; } + + public String getFontSize() { return sFontSize; } + + public void setFontColor(String sFontColor) { this.sFontColor = sFontColor; } + + public String getFontColor() { return sFontColor; } + + public void setLang(String sLang) { this.sLang = sLang; } + + public String getLang() { return sLang; } + + public void setCountry(String sCountry) { this.sCountry = sCountry; } + + public String getCountry() { return sCountry; } + + public void setInHeaderFooter(boolean bInHeaderFooter) { + this.bInHeaderFooter = bInHeaderFooter; + } + + public boolean isInHeaderFooter() { return bInHeaderFooter; } + + public void setInTable(boolean bInTable) { this.bInTable = bInTable; } + + public boolean isInTable() { return bInTable; } + + public void setInLastTableColumn(boolean bInLastTableColumn) { this.bInLastTableColumn = bInLastTableColumn; } + + public boolean isInLastTableColumn() { return bInLastTableColumn; } + + public void setInSimpleTable(boolean bInSimpleTable) { this.bInSimpleTable = bInSimpleTable; } + + public boolean isInSimpleTable() { return bInSimpleTable; } + + public void setInMulticols(boolean bInMulticols) { + this.bInMulticols = bInMulticols; + } + + public boolean isInMulticols() { return bInMulticols; } + + public void setListLevel(int nListLevel) { this.nListLevel = nListLevel; } + + public void incListLevel() { nListLevel++; } + + public int getListLevel() { return nListLevel; } + + public void setInSection(boolean bInSection) { this.bInSection = bInSection; } + + public boolean isInSection() { return bInSection; } + + public void setInCaption(boolean bInCaption) { this.bInCaption = bInCaption; } + + public boolean isInCaption() { return bInCaption; } + + public void setInFigureFloat(boolean bInFigureFloat) { this.bInFigureFloat = bInFigureFloat; } + + public boolean isInFigureFloat() { return bInFigureFloat; } + + public void setInTableFloat(boolean bInTableFloat) { this.bInTableFloat = bInTableFloat; } + + public boolean isInTableFloat() { return bInTableFloat; } + + public void setInFrame(boolean bInFrame) { this.bInFrame = bInFrame; } + + public boolean isInFrame() { return bInFrame; } + + public void setInFootnote(boolean bInFootnote) { + this.bInFootnote = bInFootnote; + } + + public boolean isInFootnote() { return bInFootnote; } + + public void setNoFootnotes(boolean bNoFootnotes) { + this.bNoFootnotes = bNoFootnotes; + } + + public boolean isNoFootnotes() { return bNoFootnotes; } + + public void setIgnoreLists(boolean bIgnoreLists) { + this.bIgnoreLists = bIgnoreLists; + } + + public boolean isIgnoreLists() { return bIgnoreLists; } + + public void setNoLineBreaks(boolean bNoLineBreaks) { + this.bNoLineBreaks = bNoLineBreaks; + } + public boolean isNoLineBreaks() { return bNoLineBreaks; } + + public boolean isVerbatim() { return bVerbatim; } + + public void setVerbatim(boolean bVerbatim) { this.bVerbatim = bVerbatim; } + + public boolean isMathMode() { return bMathMode; } + + public void setMathMode(boolean bMathMode) { this.bMathMode = bMathMode; } + + // update context + + public void updateFormattingFromStyle(StyleWithProperties style) { + String s; + + if (style==null) { return; } + + s = style.getProperty(XMLString.STYLE_FONT_NAME); + if (s!=null) { setFontName(s); } + + s = style.getProperty(XMLString.FO_FONT_STYLE); + if (s!=null) { setFontStyle(s); } + + s = style.getProperty(XMLString.FO_FONT_VARIANT); + if (s!=null) { setFontVariant(s); } + + s = style.getProperty(XMLString.FO_FONT_WEIGHT); + if (s!=null) { setFontWeight(s); } + + s = style.getProperty(XMLString.FO_FONT_SIZE); + if (s!=null) { setFontSize(s); } + + s = style.getProperty(XMLString.FO_COLOR); + if (s!=null) { setFontColor(s); } + + s = style.getProperty(XMLString.FO_LANGUAGE); + if (s!=null) { setLang(s); } + + s = style.getProperty(XMLString.FO_COUNTRY); + if (s!=null) { setCountry(s); } + } + + public void resetFormattingFromStyle(StyleWithProperties style) { + setFontName(null); + setFontStyle(null); + setFontVariant(null); + setFontWeight(null); + setFontSize(null); + setFontColor(null); + setLang(null); + setCountry(null); + updateFormattingFromStyle(style); + } + + + // clone this Context + public Object clone() { + Context newContext = new Context(); + + newContext.setListStyleName(sListStyleName); + newContext.setBgColor(sBgColor); + newContext.setFontName(sFontName); + newContext.setFontStyle(sFontStyle); + newContext.setFontVariant(sFontVariant); + newContext.setFontWeight(sFontWeight); + newContext.setFontSize(sFontSize); + newContext.setFontColor(sFontColor); + newContext.setLang(sLang); + newContext.setCountry(sCountry); + newContext.setInHeaderFooter(bInHeaderFooter); + newContext.setInTable(bInTable); + newContext.setInLastTableColumn(bInLastTableColumn); + newContext.setInSimpleTable(bInSimpleTable); + newContext.setInMulticols(bInMulticols); + newContext.setListLevel(nListLevel); + newContext.setInSection(bInSection); + newContext.setInCaption(bInCaption); + newContext.setInFigureFloat(bInFigureFloat); + newContext.setInTableFloat(bInTableFloat); + newContext.setInFrame(bInFrame); + newContext.setInFootnote(bInFootnote); + newContext.setVerbatim(bVerbatim); + newContext.setMathMode(bMathMode); + newContext.setNoFootnotes(bNoFootnotes); + newContext.setIgnoreLists(bIgnoreLists); + newContext.setNoLineBreaks(bNoLineBreaks); + + return newContext; + } + +} diff --git a/source/java/writer2latex/latex/util/HeadingMap.java b/source/java/writer2latex/latex/util/HeadingMap.java new file mode 100644 index 0000000..2637c75 --- /dev/null +++ b/source/java/writer2latex/latex/util/HeadingMap.java @@ -0,0 +1,69 @@ +/************************************************************************ + * + * HeadingMap.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2006 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2006-11-02) + * + */ + +package writer2latex.latex.util; + +/** This class contains data for the mapping of OOo headings to LaTeX headings. + A LaTeX heading is characterized by a name and a level. + The heading is inserted with \name{...} or \name[...]{...} + The headings are supposed to be "normal" LaTeX headings, + ie. the names are also counter names, and the headings + can be reformatted using \@startsection etc. + Otherwise max-level should be zero. +*/ +public class HeadingMap { + private int nMaxLevel; + private String[] sName; + private int[] nLevel; + + /** Constructor: Create a new HeadingMap + @param nMaxLevel the maximal level of headings that are mapped */ + public HeadingMap(int nMaxLevel) { + reset(nMaxLevel); + } + + /** Clear all data associated with this HeadingMap (in order to reuse it) */ + public void reset(int nMaxLevel) { + this.nMaxLevel = nMaxLevel; + sName = new String[nMaxLevel+1]; + nLevel = new int[nMaxLevel+1]; + } + + /** Set data associated with a specific heading level */ + public void setLevelData(int nWriterLevel, String sName, int nLevel) { + this.sName[nWriterLevel] = sName; + this.nLevel[nWriterLevel] = nLevel; + } + + /** Returns the maximal Writer level associated with this HeadingMap */ + public int getMaxLevel() { return nMaxLevel; } + + /** Return the name (for counter and \@startsection) for this level */ + public String getName(int nWriterLevel) { return sName[nWriterLevel]; } + + /** Return the LaTeX level for this Writer level (for \@startsection) */ + public int getLevel(int nWriterLevel) { return nLevel[nWriterLevel]; } +} diff --git a/source/java/writer2latex/latex/util/Info.java b/source/java/writer2latex/latex/util/Info.java new file mode 100644 index 0000000..24a0424 --- /dev/null +++ b/source/java/writer2latex/latex/util/Info.java @@ -0,0 +1,76 @@ +/************************************************************************ + * + * Info.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-09-08) + * + */ + +package writer2latex.latex.util; + +import org.w3c.dom.Element; + +import writer2latex.latex.LaTeXConfig; +import writer2latex.util.Misc; +import writer2latex.office.OfficeReader; +import writer2latex.office.StyleWithProperties; +import writer2latex.office.XMLString; +import writer2latex.latex.LaTeXDocumentPortion; +import writer2latex.latex.ConverterHelper; +import writer2latex.latex.ConverterPalette; + + +/** + *This class creates various information to the user about the conversion.
+ */ +public class Info extends ConverterHelper { + + public Info(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { + super(ofr,config,palette); + } + + public void addDebugInfo(Element node, LaTeXDocumentPortion ldp) { + if (config.debug()) { + ldp.append("% ").append(node.getNodeName()); + addDebugInfo(node,ldp,XMLString.TEXT_ID); + addDebugInfo(node,ldp,XMLString.TEXT_NAME); + addDebugInfo(node,ldp,XMLString.TABLE_NAME); + addDebugInfo(node,ldp,XMLString.TEXT_STYLE_NAME); + if (node.getNodeName().equals(XMLString.TEXT_P) || node.getNodeName().equals(XMLString.TEXT_H)) { + StyleWithProperties style = ofr.getParStyle(node.getAttribute(XMLString.TEXT_STYLE_NAME)); + if (style!=null && style.isAutomatic()) { + ldp.append(" ("+style.getParentName()+")"); + } + ldp.append(" ("+ofr.getParStyles().getDisplayName(node.getAttribute(XMLString.TEXT_STYLE_NAME))+")"); + } + ldp.nl(); + } + } + + private void addDebugInfo(Element node, LaTeXDocumentPortion ldp, String sAttribute) { + String sValue = Misc.getAttribute(node,sAttribute); + if (sValue!=null) { + ldp.append(" ").append(sAttribute).append("=\"").append(sValue).append("\""); + } + } + + +} \ No newline at end of file diff --git a/source/java/writer2latex/latex/util/Package.html b/source/java/writer2latex/latex/util/Package.html new file mode 100644 index 0000000..e59bf06 --- /dev/null +++ b/source/java/writer2latex/latex/util/Package.html @@ -0,0 +1,11 @@ + + + + +Some general utility classes for LaTeX export.
+ + diff --git a/source/java/writer2latex/latex/util/StyleMap.java b/source/java/writer2latex/latex/util/StyleMap.java new file mode 100644 index 0000000..d4469ef --- /dev/null +++ b/source/java/writer2latex/latex/util/StyleMap.java @@ -0,0 +1,99 @@ +/************************************************************************ + * + * StyleMap.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2007-07-30) + * + */ + +package writer2latex.latex.util; + +import java.util.Hashtable; +import java.util.Enumeration; + +public class StyleMap { + private Hashtable items = new Hashtable(); + + public void put(String sName, String sBefore, String sAfter, boolean bLineBreak, boolean bVerbatim) { + StyleMapItem item = new StyleMapItem(); + item.sBefore = sBefore; + item.sAfter = sAfter; + item.sNext = ";;"; + item.bLineBreak = bLineBreak; + item.bVerbatim = bVerbatim; + items.put(sName,item); + } + + public void put(String sName, String sBefore, String sAfter, String sNext, boolean bVerbatim) { + StyleMapItem item = new StyleMapItem(); + item.sBefore = sBefore; + item.sAfter = sAfter; + item.sNext = ";"+sNext+";"; + item.bLineBreak = true; + item.bVerbatim = bVerbatim; + items.put(sName,item); + } + + public void put(String sName, String sBefore, String sAfter) { + StyleMapItem item = new StyleMapItem(); + item.sBefore = sBefore; + item.sAfter = sAfter; + item.sNext = ";;"; + item.bLineBreak = true; + item.bVerbatim = false; + items.put(sName,item); + } + + public boolean contains(String sName) { + return sName!=null && items.containsKey(sName); + } + + public String getBefore(String sName) { + return ((StyleMapItem) items.get(sName)).sBefore; + } + + public String getAfter(String sName) { + return ((StyleMapItem) items.get(sName)).sAfter; + } + + public String getNext(String sName) { + String sNext = ((StyleMapItem) items.get(sName)).sNext; + return sNext.substring(1,sNext.length()-1); + } + + public boolean isNext(String sName, String sNext) { + String sNext1 = ((StyleMapItem) items.get(sName)).sNext; + return sNext1.indexOf(";"+sNext+";")>-1; + } + + public boolean getLineBreak(String sName) { + return contains(sName) && ((StyleMapItem) items.get(sName)).bLineBreak; + } + + public boolean getVerbatim(String sName) { + return contains(sName) && ((StyleMapItem) items.get(sName)).bVerbatim; + } + + public Enumeration getNames() { + return items.keys(); + } + +} diff --git a/source/java/writer2latex/latex/util/StyleMapItem.java b/source/java/writer2latex/latex/util/StyleMapItem.java new file mode 100644 index 0000000..a4ecb61 --- /dev/null +++ b/source/java/writer2latex/latex/util/StyleMapItem.java @@ -0,0 +1,36 @@ +/************************************************************************ + * + * StyleMapItem.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2007-07-30) + * + */ + +package writer2latex.latex.util; + +// A struct to hold data about a style map +class StyleMapItem { + String sBefore; + String sAfter; + String sNext; + boolean bLineBreak; + boolean bVerbatim; +} diff --git a/source/java/writer2latex/office/BibMark.java b/source/java/writer2latex/office/BibMark.java new file mode 100644 index 0000000..ce3426f --- /dev/null +++ b/source/java/writer2latex/office/BibMark.java @@ -0,0 +1,146 @@ +/************************************************************************ + * + * BibMark.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-22) + * + */ + +package writer2latex.office; + +import org.w3c.dom.Node; + +import writer2latex.util.*; +//import writer2latex.office.*; + +/** + *This class represents a single bibliography-mark.
+ */ +public final class BibMark { + // Available fields + public static final int ADDRESS = 0; + public static final int ANNOTE = 1; + public static final int AUTHOR = 2; + public static final int BOOKTITLE = 3; + public static final int CHAPTER = 4; + // public static final int CROSSREF = 5; // BibTeX, missing in OOo + public static final int EDITION = 6; + public static final int EDITOR = 7; + public static final int HOWPUBLISHED = 8; + public static final int INSTITUTION = 9; + public static final int JOURNAL = 10; + // public static final int KEY = 11; // BibTeX, missing in OOo + public static final int MONTH = 12; + public static final int NOTE = 13; + public static final int NUMBER = 14; + public static final int ORGANIZATIONS = 15; // BibTeX: organization + public static final int PAGES = 16; + public static final int PUBLISHER = 17; + public static final int SCHOOL = 18; + public static final int SERIES = 19; + public static final int TITLE = 20 ; + public static final int REPORT_TYPE = 21; // BibTeX: report + public static final int VOLUME = 22; + public static final int YEAR = 23; + // remaining fields are not standard in BibTeX + public static final int URL = 24; + public static final int CUSTOM1 = 25; + public static final int CUSTOM2 = 26; + public static final int CUSTOM3 = 27; + public static final int CUSTOM4 = 28; + public static final int CUSTOM5 = 29; + public static final int ISBN = 30; + public static final int FIELD_COUNT = 31; + + + // Private data + private String sIdentifier; + private String sEntryType; + private String[] fields = new String[FIELD_COUNT]; + + /** + *Create a new BibMark from scratch.
+ */ + public BibMark(String sIdentifier, String sEntryType) { + this.sIdentifier = sIdentifier; + this.sEntryType = sEntryType; + } + + /** + *Create a new BibMark from a text:bibliography-mark node.
+ */ + public BibMark(Node node) { + sIdentifier = Misc.getAttribute(node,XMLString.TEXT_IDENTIFIER); + sEntryType = Misc.getAttribute(node,XMLString.TEXT_BIBLIOGRAPHY_TYPE); + if (sEntryType==null) { // bug in OOo 1.0! + sEntryType = Misc.getAttribute(node,XMLString.TEXT_BIBILIOGRAPHIC_TYPE); + } + fields[ADDRESS] = Misc.getAttribute(node,XMLString.TEXT_ADDRESS); + fields[ANNOTE] = Misc.getAttribute(node,XMLString.TEXT_ANNOTE); + fields[AUTHOR] = Misc.getAttribute(node,XMLString.TEXT_AUTHOR); + fields[BOOKTITLE] = Misc.getAttribute(node,XMLString.TEXT_BOOKTITLE); + fields[CHAPTER] = Misc.getAttribute(node,XMLString.TEXT_CHAPTER); + fields[EDITION] = Misc.getAttribute(node,XMLString.TEXT_EDITION); + fields[EDITOR] = Misc.getAttribute(node,XMLString.TEXT_EDITOR); + fields[HOWPUBLISHED] = Misc.getAttribute(node,XMLString.TEXT_HOWPUBLISHED); + fields[INSTITUTION] = Misc.getAttribute(node,XMLString.TEXT_INSTITUTION); + fields[JOURNAL] = Misc.getAttribute(node,XMLString.TEXT_JOURNAL); + fields[MONTH] = Misc.getAttribute(node,XMLString.TEXT_MONTH); + fields[NOTE] = Misc.getAttribute(node,XMLString.TEXT_NOTE); + fields[NUMBER] = Misc.getAttribute(node,XMLString.TEXT_NUMBER); + fields[ORGANIZATIONS] = Misc.getAttribute(node,XMLString.TEXT_ORGANIZATIONS); + fields[PAGES] = Misc.getAttribute(node,XMLString.TEXT_PAGES); + fields[PUBLISHER] = Misc.getAttribute(node,XMLString.TEXT_PUBLISHER); + fields[SCHOOL] = Misc.getAttribute(node,XMLString.TEXT_SCHOOL); + fields[SERIES] = Misc.getAttribute(node,XMLString.TEXT_SERIES); + fields[TITLE] = Misc.getAttribute(node,XMLString.TEXT_TITLE); + fields[REPORT_TYPE] = Misc.getAttribute(node,XMLString.TEXT_REPORT_TYPE); + fields[VOLUME] = Misc.getAttribute(node,XMLString.TEXT_VOLUME); + fields[YEAR] = Misc.getAttribute(node,XMLString.TEXT_YEAR); + fields[URL] = Misc.getAttribute(node,XMLString.TEXT_URL); + fields[CUSTOM1] = Misc.getAttribute(node,XMLString.TEXT_CUSTOM1); + fields[CUSTOM2] = Misc.getAttribute(node,XMLString.TEXT_CUSTOM2); + fields[CUSTOM3] = Misc.getAttribute(node,XMLString.TEXT_CUSTOM3); + fields[CUSTOM4] = Misc.getAttribute(node,XMLString.TEXT_CUSTOM4); + fields[CUSTOM5] = Misc.getAttribute(node,XMLString.TEXT_CUSTOM5); + fields[ISBN] = Misc.getAttribute(node,XMLString.TEXT_ISBN); + } + + /** + *Get the identifier.
+ */ + public String getIdentifier() { return sIdentifier; } + + /** + *Get the entry type.
+ */ + public String getEntryType() { return sEntryType; } + + /** + *Set a specific field.
+ */ + public void setField(int nField,String sValue) { fields[nField] = sValue; } + + /** + *Return a specific field.
+ */ + public String getField(int nField) { return fields[nField]; } +} \ No newline at end of file diff --git a/source/java/writer2latex/office/CellView.java b/source/java/writer2latex/office/CellView.java new file mode 100644 index 0000000..62aefbc --- /dev/null +++ b/source/java/writer2latex/office/CellView.java @@ -0,0 +1,40 @@ +/************************************************************************ + * + * CellView.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-09-07) + * + */ + +package writer2latex.office; + +import org.w3c.dom.Element; + +/** + * This class represent a cell in a table view + */ +public class CellView { + public Element cell = null; + public int nRowSpan = 1; + public int nColSpan = 1; + public int nOriginalRow = -1; + public int nOriginalCol = -1; +} \ No newline at end of file diff --git a/source/java/writer2latex/office/ControlReader.java b/source/java/writer2latex/office/ControlReader.java new file mode 100644 index 0000000..a7f0f8a --- /dev/null +++ b/source/java/writer2latex/office/ControlReader.java @@ -0,0 +1,151 @@ +/************************************************************************ + * + * ControlReader.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-23) + * + */ + +package writer2latex.office; + +//import java.util.Hashtable; +import java.util.Vector; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import writer2latex.util.Misc; + +/**This class reads a form control in an OOo document (a form:control + * node). A control always has an owner form. + * Properties and events are ignored.
+ */ +public class ControlReader { + + private FormReader ownerForm; // a control always belongs to a form + private String sId; // a control is identified by id + private Element control; // the control element + private Element controlType; // the type specific child element + private Vector items = new Vector(); // the options/items of a list/combobox + + /**The constructor reads the content of a control element
+ * The representation in OpenDocument differs slightly from OOo 1.x. + + * @param control a DOM element, which must be control node + */ + public ControlReader(Element control, FormReader ownerForm) { + this.ownerForm = ownerForm; + this.control = control; + sId = control.getAttribute(XMLString.FORM_ID); + // Read the control type specific info + if (control.getTagName().equals(XMLString.FORM_CONTROL)) { // old format + controlType = Misc.getFirstChildElement(control); + } + else { // oasos + controlType = control; + } + if (controlType!=null) { // must always be the case! + // Collect options/items + Node child = controlType.getFirstChild(); + while (child!=null) { + if (child.getNodeType()==Node.ELEMENT_NODE && ( + child.getNodeName().equals(XMLString.FORM_OPTION) || + child.getNodeName().equals(XMLString.FORM_ITEM))) { + items.add(child); + } + child = child.getNextSibling(); + } + } + } + + /**A control in OOo is identified by id (form:control-id
+ * attribute. The id is accessed by this method.
A control in OOo belongs to a form.
+ * @return the form containing this control + */ + public FormReader getOwnerForm() { return ownerForm; } + + /**Get an attribute of the control. If the attribute does not exist,
+ * this method returns null
.
+ * @param sName the name of the attribute
+ * @return the value of the attribute, or null
+ */
+ public String getAttribute(String sName) {
+ return control.hasAttribute(sName) ? control.getAttribute(sName) : null;
+ }
+
+ /**
The type of the control is identified by a name, eg. form:submit
+ * @return the type of this control + */ + public String getControlType() { return controlType.getTagName(); } + + /**Get an attribute specific to this type of control.
+ * If the attribute does not exist, this method returns null
.
+ * @param sName the name of the attribute
+ * @return the value of the attribute, or null
+ */
+ public String getTypeAttribute(String sName) {
+ return controlType!=null && controlType.hasAttribute(sName) ?
+ controlType.getAttribute(sName) : null;
+ }
+
+ /**
Return the number of options/items in this control. + * Only listbox (options) and combobox (items) controls can have these, + * for other controls this will return 0. + * @return the number of options/items + */ + public int getItemCount() { return items.size(); } + + /**
Get an attribute of an option/item.
+ * If the index and/or the attribute does not exist, this method returns
+ * null
.
+ * @param nIndex the index of the option/item
+ * @param sName the name of the attribute
+ * @return the value of the attribute, or null
+ */
+ public String getItemAttribute(int nIndex, String sName) {
+ if (0<=nIndex && nIndex<=items.size()) {
+ return ((Element)items.get(nIndex)).hasAttribute(sName) ?
+ ((Element)items.get(nIndex)).getAttribute(sName) : null;
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
Get the value of an option/item.
+ * If the index does not exist, this method returns
+ * null
.
+ * @param nIndex the index of the option/item
+ * @return the value of the option/item, or null
+ */
+ public String getItemValue(int nIndex) {
+ if (0<=nIndex && nIndex<=items.size()) {
+ return Misc.getPCDATA((Element)items.get(nIndex));
+ }
+ else {
+ return null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/office/FontDeclaration.java b/source/java/writer2latex/office/FontDeclaration.java
new file mode 100644
index 0000000..e286f83
--- /dev/null
+++ b/source/java/writer2latex/office/FontDeclaration.java
@@ -0,0 +1,61 @@
+/************************************************************************
+ *
+ * FontDeclaration.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2005 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 0.5 (2005-10-10)
+ *
+ */
+
+package writer2latex.office;
+
+import org.w3c.dom.Node;
+
+/**
Class representing a font declaration in OOo
+ */ +public class FontDeclaration extends OfficeStyle { + private PropertySet properties = new PropertySet(); + + private String sFontFamily = null; + private String sFontFamilyGeneric = null; + private String sFontPitch = null; + + public void loadStyleFromDOM(Node node) { + super.loadStyleFromDOM(node); + properties.loadFromDOM(node); + sFontFamily = properties.getProperty(XMLString.FO_FONT_FAMILY); + if (sFontFamily==null) { // oasis + sFontFamily = properties.getProperty(XMLString.SVG_FONT_FAMILY); + } + sFontFamilyGeneric = properties.getProperty(XMLString.STYLE_FONT_FAMILY_GENERIC); + sFontPitch = properties.getProperty(XMLString.STYLE_FONT_PITCH); + } + + public String getProperty(String sProperty){ + return properties.getProperty(sProperty); + } + + public String getFontFamily() { return sFontFamily; } + + public String getFontFamilyGeneric() { return sFontFamilyGeneric; } + + public String getFontPitch() { return sFontPitch; } + +} diff --git a/source/java/writer2latex/office/FormReader.java b/source/java/writer2latex/office/FormReader.java new file mode 100644 index 0000000..25dea9d --- /dev/null +++ b/source/java/writer2latex/office/FormReader.java @@ -0,0 +1,79 @@ +/************************************************************************ + * + * FormReader.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + */ + +// Version 1.0 (2008-11-22) + +package writer2latex.office; + +//import java.util.Hashtable; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import writer2latex.util.Misc; + +/**This class reads a form in an OOo document (a form:form node)
+ * Note: Subforms, properties and events are ignored. + */ +public class FormReader { + + //private FormsReader forms; // the global collection of all forms + private String sName; // a form is identified by name + private Element form; // the form element + + /**The constructor reads the content of a form:form
element
form:form
node
+ */
+ public FormReader(Element form, FormsReader forms) {
+ //this.forms = forms;
+ this.form = form;
+ sName = form.getAttribute(XMLString.FORM_NAME);
+ // Collect all controls contained in this form
+ Node child = form.getFirstChild();
+ while (child!=null) {
+ if (child.getNodeType()==Node.ELEMENT_NODE) {
+ String sId = Misc.getAttribute((Element)child,XMLString.FORM_ID);
+ if (sId!=null) {
+ ControlReader control = new ControlReader((Element) child, this);
+ forms.addControl(control);
+ }
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ /** A form in OOo is identified by name (form:name
+ * attribute. The name is accessed by this method.
Get an attribute of the form. If the attribute does not exist,
+ * this method returns null
.
+ * @param sName the name of the attribute
+ * @return the value of the attribute, or null
+ */
+ public String getAttribute(String sName) {
+ return form.hasAttribute(sName) ? form.getAttribute(sName) : null;
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/office/FormsReader.java b/source/java/writer2latex/office/FormsReader.java
new file mode 100644
index 0000000..978f5cb
--- /dev/null
+++ b/source/java/writer2latex/office/FormsReader.java
@@ -0,0 +1,114 @@
+/************************************************************************
+ *
+ * FormsReader.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-23)
+ *
+ */
+
+package writer2latex.office;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
This class reads the collection of all forms in an OOo document
+ * (the office:forms
element).
An OOo document may contain any number of forms; these are declared
+ * within this element. In OOo, unlike eg. html, the form declaration is
+ * separated from the presentation. This element contains the
+ * declaration. The presentation is given by inclusion of
+ * draw:control
elements in the document flow. These refer to form
+ * controls by id.
Note: A form is identified by a unique name, a control is + * identified by a (globally) unique id.
+ */ +public class FormsReader { + + private Element formsElement; // The office:forms element + private Hashtable forms = new Hashtable(); // all forms, indexed by name + private Hashtable controls = new Hashtable(); // all controls, indexed by id + + /**Read the content of an office:forms
element
office:forms
node
+ */
+ public void read(Element formsElement) {
+ this.formsElement = formsElement;
+ // Collect all forms
+ Node child = formsElement.getFirstChild();
+ while (child!=null) {
+ if (child.getNodeType()==Node.ELEMENT_NODE &&
+ child.getNodeName().equals(XMLString.FORM_FORM)) {
+ FormReader form = new FormReader((Element) child, this);
+ forms.put(form.getName(),form);
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ /** Get an attribute of the forms. If the attribute does not exist,
+ * this method returns null
.
+ * @param sName the name of the attribute
+ * @return the value of the attribute, or null
+ */
+ public String getAttribute(String sName) {
+ return formsElement.hasAttribute(sName) ? formsElement.getAttribute(sName) : null;
+ }
+
+ /**
Get a Iterator
over all forms.
Iterator
over all forms
+ */
+ public Iterator getFormsIterator() {
+ return forms.values().iterator();
+ }
+
+ /** Get a form by name
+ * @param sName theform:name
of the form
+ * @return the form as a FormReader
object
+ */
+ public FormReader getForm(String sName) {
+ return (FormReader) forms.get(sName);
+ }
+
+ /** Get a Iterator
over all controls.
Iterator
over all controls
+ */
+ public Iterator getControlsIterator() {
+ return controls.values().iterator();
+ }
+
+ /** Get a control by id
+ * @param sId theform:control-id
of the control
+ * @return the control as a ControlReader
object
+ */
+ public ControlReader getControl(String sId) {
+ return (ControlReader) controls.get(sId);
+ }
+
+ /** Add a control
+ * @param control aControlReader
representing the control
+ */
+ protected void addControl(ControlReader control) {
+ controls.put(control.getId(),control);
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/office/ImageLoader.java b/source/java/writer2latex/office/ImageLoader.java
new file mode 100644
index 0000000..68c6f42
--- /dev/null
+++ b/source/java/writer2latex/office/ImageLoader.java
@@ -0,0 +1,194 @@
+/************************************************************************
+ *
+ * ImageLoader.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.office;
+
+//import java.io.ByteArrayInputStream;
+//import java.io.ByteArrayOutputStream;
+//import java.io.IOException;
+import java.util.HashSet;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import writer2latex.api.GraphicConverter;
+import writer2latex.util.Base64;
+import writer2latex.util.Misc;
+import writer2latex.xmerge.BinaryGraphicsDocument;
+import writer2latex.xmerge.EmbeddedObject;
+import writer2latex.xmerge.EmbeddedBinaryObject;
+import writer2latex.xmerge.OfficeDocument;
+
+//import writer2latex.util.*;
+
+/**
+ * This class extracts images from an OOo file. + * The images are returned as BinaryGraphicsDocument.
+ */ +public final class ImageLoader { + // The Office document to load images from + private OfficeDocument oooDoc; + + // Data for file name generation + private String sOutFileName; + private boolean bUseSubdir = false; + private int nImageCount = 0; + + // should EPS be extracted from SVM? + private boolean bExtractEPS; + + // Data for image conversion + private GraphicConverter gcv = null; + private boolean bAcceptOtherFormats = true; + private String sDefaultFormat = null; + private String sDefaultVectorFormat = null; + private HashSet acceptedFormats = new HashSet(); + + public ImageLoader(OfficeDocument oooDoc, String sOutFileName, boolean bExtractEPS) { + this.oooDoc = oooDoc; + this.sOutFileName = sOutFileName; + this.bExtractEPS = bExtractEPS; + } + + public void setOutFileName(String sOutFileName) { this.sOutFileName = sOutFileName; } + + public void setUseSubdir(boolean bUseSubdir) { this.bUseSubdir = bUseSubdir; } + + public void setAcceptOtherFormats(boolean b) { bAcceptOtherFormats = b; } + + public void setDefaultFormat(String sMime) { + addAcceptedFormat(sMime); + sDefaultFormat = sMime; + } + + public void setDefaultVectorFormat(String sMime) { + addAcceptedFormat(sMime); + sDefaultVectorFormat = sMime; + } + + public void addAcceptedFormat(String sMime) { acceptedFormats.add(sMime); } + + private boolean isAcceptedFormat(String sMime) { return acceptedFormats.contains(sMime); } + + public void setGraphicConverter(GraphicConverter gcv) { this.gcv = gcv; } + + public BinaryGraphicsDocument getImage(Node node) { + // node must be a draw:image element. + // variables to hold data about the image: + String sMIME = null; + String sExt = null; + byte[] blob = null; + + String sHref = Misc.getAttribute(node,XMLString.XLINK_HREF); + if (sHref==null || sHref.length()==0) { + // Image must be contained in an office:binary-element as base64: + Node obd = Misc.getChildByTagName(node,XMLString.OFFICE_BINARY_DATA); + if (obd!=null) { + StringBuffer buf = new StringBuffer(); + NodeList nl = obd.getChildNodes(); + int nLen = nl.getLength(); + for (int i=0; iThis class produces labels for OOo lists/outlines (for xhtml + * and text, which cannot produce them on their own).
+ * + */ +public class ListCounter { + private int nCounter[] = new int[11]; + private String sNumFormat[] = new String[11]; + private ListStyle style; + private int nLevel=1; // current level + + public ListCounter() { + // Create a dummy counter + this.style = null; + for (int i=1; i<=10; i++) { + sNumFormat[i] = null; + } + } + + public ListCounter(ListStyle style) { + this(); + if (style!=null) { + this.style = style; + for (int i=1; i<=10; i++) { + sNumFormat[i] = style.getLevelProperty(i,XMLString.STYLE_NUM_FORMAT); + } + } + } + + public ListCounter step(int nLevel) { + // Make sure no higher levels are zero + // This means that unlike eg. LaTeX, step(1).step(3) does not create + // the value 1.0.1 but rather 1.1.1 + for (int i=1; iThe class reads a text:illustration-index
or
+ * text:table-index
element.
Initialize the LoftReader with a illustration/table index node
+ * @param onode a text:*-index
+ */
+ public LoftReader(Element onode) {
+ bIsTableIndex = onode.getTagName().equals(XMLString.TEXT_TABLE_INDEX);
+
+ sName = Misc.getAttribute(onode,XMLString.TEXT_NAME);
+ sStyleName = Misc.getAttribute(onode,XMLString.TEXT_STYLE_NAME);
+
+ loftSource = bIsTableIndex ?
+ Misc.getChildByTagName(onode,XMLString.TEXT_TABLE_INDEX_SOURCE) :
+ Misc.getChildByTagName(onode,XMLString.TEXT_ILLUSTRATION_INDEX_SOURCE);
+
+ indexBody = Misc.getChildByTagName(onode,XMLString.TEXT_INDEX_BODY);
+
+ if (loftSource!=null) {
+ bUseCaption = !"false".equals(loftSource.getAttribute(XMLString.TEXT_USE_CAPTION));
+ sCaptionSequenceName = loftSource.getAttribute(XMLString.TEXT_CAPTION_SEQUENCE_NAME);
+ bIsByChapter = "chapter".equals(loftSource.getAttribute(XMLString.TEXT_INDEX_SCOPE));
+
+ indexTitleTemplate = Misc.getChildByTagName(loftSource,XMLString.TEXT_INDEX_TITLE_TEMPLATE);
+ loftEntryTemplate = bIsTableIndex ?
+ Misc.getChildByTagName(loftSource,XMLString.TEXT_TABLE_INDEX_ENTRY_TEMPLATE) :
+ Misc.getChildByTagName(loftSource,XMLString.TEXT_ILLUSTRATION_INDEX_ENTRY_TEMPLATE);
+ }
+ }
+
+ /**
Get the (section) name for this loft
+ * @return the name of the loft + */ + public String getName() { return sName; } + + /**Get the (section) style name for this loft
+ * @return name of the section style to use for this loft + */ + public String getStyleName() { return sStyleName; } + + /**Is this a table index or a figure index?
+ * @return true if it's a table index + */ + public boolean isTableIndex() { return bIsTableIndex; } + + /**Is this loft by chapter?
+ * @return true if the scope is a chapter only + */ + public boolean isByChapter() { return bIsByChapter; } + + /**Is this loft generated by captions? (otherwise: by object names)
+ * @return true if we use captions + */ + public boolean useCaption() { return bUseCaption; } + + /**Get the sequence name to use for the caption
+ * @return the name of the caption + */ + public String getCaptionSequenceName() { return sCaptionSequenceName; } + + /**Get the index title template for this loft
+ * @return thetext:index-title-template
element, or null
+ */
+ public Element getIndexTitleTemplate() { return indexTitleTemplate; }
+
+ /** Get the entry template for this loft at a specific level
+ * @param nLevel the outline level + * @return thetext:table-of-content-entry-template
element, or null
+ */
+ public Element getLoftEntryTemplate(int nLevel) {
+ return loftEntryTemplate;
+ }
+
+ /** Return the generated content of this loft, if available
+ * @return thetext:index-body
element
+ */
+ public Element getIndexBody() { return indexBody; }
+
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/office/MIMETypes.java b/source/java/writer2latex/office/MIMETypes.java
new file mode 100644
index 0000000..3ae462e
--- /dev/null
+++ b/source/java/writer2latex/office/MIMETypes.java
@@ -0,0 +1,159 @@
+/************************************************************************
+ *
+ * MIMETypes.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-24)
+ *
+ */
+
+package writer2latex.office;
+
+/* Some helpers to handle the MIME types used by OOo
+ */
+
+public final class MIMETypes extends writer2latex.api.MIMETypes {
+ // OOo MIME types, taken from
+ // http://framework.openoffice.org/documentation/mimetypes/mimetypes.html
+ public static final String WRITER="application/vnd.sun.xml.writer";
+ public static final String CALC="application/vnd.sun.xml.calc";
+ public static final String IMPRESS="application/vnd.sun.xml.impress";
+ public static final String DRAW="application/vnd.sun.xml.draw";
+ public static final String CHART="application/vnd.sun.xml.chart";
+ public static final String MATH="application/vnd.sun.xml.math";
+ // OpenDocument MIME types (from spec)
+ public static final String ODT="application/vnd.oasis.opendocument.text";
+ public static final String ODS="application/vnd.oasis.opendocument.spreadsheet";
+ public static final String ODP="application/vnd.oasis.opendocument.presentation";
+ public static final String ODF="application/vnd.oasis.opendocument.formula";
+
+ // zip
+ public static final String ZIP="application/zip";
+
+ // Magic signatures for some binary files
+ public static final byte[] PNG_SIG = { (byte) 0x89, 0x50, 0x4e, 0x47 }; // .PNG
+ public static final byte[] JPEG_SIG = { (byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xe0 };
+ public static final byte[] GIF87_SIG = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; // GIF87a
+ public static final byte[] GIF89_SIG = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; // GIF89a
+ public static final byte[] TIFF_SIG = { 0x49, 0x49, 0x2A }; // II*
+ public static final byte[] BMP_SIG = { 0x42, 0x4d }; // BM
+ public static final byte[] WMF_SIG = { (byte) 0xd7, (byte) 0xcd, (byte) 0xc6, (byte) 0x9a };
+ public static final byte[] WMF30_SIG = { 1, 0, 9, 0 }; // Old WMF format, not reliable - see below
+ public static final byte[] EPS_SIG = { 0x25, 0x21 }; // %!
+ public static final byte[] SVM_SIG = { 0x56, 0x43, 0x4c, 0x4d, 0x54, 0x46 }; // VCLMTF
+ public static final byte[] ZIP_SIG = { 0x50, 0x4b, 0x03, 0x04 }; // PK..
+
+
+ // Preferred file extensions for some files
+ public static final String LATEX_EXT = ".tex";
+ public static final String BIBTEX_EXT = ".bib";
+ public static final String XHTML_EXT = ".html";
+ public static final String XHTML_MATHML_EXT = ".xhtml";
+ public static final String XHTML_MATHML_XSL_EXT = ".xml";
+ public static final String PNG_EXT = ".png";
+ public static final String JPEG_EXT = ".jpg"; // this is the default in graphicx.sty
+ public static final String GIF_EXT = ".gif";
+ public static final String TIFF_EXT = ".tif";
+ public static final String BMP_EXT = ".bmp";
+ public static final String WMF_EXT = ".wmf";
+ public static final String EPS_EXT = ".eps";
+ public static final String SVM_EXT = ".svm";
+ public static final String PDF_EXT = ".pdf";
+
+ private static final boolean isType(byte[] blob, byte[] sig) {
+ int n = sig.length;
+ for (int i=0; iThis class represents the metadata of an OOo Writer document.
+ */ +public class MetaData { + // Dublin Core + private String sTitle = ""; + private String sCreator = ""; + private String sInitialCreator = ""; + private String sDate = ""; + private String sDescription = ""; + private String sLanguage = ""; + private String sSubject = ""; + // Keywords + private String sKeywords = ""; + + /**Construct a new instance from an OOo Writer document.
+ * @param oooDoc is the OOo document + */ + public MetaData(OfficeDocument oooDoc) { + // get the DOM (either package or flat) + Document dom = oooDoc.getMetaDOM(); + if (dom==null) { dom = oooDoc.getContentDOM(); } + + // get the office:meta element + NodeList list = dom.getElementsByTagName(XMLString.OFFICE_META); + if (list.getLength() == 0) { return; } // oops, no metadata - fails silently + Node meta = list.item(0); + if (!meta.hasChildNodes()) { return; } + + // traverse the metadata + CSVList keywords = new CSVList(", "); + list = meta.getChildNodes(); + int nLen = list.getLength(); + for (int i=0; iGet the creator of this document (may be null)
+ * @return the creator of the document (or the initial creator if none is specified) + */ + public String getCreator() { return sCreator==null ? sInitialCreator : sCreator; } + + /**Get the initial creator of this document (may be null)
+ * @return the initial creator of the document + */ + public String getInitialCreator() { return sInitialCreator; } + + /**Get the date of this document (may be null)
+ * @return the date of the document + */ + public String getDate() { return sDate; } + + /**Get the description of this document (may be null)
+ * @return the description of the document + */ + public String getDescription() { return sDescription; } + + /**Get the language of this document (may be null)
+ * @return the language of the document + */ + public String getLanguage() { return sLanguage; } + + /**Get the subject of this document (may be null)
+ * @return the subject of the document + */ + public String getSubject() { return sSubject; } + + /**Get the keywords of this document as a comma separated list (may be null)
+ * @return the keywords of the document + */ + public String getKeywords() { return sKeywords; } + + private String getContent(Node node) { + if (!node.hasChildNodes()) { return null; } + String s=""; + NodeList list = node.getChildNodes(); + int nLen = list.getLength(); + for (int i=0; iChecks, if the only text content of this node is whitespace
+ * @param node the node to check (should be a paragraph node or a child + * of a paragraph node) + * @return true if the node contains whitespace only + */ + public static boolean isWhitespaceContent(Node node) { + Node child = node.getFirstChild(); + while (child!=null) { + if (child.getNodeType()==Node.ELEMENT_NODE) { + if (child.getNodeName().equals(XMLString.TEXT_SPAN)) { + if (!isWhitespaceContent(child)) { return false; } + } + else if (child.getNodeName().equals(XMLString.TEXT_A)) { + if (!isWhitespaceContent(child)) { return false; } + } + else if (child.getNodeName().equals(XMLString.TEXT_BIBLIOGRAPHY_MARK)) { + if (!isWhitespaceContent(child)) { return false; } + } + else if (!isTextElement(child)) { + return false; // found non-text content! + } + } + else if (child.getNodeType()==Node.TEXT_NODE) { + if (!isWhitespace(child.getNodeValue())) { return false; } + } + child = child.getNextSibling(); + } + return true; // found nothing! + } + + /**Checks, if this text is whitespace
+ * @param s the String to check + * @return true if the String contains whitespace only + */ + public static boolean isWhitespace(String s) { + int nLen = s.length(); + for (int i=0; iGet the collection of all font declarations.
+ * @return theOfficeStyleFamily
of font declarations
+ */
+ public OfficeStyleFamily getFontDeclarations() { return font; }
+
+ /** Get a specific font declaration
+ * @param sName the name of the font declaration + * @return aFontDeclaration
representing the font
+ */
+ public FontDeclaration getFontDeclaration(String sName) {
+ return (FontDeclaration) font.getStyle(sName);
+ }
+
+ // Accessor methods for styles
+ public OfficeStyleFamily getTextStyles() { return text; }
+ public StyleWithProperties getTextStyle(String sName) {
+ return (StyleWithProperties) text.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getParStyles() { return par; }
+ public StyleWithProperties getParStyle(String sName) {
+ return (StyleWithProperties) par.getStyle(sName);
+ }
+ public StyleWithProperties getDefaultParStyle() {
+ return (StyleWithProperties) par.getDefaultStyle();
+ }
+
+ public OfficeStyleFamily getSectionStyles() { return section; }
+ public StyleWithProperties getSectionStyle(String sName) {
+ return (StyleWithProperties) section.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getTableStyles() { return table; }
+ public StyleWithProperties getTableStyle(String sName) {
+ return (StyleWithProperties) table.getStyle(sName);
+ }
+ public OfficeStyleFamily getColumnStyles() { return column; }
+ public StyleWithProperties getColumnStyle(String sName) {
+ return (StyleWithProperties) column.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getRowStyles() { return row; }
+ public StyleWithProperties getRowStyle(String sName) {
+ return (StyleWithProperties) row.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getCellStyles() { return cell; }
+ public StyleWithProperties getCellStyle(String sName) {
+ return (StyleWithProperties) cell.getStyle(sName);
+ }
+ public StyleWithProperties getDefaultCellStyle() {
+ return (StyleWithProperties) cell.getDefaultStyle();
+ }
+
+ public OfficeStyleFamily getFrameStyles() { return frame; }
+ public StyleWithProperties getFrameStyle(String sName) {
+ return (StyleWithProperties) frame.getStyle(sName);
+ }
+ public StyleWithProperties getDefaultFrameStyle() {
+ return (StyleWithProperties) frame.getDefaultStyle();
+ }
+
+ public OfficeStyleFamily getPresentationStyles() { return presentation; }
+ public StyleWithProperties getPresentationStyle(String sName) {
+ return (StyleWithProperties) presentation.getStyle(sName);
+ }
+ public StyleWithProperties getDefaultPresentationStyle() {
+ return (StyleWithProperties) presentation.getDefaultStyle();
+ }
+
+ public OfficeStyleFamily getDrawingPageStyles() { return drawingPage; }
+ public StyleWithProperties getDrawingPageStyle(String sName) {
+ return (StyleWithProperties) drawingPage.getStyle(sName);
+ }
+ public StyleWithProperties getDefaultDrawingPageStyle() {
+ return (StyleWithProperties) drawingPage.getDefaultStyle();
+ }
+
+ public OfficeStyleFamily getListStyles() { return list; }
+ public ListStyle getListStyle(String sName) {
+ return (ListStyle) list.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getPageLayouts() { return pageLayout; }
+ public PageLayout getPageLayout(String sName) {
+ return (PageLayout) pageLayout.getStyle(sName);
+ }
+
+ public OfficeStyleFamily getMasterPages() { return masterPage; }
+ public MasterPage getMasterPage(String sName) {
+ return (MasterPage) masterPage.getStyle(sName);
+ }
+
+ public ListStyle getOutlineStyle() { return outline; }
+
+ public PropertySet getFootnotesConfiguration() { return footnotes; }
+
+ public PropertySet getEndnotesConfiguration() { return endnotes; }
+
+ /** Returns the paragraph style associated with headings of a specific
+ * level. Returns null
if no such style is known.
+ *
In principle, different styles can be used for each heading, in
+ * practice the same (soft) style is used for all headings of a specific
+ * level.
+ * @param nLevel the level of the heading
+ * @return a StyleWithProperties
object representing the style
+ */
+ public StyleWithProperties getHeadingStyle(int nLevel) {
+ return 1<=nLevel && nLevel<=10 ? heading[nLevel] : null;
+ }
+
+ /**
Returns the first master page used in the document. If no master
+ * page is used explicitly, the first master page found in the styles is
+ * returned. Returns null if no master pages exists.
+ * @return a MasterPage
object representing the master page
+ */
+ public MasterPage getFirstMasterPage() { return firstMasterPage; }
+
+ /** Return the iso language used in most paragaph styles (in a well-structured
+ * document this will be the default language)
+ * TODO: Base on content rather than style
+ * @return the iso language
+ */
+ public String getMajorityLanguage() {
+ Hashtable langs = new Hashtable();
+
+ // Read the default language from the default paragraph style
+ String sDefaultLang = null;
+ StyleWithProperties style = getDefaultParStyle();
+ if (style!=null) {
+ sDefaultLang = style.getProperty(XMLString.FO_LANGUAGE);
+ }
+
+ // Collect languages from paragraph styles
+ Enumeration enumeration = getParStyles().getStylesEnumeration();
+ while (enumeration.hasMoreElements()) {
+ style = (StyleWithProperties) enumeration.nextElement();
+ String sLang = style.getProperty(XMLString.FO_LANGUAGE);
+ if (sLang==null) { sLang = sDefaultLang; }
+ if (sLang!=null) {
+ int nCount = 1;
+ if (langs.containsKey(sLang)) {
+ nCount = ((Integer) langs.get(sLang)).intValue()+1;
+ }
+ langs.put(sLang,new Integer(nCount));
+ }
+ }
+
+ // Find the most common language
+ int nMaxCount = 0;
+ String sMajorityLanguage = null;
+ enumeration = langs.keys();
+ while (enumeration.hasMoreElements()) {
+ String sLang = (String) enumeration.nextElement();
+ int nCount = ((Integer) langs.get(sLang)).intValue();
+ if (nCount>nMaxCount) {
+ nMaxCount = nCount;
+ sMajorityLanguage = sLang;
+ }
+ }
+ return sMajorityLanguage;
+ }
+
+
+ /**
Returns a reader for a specific toc
+ * @param onode the text:table-of-content-node
+ * @return the reader, or null
+ */
+ public TocReader getTocReader(Element onode) {
+ if (indexes.containsKey(onode)) { return (TocReader) indexes.get(onode); }
+ else { return null; }
+ }
+
+ /**
Is this style used in some toc as an index source style?
+ * @param sStyleName the name of the style + * @return true if this is an index source style + */ + public boolean isIndexSourceStyle(String sStyleName) { + return indexSourceStyles.contains(sStyleName); + } + + /**Does this sequence name belong to a lof?
+ * @param sName the name of the sequence + * @return true if it belongs to an index + */ + public boolean isFigureSequenceName(String sName) { + return figureSequenceNames.contains(sName); + } + + /**Does this sequence name belong to a lot?
+ * @param sName the name of the sequence + * @return true if it belongs to an index + */ + public boolean isTableSequenceName(String sName) { + return tableSequenceNames.contains(sName); + } + + /**Add a sequence name for table captions.
+ *OpenDocument has a very weak notion of table captions: A caption is a + * paragraph containing a text:sequence element. Moreover, the only source + * to identify which sequence number to use is the list(s) of tables. + * If there's no list of tables, captions cannot be identified. + * Thus this method lets the user add a sequence name to identify the + * table captions. + * @param sName the name to add + */ + public void addTableSequenceName(String sName) { + tableSequenceNames.add(sName); + } + + /**
Add a sequence name for figure captions.
+ *OpenDocument has a very weak notion of figure captions: A caption is a + * paragraph containing a text:sequence element. Moreover, the only source + * to identify which sequence number to use is the list(s) of figures. + * If there's no list of figures, captions cannot be identified. + * Thus this method lets the user add a sequence name to identify the + * figure captions. + * @param sName the name to add + */ + public void addFigureSequenceName(String sName) { + figureSequenceNames.add(sName); + } + /**
Get the sequence name associated with a paragraph
+ * @param par the paragraph to look up + * @return the sequence name or null + */ + public String getSequenceName(Element par) { + return sequenceNames.containsKey(par) ? (String) sequenceNames.get(par) : null; + } + + /**Get the sequence name associated with a reference name
+ * @param sRefName the reference name to use + * @return the sequence name or null + */ + public String getSequenceFromRef(String sRefName) { + return (String) seqrefNames.get(sRefName); + } + + + /**Is there a reference to this footnote id? + * @param sId the id of the footnote + * @return true if there is a reference + */ + public boolean hasFootnoteRefTo(String sId) { + return footnoteRef.contains(sId); + } + + /**
Is there a reference to this endnote? + * @param sId the id of the endnote + * @return true if there is a reference + */ + public boolean hasEndnoteRefTo(String sId) { + return endnoteRef.contains(sId); + } + + /** Is this reference mark contained in a heading? + * @param sName the name of the reference mark + * @return true if so + */ + public boolean referenceMarkInHeading(String sName) { + return referenceHeading.contains(sName); + } + + /** Is there a reference to this reference mark? + * @param sName the name of the reference mark + * @return true if there is a reference + */ + public boolean hasReferenceRefTo(String sName) { + return referenceRef.contains(sName); + } + + /** Is this bookmark contained in a heading? + * @param sName the name of the bookmark + * @return true if so + */ + public boolean bookmarkInHeading(String sName) { + return bookmarkHeading.contains(sName); + } + + /**
Is there a reference to this bookmark? + * @param sName the name of the bookmark + * @return true if there is a reference + */ + public boolean hasBookmarkRefTo(String sName) { + return bookmarkRef.contains(sName); + } + + /**
Is there a reference to this sequence field? + * @param sId the id of the sequence field + * @return true if there is a reference + */ + public boolean hasSequenceRefTo(String sId) { + return sequenceRef.contains(sId); + } + + /**
Is there a link to this sequence anchor name? + * @param sName the name of the anchor + * @return true if there is a link + */ + public boolean hasLinkTo(String sName) { + return links.contains(sName); + } + + /**
Is this an OASIS OpenDocument or an OOo 1.0 document? + * @return true if it's an OASIS OpenDocument + */ + public boolean isOpenDocument() { return bOpenDocument; } + + /**
Is this an text document? + * @return true if it's a text document + */ + public boolean isText() { return bText; } + + /**
Is this a spreadsheet document? + * @return true if it's a spreadsheet document + */ + public boolean isSpreadsheet() { return bSpreadsheet; } + + /**
Is this a presentation document? + * @return true if it's a presentation document + */ + public boolean isPresentation() { return bPresentation; } + + /**
Get the content element
+ *In the old file format this means the office:body
element
+ *
In the OpenDocument format this means a office:text
,
+ * office:spreadsheet
or office:presentation
+ * element.
Element
+ */
+ public Element getContent() {
+ return content;
+ }
+
+ /** Get the forms belonging to this document.
+ * @return aFormsReader
representing the forms
+ */
+ public FormsReader getForms() { return forms; }
+
+ /** Read a table from a table:table node
+ * @param node the table:table Element node + * @return aTableReader
object representing the table
+ */
+ public TableReader getTableReader(Element node) {
+ return new TableReader(this,node);
+ }
+
+ /** Constructor; read a document */
+ public OfficeReader(OfficeDocument oooDoc, boolean bAllParagraphsAreSoft) {
+ this.oooDoc = oooDoc;
+ loadStylesFromDOM(oooDoc.getStyleDOM(),oooDoc.getContentDOM(),bAllParagraphsAreSoft);
+ loadContentFromDOM(oooDoc.getContentDOM());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Helpers
+
+ /*private void collectMasterPage(StyleWithProperties style) {
+ if (style==null || firstMasterPage!=null) { return; }
+ String s = style.getMasterPageName();
+ if (s!=null && s.length()>0) {
+ firstMasterPage = getMasterPage(s);
+ }
+ }*/
+
+ private void loadStylesFromDOM(Node node, boolean bAllParagraphsAreSoft) {
+ // node should be office:master-styles, office:styles or office:automatic-styles
+ boolean bAutomatic = XMLString.OFFICE_AUTOMATIC_STYLES.equals(node.getNodeName());
+ if (node.hasChildNodes()){
+ NodeList nl = node.getChildNodes();
+ int nLen = nl.getLength();
+ for (int i = 0; i < nLen; i++ ) {
+ Node child=nl.item(i);
+ if (child.getNodeType()==Node.ELEMENT_NODE){
+ if (child.getNodeName().equals(XMLString.STYLE_STYLE)){
+ String sFamily = Misc.getAttribute(child,XMLString.STYLE_FAMILY);
+ if ("text".equals(sFamily)){
+ text.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("paragraph".equals(sFamily)){
+ par.loadStyleFromDOM(child,bAutomatic && !bAllParagraphsAreSoft);
+ }
+ else if ("section".equals(sFamily)){
+ section.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("table".equals(sFamily)){
+ table.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("table-column".equals(sFamily)){
+ column.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("table-row".equals(sFamily)){
+ row.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("table-cell".equals(sFamily)){
+ cell.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("graphics".equals(sFamily)){
+ frame.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("graphic".equals(sFamily)){ // oasis
+ frame.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("presentation".equals(sFamily)){
+ presentation.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if ("drawing-page".equals(sFamily)){
+ // Bug in OOo 1.x: The same name may be used for a real and an automatic style...
+ if (drawingPage.getStyle(Misc.getAttribute(child,XMLString.STYLE_NAME))==null) {
+ drawingPage.loadStyleFromDOM(child,bAutomatic);
+ }
+ }
+ }
+ else if (child.getNodeName().equals(XMLString.STYLE_PAGE_MASTER)) { // old
+ pageLayout.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if (child.getNodeName().equals(XMLString.STYLE_PAGE_LAYOUT)) { // oasis
+ pageLayout.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if (child.getNodeName().equals(XMLString.STYLE_MASTER_PAGE)) {
+ masterPage.loadStyleFromDOM(child,bAutomatic);
+ if (firstMasterPage==null) {
+ firstMasterPage = (MasterPage) masterPage.getStyle(Misc.getAttribute(child,XMLString.STYLE_NAME));
+ }
+ }
+ else if (child.getNodeName().equals(XMLString.TEXT_LIST_STYLE)) {
+ list.loadStyleFromDOM(child,bAutomatic);
+ }
+ else if (child.getNodeName().equals(XMLString.TEXT_OUTLINE_STYLE)) {
+ outline.loadStyleFromDOM(child);
+ }
+ else if (child.getNodeName().equals(XMLString.STYLE_DEFAULT_STYLE)){
+ String sFamily = Misc.getAttribute(child,XMLString.STYLE_FAMILY);
+ if ("paragraph".equals(sFamily)) {
+ StyleWithProperties defaultPar = new StyleWithProperties();
+ defaultPar.loadStyleFromDOM(child);
+ par.setDefaultStyle(defaultPar);
+ }
+ else if ("graphics".equals(sFamily) || "graphic".equals(sFamily)) { // oasis: no s
+ StyleWithProperties defaultFrame = new StyleWithProperties();
+ defaultFrame.loadStyleFromDOM(child);
+ frame.setDefaultStyle(defaultFrame);
+ }
+ else if ("table-cell".equals(sFamily)) {
+ StyleWithProperties defaultCell = new StyleWithProperties();
+ defaultCell.loadStyleFromDOM(child);
+ cell.setDefaultStyle(defaultCell);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void loadStylesFromDOM(Document stylesDOM, Document contentDOM, boolean bAllParagraphsAreSoft){
+ // Flat xml: stylesDOM will be null and contentDOM contain everything
+ // This is only the case for old versions of xmerge; newer versions
+ // creates DOM for styles, content, meta and settings.
+ NodeList list;
+
+ // font declarations: Try old format first
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.OFFICE_FONT_DECLS);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.OFFICE_FONT_DECLS);
+ }
+ // If that fails, try oasis format
+ if (list.getLength()==0) {
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.OFFICE_FONT_FACE_DECLS);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.OFFICE_FONT_FACE_DECLS);
+ }
+ }
+
+ if (list.getLength()!=0) {
+ Node node = list.item(0);
+ if (node.hasChildNodes()){
+ NodeList nl = node.getChildNodes();
+ int nLen = nl.getLength();
+ for (int i = 0; i < nLen; i++ ) {
+ Node child = nl.item(i);
+ if (child.getNodeType()==Node.ELEMENT_NODE){
+ if (child.getNodeName().equals(XMLString.STYLE_FONT_DECL)){
+ font.loadStyleFromDOM(child,false);
+ }
+ else if (child.getNodeName().equals(XMLString.STYLE_FONT_FACE)){
+ font.loadStyleFromDOM(child,false);
+ }
+ }
+ }
+ }
+ }
+
+ // soft formatting:
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.OFFICE_STYLES);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.OFFICE_STYLES);
+ }
+ if (list.getLength()!=0) {
+ loadStylesFromDOM(list.item(0),bAllParagraphsAreSoft);
+ }
+
+ // master styles:
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.OFFICE_MASTER_STYLES);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.OFFICE_MASTER_STYLES);
+ }
+ if (list.getLength()!=0) {
+ loadStylesFromDOM(list.item(0),bAllParagraphsAreSoft);
+ }
+
+ // hard formatting:
+ // Load from styles.xml first. Problem: There may be name clashes
+ // with automatic styles from content.xml
+ if (stylesDOM!=null) {
+ list = stylesDOM.getElementsByTagName(XMLString.OFFICE_AUTOMATIC_STYLES);
+ if (list.getLength()!=0) {
+ loadStylesFromDOM(list.item(0),bAllParagraphsAreSoft);
+ }
+ }
+ list = contentDOM.getElementsByTagName(XMLString.OFFICE_AUTOMATIC_STYLES);
+ if (list.getLength()!=0) {
+ loadStylesFromDOM(list.item(0),bAllParagraphsAreSoft);
+ }
+
+ // footnotes configuration:
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.TEXT_FOOTNOTES_CONFIGURATION);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.TEXT_FOOTNOTES_CONFIGURATION);
+ }
+ if (list.getLength()!=0) {
+ footnotes = new PropertySet();
+ footnotes.loadFromDOM(list.item(0));
+ }
+
+ // endnotes configuration:
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.TEXT_ENDNOTES_CONFIGURATION);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.TEXT_ENDNOTES_CONFIGURATION);
+ }
+ if (list.getLength()!=0) {
+ endnotes = new PropertySet();
+ endnotes.loadFromDOM(list.item(0));
+ }
+
+ // if it failed, try oasis format
+ if (footnotes==null || endnotes==null) {
+ if (stylesDOM==null) {
+ list = contentDOM.getElementsByTagName(XMLString.TEXT_NOTES_CONFIGURATION);
+ }
+ else {
+ list = stylesDOM.getElementsByTagName(XMLString.TEXT_NOTES_CONFIGURATION);
+ }
+ int nLen = list.getLength();
+ for (int i=0; iAbstract class representing a style in OOo
*/ +public abstract class OfficeStyle { + // These attributes are defined by OfficeStyleFamily upon collection of styles + protected String sName; + protected OfficeStyleFamily family; + protected boolean bAutomatic; + + private String sDisplayName; + private String sParentName; + private String sListStyleName; + private String sMasterPageName; + + public String getName() { return sName; } + + public OfficeStyleFamily getFamily() { return family; } + + public boolean isAutomatic() { return bAutomatic; } + + public String getDisplayName() { return sDisplayName; } + + public String getParentName() { return sParentName; } + + public String getListStyleName() { return sListStyleName; } + + public String getMasterPageName() { return sMasterPageName; } + + public void loadStyleFromDOM(Node node){ + sDisplayName = Misc.getAttribute(node,XMLString.STYLE_DISPLAY_NAME); + if (sDisplayName==null) { sDisplayName = sName; } + sParentName = Misc.getAttribute(node,XMLString.STYLE_PARENT_STYLE_NAME); + sListStyleName = Misc.getAttribute(node,XMLString.STYLE_LIST_STYLE_NAME); + sMasterPageName = Misc.getAttribute(node,XMLString.STYLE_MASTER_PAGE_NAME); + } + +} \ No newline at end of file diff --git a/source/java/writer2latex/office/OfficeStyleFamily.java b/source/java/writer2latex/office/OfficeStyleFamily.java new file mode 100644 index 0000000..36426e3 --- /dev/null +++ b/source/java/writer2latex/office/OfficeStyleFamily.java @@ -0,0 +1,137 @@ +/************************************************************************ + * + * OfficeStyleFamily.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-23) + * + */ + +package writer2latex.office; + +import org.w3c.dom.Node; +import java.util.Hashtable; +import java.util.Enumeration; +import writer2latex.util.Misc; + +/** Container class representing a style family in OOo */ +public class OfficeStyleFamily { + private Hashtable styles = new Hashtable(); + private Class styleClass; + + private Hashtable displayNames = new Hashtable(); + + private OfficeStyle defaultStyle = null; + + /** Create a new OfficeStyleFamily based on a class + * @param styleClass the subclass of OfficeStyle used to represent styles + * in this family + */ + public OfficeStyleFamily(Class styleClass) { + this.styleClass = styleClass; + } + + /** Define the default style for this family, ie. an unnamed style providing + * defaults for some style properties. This style cannot be found using + * getStyle or getStyleByDisplayName. + * @param style the new default style + */ + public void setDefaultStyle(OfficeStyle style) { + defaultStyle = style; + } + + /** Get the default style for this family + * @return the default style, or null if none is defined + */ + public OfficeStyle getDefaultStyle() { + return defaultStyle; + } + + /** Get a style by name + * @param sName the name of the style + * @return the style, or null if such a style does not exist + */ + public OfficeStyle getStyle(String sName) { + if (sName==null) { return null; } + else { return (OfficeStyle) styles.get(sName); } + } + + /** Get a style by display name. Automatic styles does not have a display + * name, so only common styles can be retrieved with this method + * @param sDisplayName the display name of the style + * @return the style, or null if such a style does not exist + */ + public OfficeStyle getStyleByDisplayName(String sDisplayName) { + if (sDisplayName==null) { return null; } + else { return getStyle((String) displayNames.get(sDisplayName)); } + } + + /** Get the display name for the style with the specified name. + * If this is an automatic style, the parent style is used + * @param sName the style name + * @return the display name, or null if the style does not exist + */ + public String getDisplayName(String sName) { + OfficeStyle style = getStyle(sName); + if (style==null) { return null; } + if (style.isAutomatic()) { + style = getStyle(style.getParentName()); + if (style==null) { return null; } + } + return style.getDisplayName(); + } + + /** Get all named styles in the family (ie. excluding the default style) + * @return an enumeration of all styles represented by OfficeStyle objects + */ + public Enumeration getStylesEnumeration(){ + return styles.elements(); + } + + /** Load a style from a DOM representation + * @param node the style:... node representing the style + * @param bAutomatic if true, the style is an automatic style + */ + public void loadStyleFromDOM(Node node, boolean bAutomatic) { + String sName = Misc.getAttribute(node,XMLString.STYLE_NAME); + if (sName!=null) { + try { + OfficeStyle style = (OfficeStyle) styleClass.newInstance(); + style.sName=sName; + style.family=this; + style.bAutomatic=bAutomatic; + style.loadStyleFromDOM(node); + styles.put(sName,style); + if (!bAutomatic) { + // Create backlink from display name to name + displayNames.put(style.getDisplayName(),sName); + } + } + catch (InstantiationException e) { + // Will not happen if a proper class is passed in the constructor + } + catch (IllegalAccessException e) { + // Should also not happen + } + } + } + + +} \ No newline at end of file diff --git a/source/java/writer2latex/office/Package.html b/source/java/writer2latex/office/Package.html new file mode 100644 index 0000000..a425c9c --- /dev/null +++ b/source/java/writer2latex/office/Package.html @@ -0,0 +1,13 @@ + + + + +A collection of classes that reads ODF files.
+In general the DOM tree is used directly, but these classes provides a more +convenient interface to specific parts of the document.
+ + diff --git a/source/java/writer2latex/office/PageLayout.java b/source/java/writer2latex/office/PageLayout.java new file mode 100644 index 0000000..6226a56 --- /dev/null +++ b/source/java/writer2latex/office/PageLayout.java @@ -0,0 +1,91 @@ +/************************************************************************ + * + * PageLayout.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-03-17) + * + */ + +package writer2latex.office; + +import org.w3c.dom.Node; +import writer2latex.util.Misc; + +/**Class representing a page master in OOo Writer. This is represented + * like other styles + a separate style for header and footer
+ */ +public class PageLayout extends StyleWithProperties { + private String sPageUsage = null; + + private boolean bHasHeaderStyle = false; + private PropertySet headerStyle = new PropertySet(); + + private boolean bHasFooterStyle = false; + private PropertySet footerStyle = new PropertySet(); + + + public String getPageUsage() { + return sPageUsage; + } + + public boolean hasHeaderStyle() { return bHasHeaderStyle; } + + public String getHeaderProperty(String sPropName) { + return headerStyle.getProperty(sPropName); + } + + public boolean hasFooterStyle() { return bHasFooterStyle; } + + public String getFooterProperty(String sPropName) { + return footerStyle.getProperty(sPropName); + } + + public void loadStyleFromDOM(Node node) { + super.loadStyleFromDOM(node); + sPageUsage = Misc.getAttribute(node,XMLString.STYLE_PAGE_USAGE); + + Node hsNode = Misc.getChildByTagName(node,XMLString.STYLE_HEADER_STYLE); + if (hsNode!=null) { + Node hsProperties = Misc.getChildByTagName(hsNode,XMLString.STYLE_PROPERTIES); + if (hsProperties==null) { // oasis: + hsProperties = Misc.getChildByTagName(hsNode,XMLString.STYLE_HEADER_FOOTER_PROPERTIES); + } + if (hsProperties!=null) { + bHasHeaderStyle = true; + headerStyle.loadFromDOM(hsProperties); + } + } + + Node fsNode = Misc.getChildByTagName(node,XMLString.STYLE_FOOTER_STYLE); + if (fsNode!=null) { + Node fsProperties = Misc.getChildByTagName(fsNode,XMLString.STYLE_PROPERTIES); + if (fsProperties==null) { // oasis: + fsProperties = Misc.getChildByTagName(fsNode,XMLString.STYLE_HEADER_FOOTER_PROPERTIES); + } + if (fsProperties!=null) { + bHasFooterStyle = true; + footerStyle.loadFromDOM(fsProperties); + } + } + + } + +} \ No newline at end of file diff --git a/source/java/writer2latex/office/PropertySet.java b/source/java/writer2latex/office/PropertySet.java new file mode 100644 index 0000000..0c67af0 --- /dev/null +++ b/source/java/writer2latex/office/PropertySet.java @@ -0,0 +1,98 @@ +/************************************************************************ + * + * PropertySet.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-03-17) + * + */ + +package writer2latex.office; + +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import java.util.Enumeration; +import java.util.Hashtable; + +/**Class representing a set of style properties in OOo (actually this + is simply the set of attributes of an element).
+ */ +public class PropertySet { + private Hashtable properties = new Hashtable(); + private String sName; + + public PropertySet() { + properties = new Hashtable(); + sName=""; + } + + public String getProperty(String sPropName) { + if (sPropName!=null) { + String sValue = (String) properties.get(sPropName); + if (sValue!=null && sValue.endsWith("inch")) { + // Cut of inch to in + return sValue.substring(0,sValue.length()-2); + } + else { + return sValue; + } + } + else { + return null; + } + } + + public String getName() { return sName; } + + public void loadFromDOM(Node node) { + sName = node.getNodeName(); + // read the attributes of the node, if any + if (node!=null) { + NamedNodeMap attrNodes = node.getAttributes(); + if (attrNodes!=null) { + int nLen = attrNodes.getLength(); + for (int i=0; iTableView
can be derived from a table range,
+ * providing read access to the range.
+ */
+public class TableRange {
+ private TableReader reader;
+
+ private int nFirstRow;
+ private int nLastRow;
+ private int nFirstCol;
+ private int nLastCol;
+ private boolean bIncludeHidden;
+ private boolean bIncludeFiltered;
+
+ public TableRange(TableReader reader) {
+ this.reader = reader;
+
+ // The initial view is the complete table
+ nFirstRow = 0;
+ nLastRow = reader.getRowCount()-1;
+ nFirstCol = 0;
+ nLastCol = reader.getColCount()-1;
+ bIncludeHidden = true;
+ bIncludeFiltered = true;
+ }
+
+ public void setFirstRow(int nRow) {
+ // Adjust to a valid value (in 0..nLastRow)
+ if (nRow<0) { nFirstRow = 0; }
+ else if (nRow>nLastRow) { nFirstRow = nLastRow; }
+ else { nFirstRow = nRow; }
+ }
+
+ public int getFirstRow() {
+ return nFirstRow;
+ }
+
+ public void setLastRow(int nRow) {
+ // Adjust to a valid value (in nFirstRow..(nRowCount-1))
+ if (nRowThis class reads a table from a table:table or table:sub-table element + * and presents it as an n by m grid. In addition it gives access to the + * absolute and relative widths of tables, columns and cells.
+ */ +public class TableReader { + //private OfficeReader ofr; + private Element tableNode; + private LinkedList cols = new LinkedList(); + private LinkedList rows = new LinkedList(); + private LinkedList cells = new LinkedList(); + private int nMaxCols = 1; // real number of columns (count to last non-empty) + private int nMaxRows = 1; // real number of rows (count to last non-empty) + private String[] sColWidth; + private String[] sRelColWidth; + private String sTableWidth; + private String sRelTableWidth; + private Vector printRanges; + + /** + *The constructor reads a table from a table:table or table:sub-table + * node.
+ * @param ofr the OfficeReader object to get style information from + * @param tableNode the table node + */ + public TableReader(OfficeReader ofr, Element tableNode) { + //this.ofr = ofr; + this.tableNode = tableNode; + if (!tableNode.hasChildNodes()) { return; } // empty table! + NodeList nl = tableNode.getChildNodes(); + int nLen = nl.getLength(); + for (int i = 0; i < nLen; i++) { + Node child = nl.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + String sName = child.getNodeName(); + if (sName.equals(XMLString.TABLE_TABLE_COLUMN)) { + readTableColumn(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_COLUMNS)) { + readTableColumns(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_COLUMN_GROUP)) { + readTableColumnGroup(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_HEADER_COLUMNS)) { + readTableHeaderColumns(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_ROW)) { + readTableRow(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_ROWS)) { + readTableRows(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_ROW_GROUP)) { + readTableRowGroup(child,false,false); + } + else if (sName.equals(XMLString.TABLE_TABLE_HEADER_ROWS)) { + readTableHeaderRows(child,false,false); + } + } + } + + // Read table width from style + StyleWithProperties tableStyle = ofr.getTableStyle(getTableStyleName()); + if (tableStyle!=null) { + sTableWidth = tableStyle.getProperty(XMLString.STYLE_WIDTH); + sRelTableWidth = tableStyle.getProperty(XMLString.STYLE_REL_WIDTH); + } + + // Determine column widths + int nCols = cols.size(); + sColWidth = new String[nCols]; + sRelColWidth = new String[nCols]; + int[] nRelColWidth = new int[nCols]; + boolean bHasRelWidth=true; // set to false if some columns does not have a relative width set + int nColSum = 0; + for (int nCol=0; nColThe class reads a text:table-of-content
element.
Initialize the TocReader with a table of content node.
+ * @param onode a text:table-of-content
+ */
+ public TocReader(Element onode) {
+ sName = Misc.getAttribute(onode,XMLString.TEXT_NAME);
+ sStyleName = Misc.getAttribute(onode,XMLString.TEXT_STYLE_NAME);
+
+ Element tocSource = Misc.getChildByTagName(onode,XMLString.TEXT_TABLE_OF_CONTENT_SOURCE);
+ //Element indexBody = Misc.getChildByTagName(onode,XMLString.TEXT_INDEX_BODY);
+
+ if (tocSource!=null) {
+ nOutlineLevel = Misc.getPosInteger(tocSource.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
+ bUseOutlineLevel = !"false".equals(tocSource.getAttribute(XMLString.TEXT_USE_OUTLINE_LEVEL));
+ bUseIndexSourceStyles = "true".equals(tocSource.getAttribute(XMLString.TEXT_USE_INDEX_SOURCE_STYLES));
+ bUseIndexMarks = !"false".equals(tocSource.getAttribute(XMLString.TEXT_USE_INDEX_MARKS));
+ bIsByChapter = "chapter".equals(tocSource.getAttribute(XMLString.TEXT_INDEX_SCOPE));
+
+ // traverse the source to collect templates
+ Node child = tocSource.getFirstChild();
+ while (child!=null) {
+ if (child.getNodeType()==Node.ELEMENT_NODE) {
+ Element elm = (Element) child;
+ if (XMLString.TEXT_INDEX_TITLE_TEMPLATE.equals(elm.getTagName())) {
+ indexTitleTemplate = elm;
+ }
+ if (XMLString.TEXT_TABLE_OF_CONTENT_ENTRY_TEMPLATE.equals(elm.getTagName())) {
+ int nLevel = Misc.getPosInteger(elm.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
+ if (1<=nLevel && nLevel<=10) { tocEntryTemplate[nLevel] = elm; }
+ }
+ if (XMLString.TEXT_INDEX_SOURCE_STYLES.equals(elm.getTagName())) {
+ int nLevel = Misc.getPosInteger(elm.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
+ if (1<=nLevel && nLevel<=10) {
+ // traverse to collect index source styles for this level
+ Node child1 = elm.getFirstChild();
+ while (child1!=null) {
+ if (child1.getNodeType()==Node.ELEMENT_NODE) {
+ Element elm1 = (Element) child1;
+ if (XMLString.TEXT_INDEX_SOURCE_STYLE.equals(elm1.getTagName())) {
+ String sIndexSourceStyle = Misc.getAttribute(elm1,XMLString.TEXT_STYLE_NAME);
+ if (sIndexSourceStyle!=null) {
+ indexSourceStyles.put(sIndexSourceStyle,new Integer(nLevel));
+ }
+ }
+ }
+ child1 = child1.getNextSibling();
+ }
+ }
+ }
+ }
+ child = child.getNextSibling();
+ }
+ }
+ }
+
+ /**
Get the (section) name for this toc
+ * @return the name of the toc + */ + public String getName() { return sName; } + + /**Get the (section) style name for this toc
+ * @return name of the section style to use for this toc + */ + public String getStyleName() { return sStyleName; } + + /**Get max outline level for this toc
+ * @return max outline level + */ + public int getOutlineLevel() { return nOutlineLevel; } + + /**Do we use outline (headings) in this toc?
+ * @return true if headings should be used + */ + public boolean useOutlineLevel() { return bUseOutlineLevel; } + + /**Do we use additional styles in this toc?
+ * @return true if additional styles should be used + */ + public boolean useIndexSourceStyles() { return bUseIndexSourceStyles; } + + /**Do we use toc marks in this toc?
+ * @return true if toc marks should be used + */ + public boolean useIndexMarks() { return bUseIndexMarks; } + + /**Is this toc by chapter?
+ * @return true if the scope is a chapter only + */ + public boolean isByChapter() { return bIsByChapter; } + + /**Get the index title template for this toc
+ * @return thetext:index-title-template
element, or null
+ */
+ public Element getIndexTitleTemplate() { return indexTitleTemplate; }
+
+ /** Get the entry template for this toc at a specific level
+ * @param nLevel the outline level + * @return thetext:table-of-content-entry-template
element, or null
+ */
+ public Element getTocEntryTemplate(int nLevel) {
+ if (1<=nLevel && nLevel<=10) { return tocEntryTemplate[nLevel]; }
+ else { return null; }
+ }
+
+ /** Get a set view of all index source styles
+ * @return a set of all index source style names + */ + public Set getIndexSourceStyles() { return indexSourceStyles.keySet(); } + + /**Get the level associated with a specific index source style
+ * @param sStyleName the style name of the index source style + * @return the level or -1 if the style is not used in this toc + */ + public int getIndexSourceStyleLevel(String sStyleName) { + if (indexSourceStyles.containsKey(sStyleName)) { + return ((Integer) indexSourceStyles.get(sStyleName)).intValue(); + } + else { + return -1; + } + } + + /**Return the generated content of this toc, if available
+ * @return thetext:index-body
element
+ */
+ public Element getIndexBody() { return indexBody; }
+
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/office/XMLString.java b/source/java/writer2latex/office/XMLString.java
new file mode 100644
index 0000000..6ab3167
--- /dev/null
+++ b/source/java/writer2latex/office/XMLString.java
@@ -0,0 +1,447 @@
+/************************************************************************
+ *
+ * XMLString.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-10)
+ *
+ */
+
+package writer2latex.office;
+
+/* XML strings (tags and attributes) in the OOo XML namespaces
+ * typosafe but not typesafe :-)
+ */
+
+public class XMLString {
+ // draw namespace - elements
+ public static final String DRAW_="draw:";
+ public static final String DRAW_PAGE="draw:page";
+ public static final String DRAW_A="draw:a";
+ public static final String DRAW_FRAME="draw:frame"; // oasis
+ public static final String DRAW_IMAGE="draw:image";
+ public static final String DRAW_OBJECT="draw:object";
+ public static final String DRAW_OBJECT_OLE="draw:object-ole";
+ public static final String DRAW_TEXT_BOX="draw:text-box";
+ public static final String DRAW_G="draw:g";
+ public static final String DRAW_CONTROL="draw:control";
+ // draw namespace - attributes
+ public static final String DRAW_NAME="draw:name";
+ public static final String DRAW_STYLE_NAME="draw:style-name";
+ public static final String DRAW_TEXT_STYLE_NAME="draw:text-style-name";
+ public static final String DRAW_MASTER_PAGE_NAME="draw:master-page-name";
+ public static final String DRAW_FILL_COLOR="draw:fill-color";
+
+ // dc namespace - elements
+ public static final String DC_CREATOR="dc:creator";
+ public static final String DC_DATE="dc:date";
+ public static final String DC_DESCRIPTION="dc:description";
+ public static final String DC_LANGUAGE="dc:language";
+ public static final String DC_SUBJECT="dc:subject";
+ public static final String DC_TITLE="dc:title";
+
+ // meta namespace - elements
+ public static final String META_INITIAL_CREATOR="meta:initial-creator";
+ public static final String META_KEYWORDS="meta:keywords";
+ public static final String META_KEYWORD="meta:keyword";
+
+ // manifest namespace
+ public static final String MANIFEST_FILE_ENTRY="manifest:file-entry";
+ public static final String MANIFEST_MEDIA_TYPE="manifest:media-type";
+ public static final String MANIFEST_FULL_PATH="manifest:full-path";
+
+ // office namespace - elements
+ public static final String OFFICE_DOCUMENT_CONTENT="office:document-content";
+ public static final String OFFICE_MASTER_STYLES="office:master-styles";
+ public static final String OFFICE_STYLES="office:styles";
+ public static final String OFFICE_AUTOMATIC_STYLES="office:automatic-styles";
+ public static final String OFFICE_FONT_DECLS="office:font-decls";
+ public static final String OFFICE_FONT_FACE_DECLS="office:font-face-decls"; // oasis
+ public static final String OFFICE_BODY="office:body";
+ public static final String OFFICE_TEXT="office:text"; // oasis
+ public static final String OFFICE_SPREADSHEET="office:spreadsheet"; // oasis
+ public static final String OFFICE_PRESENTATION="office:presentation"; // oasis
+ public static final String OFFICE_FORMS="office:forms";
+ public static final String OFFICE_ANNOTATION="office:annotation";
+ public static final String OFFICE_BINARY_DATA="office:binary-data";
+ public static final String OFFICE_META="office:meta";
+ // office namespace - attributes
+ public static final String OFFICE_TARGET_FRAME_NAME="office:target-frame-name";
+ public static final String OFFICE_NAME="office:name";
+ public static final String OFFICE_VALUE_TYPE="office:value-type"; // oasis
+
+ // form namespace - elements
+ public static final String FORM_FORM="form:form";
+ public static final String FORM_CONTROL="form:control";
+ public static final String FORM_TEXT="form:text";
+ public static final String FORM_PASSWORD="form:password";
+ public static final String FORM_FILE="form:file";
+ public static final String FORM_IMAGE="form:image";
+ public static final String FORM_HIDDEN="form:hidden";
+ public static final String FORM_CHECKBOX="form:checkbox";
+ public static final String FORM_RADIO="form:radio";
+ public static final String FORM_BUTTON="form:button";
+ public static final String FORM_FIXED_TEXT="form:fixed-text";
+ public static final String FORM_TEXTAREA="form:textarea";
+ public static final String FORM_LISTBOX="form:listbox";
+ public static final String FORM_COMBOBOX="form:combobox";
+ public static final String FORM_ITEM="form:item";
+ public static final String FORM_OPTION="form:option";
+ // form namespace - attributes
+ public static final String FORM_NAME="form:name";
+ public static final String FORM_ID="form:id";
+ public static final String FORM_METHOD="form:method";
+ public static final String FORM_TYPE="form:type";
+ public static final String FORM_BUTTON_TYPE="form:button-type";
+ public static final String FORM_DISABLED="form:disabled";
+ public static final String FORM_READONLY="form:readonly";
+ public static final String FORM_DEFAULT_VALUE="form:default-value";
+ public static final String FORM_VALUE="form:value";
+ public static final String FORM_TAB_INDEX="form:tab-index";
+ public static final String FORM_TITLE="form:title";
+ public static final String FORM_MAX_LENGTH="form:max-length";
+ public static final String FORM_MULTIPLE="form:multiple";
+ public static final String FORM_SELECTED="form:selected";
+ public static final String FORM_LABEL="form:label";
+ public static final String FORM_SIZE="form:size";
+
+ // presentation namespace - attributes
+ public static final String PRESENTATION_CLASS="presentation:class";
+ public static final String PRESENTATION_STYLE_NAME="presentation:style-name";
+
+ // style namespace - elements
+ public static final String STYLE_PAGE_MASTER="style:page-master";
+ public static final String STYLE_PAGE_LAYOUT="style:page-layout"; // oasis
+ public static final String STYLE_MASTER_PAGE="style:master-page";
+ public static final String STYLE_FONT_DECL="style:font-decl";
+ public static final String STYLE_FONT_FACE="style:font-face"; // oasis
+ public static final String STYLE_STYLE="style:style";
+ public static final String STYLE_DEFAULT_STYLE="style:default-style";
+ public static final String STYLE_PROPERTIES="style:properties";
+ public static final String STYLE_TEXT_PROPERTIES="style:text-properties"; // oasis
+ public static final String STYLE_PARAGRAPH_PROPERTIES="style:paragraph-properties"; // oasis
+ public static final String STYLE_SECTION_PROPERTIES="style:section-properties"; // oasis
+ public static final String STYLE_TABLE_PROPERTIES="style:table-properties"; // oasis
+ public static final String STYLE_TABLE_ROW_PROPERTIES="style:table-row-properties"; // oasis
+ public static final String STYLE_TABLE_COLUMN_PROPERTIES="style:table-column-properties"; // oasis
+ public static final String STYLE_TABLE_CELL_PROPERTIES="style:table-cell-properties"; // oasis
+ public static final String STYLE_GRAPHIC_PROPERTIES="style:graphic-properties"; // oasis
+ public static final String STYLE_PAGE_LAYOUT_PROPERTIES="style:page-layout-properties"; // oasis
+ public static final String STYLE_DRAWING_PAGE_PROPERTIES="style:drawing-page-properties"; // oasis
+ public static final String STYLE_HEADER_FOOTER_PROPERTIES="style:header-footer-properties"; // oasis
+ public static final String STYLE_BACKGROUND_IMAGE="style:background-image";
+ public static final String STYLE_COLUMNS="style:columns";
+ public static final String STYLE_HEADER="style:header";
+ public static final String STYLE_HEADER_LEFT="style:header-left";
+ public static final String STYLE_FOOTER="style:footer";
+ public static final String STYLE_FOOTER_LEFT="style:footer-left";
+ public static final String STYLE_FOOTNOTE_SEP="style:footnote-sep";
+ public static final String STYLE_HEADER_STYLE="style:header-style";
+ public static final String STYLE_FOOTER_STYLE="style:footer-style";
+ // style namespace - attributes
+ public static final String STYLE_NEXT_STYLE_NAME="style:next-style-name";
+ public static final String STYLE_DISPLAY_NAME="style:display-name";
+ public static final String STYLE_PAGE_MASTER_NAME="style:page-master-name";
+ public static final String STYLE_PAGE_LAYOUT_NAME="style:page-layout-name"; // oasis
+ public static final String STYLE_MASTER_PAGE_NAME="style:master-page-name";
+ public static final String STYLE_PAGE_USAGE="style:page-usage";
+ public static final String STYLE_PAGE_NUMBER="style:page-number";
+ public static final String STYLE_FONT_FAMILY_COMPLEX="style:font-family-complex";
+ public static final String STYLE_FONT_NAME="style:font-name";
+ public static final String STYLE_FONT_NAME_COMPLEX="style:font-name-complex";
+ public static final String STYLE_FONT_PITCH="style:font-pitch";
+ public static final String STYLE_FONT_FAMILY_GENERIC="style:font-family-generic";
+ public static final String STYLE_TEXT_BACKGROUND_COLOR="style:text-background-color";
+ public static final String STYLE_USE_WINDOW_FONT_COLOR="style:use-window-font-color";
+ public static final String STYLE_TEXT_CROSSING_OUT="style:text-crossing-out";
+ public static final String STYLE_TEXT_UNDERLINE="style:text-underline";
+ public static final String STYLE_TEXT_BLINKING="style:text-blinking";
+ public static final String STYLE_TEXT_LINE_THROUGH_STYLE="style:text-line-through-style"; // oasis
+ public static final String STYLE_TEXT_UNDERLINE_STYLE="style:text-underline-style"; // oasis
+ public static final String STYLE_AUTO_TEXT_INDENT="style:auto-text-indent";
+ public static final String STYLE_TEXT_ALIGN_SOURCE="style:text-align-source";
+ public static final String STYLE_NAME="style:name";
+ public static final String STYLE_PARENT_STYLE_NAME="style:parent-style-name";
+ public static final String STYLE_FAMILY="style:family";
+ public static final String STYLE_TEXT_POSITION="style:text-position";
+ public static final String STYLE_LIST_STYLE_NAME="style:list-style-name";
+ public static final String STYLE_LIST_LEVEL_PROPERTIES="style:list-level-properties";
+ public static final String STYLE_NUM_PREFIX="style:num-prefix";
+ public static final String STYLE_NUM_SUFFIX="style:num-suffix";
+ public static final String STYLE_NUM_FORMAT="style:num-format";
+ public static final String STYLE_VERTICAL_ALIGN="style:vertical-align";
+ public static final String STYLE_MAY_BREAK_BETWEEN_ROWS="style:may-break-between-rows";
+ public static final String STYLE_HORIZONTAL_POS="style:horizontal-pos";
+ public static final String STYLE_WRAP="style:wrap";
+ public static final String STYLE_COLUMN_WIDTH="style:column-width";
+ public static final String STYLE_REL_COLUMN_WIDTH="style:rel-column-width";
+ public static final String STYLE_ROW_HEIGHT="style:row-height";
+ public static final String STYLE_MIN_ROW_HEIGHT="style:min-row-height";
+ public static final String STYLE_FIRST_PAGE_NUMBER="style:first-page-number";
+ public static final String STYLE_DISTANCE_BEFORE_SEP="style:distance-before-sep";
+ public static final String STYLE_DISTANCE_AFTER_SEP="style:distance-after-sep";
+ public static final String STYLE_WIDTH="style:width";
+ public static final String STYLE_REL_WIDTH="style:rel-width";
+ public static final String STYLE_COLOR="style:color";
+ public static final String STYLE_WRITING_MODE="style:writing-mode";
+ public static final String STYLE_REPEAT="style:repeat";
+ public static final String STYLE_POSITION="style:position";
+ public static final String STYLE_ADJUSTMENT="style:adjustment";
+
+ // table namespace - elements
+ public static final String TABLE_="table:";
+ public static final String TABLE_TABLE="table:table";
+ public static final String TABLE_SUB_TABLE="table:sub-table";
+ public static final String TABLE_SHAPES="table:shapes";
+ public static final String TABLE_TABLE_COLUMN="table:table-column";
+ public static final String TABLE_TABLE_COLUMNS="table:table-columns";
+ public static final String TABLE_TABLE_COLUMN_GROUP="table:table-column-group";
+ public static final String TABLE_TABLE_HEADER_COLUMNS="table:table-header-columns";
+ public static final String TABLE_TABLE_ROW="table:table-row";
+ public static final String TABLE_TABLE_ROWS="table:table-rows";
+ public static final String TABLE_TABLE_ROW_GROUP="table:table-row-group";
+ public static final String TABLE_TABLE_HEADER_ROWS="table:table-header-rows";
+ public static final String TABLE_TABLE_CELL="table:table-cell";
+ public static final String TABLE_COVERED_TABLE_CELL="table:covered-table-cell";
+ // table namespace - attributes
+ public static final String TABLE_NAME="table:name";
+ public static final String TABLE_IS_SUB_TABLE="table:is-sub-table"; // oasis
+ public static final String TABLE_STYLE_NAME="table:style-name";
+ public static final String TABLE_VISIBILITY="table:visibility";
+ public static final String TABLE_DISPLAY="table:display";
+ public static final String TABLE_DEFAULT_CELL_STYLE_NAME="table:default-cell-style-name";
+ public static final String TABLE_VALUE_TYPE="table:value-type";
+ public static final String TABLE_NUMBER_COLUMNS_REPEATED="table:number-columns-repeated";
+ public static final String TABLE_NUMBER_ROWS_REPEATED="table:number-rows-repeated";
+ public static final String TABLE_NUMBER_ROWS_SPANNED="table:number-rows-spanned";
+ public static final String TABLE_NUMBER_COLUMNS_SPANNED="table:number-columns-spanned";
+ public static final String TABLE_ALIGN="table:align";
+ public static final String TABLE_PRINT="table:print";
+ public static final String TABLE_PRINT_RANGES="table:print-ranges";
+
+ // text namespace - elements (declarations)
+ public static final String TEXT_="text:";
+ public static final String TEXT_FOOTNOTES_CONFIGURATION="text:footnotes-configuration";
+ public static final String TEXT_ENDNOTES_CONFIGURATION="text:endnotes-configuration";
+ public static final String TEXT_NOTES_CONFIGURATION="text:notes-configuration"; // oasis
+ public static final String TEXT_SECTION_SOURCE="text:section-source";
+ public static final String TEXT_SEQUENCE_DECLS="text:sequence-decls";
+ public static final String TEXT_SEQUENCE_DECL="text:sequence-decl";
+ public static final String TEXT_OUTLINE_STYLE="text:outline-style";
+ public static final String TEXT_LIST_STYLE="text:list-style";
+ public static final String TEXT_LIST_LEVEL_STYLE_NUMBER="text:list-level-style-number";
+ public static final String TEXT_LIST_LEVEL_STYLE_BULLET="text:list-level-style-bullet";
+ public static final String TEXT_LIST_LEVEL_STYLE_IMAGE="text:list-level-style-image";
+ // text namespace - elements (block text)
+ public static final String TEXT_SECTION="text:section";
+ public static final String TEXT_P="text:p";
+ public static final String TEXT_H="text:h";
+ public static final String TEXT_LIST="text:list"; // oasis
+ public static final String TEXT_ORDERED_LIST="text:ordered-list";
+ public static final String TEXT_UNORDERED_LIST="text:unordered-list";
+ public static final String TEXT_LIST_ITEM="text:list-item";
+ public static final String TEXT_LIST_HEADER="text:list-header";
+ public static final String TEXT_ALPHABETICAL_INDEX="text:alphabetical-index";
+ public static final String TEXT_ALPHABETICAL_INDEX_SOURCE="text:alphabetical-index-source";
+ public static final String TEXT_ALPHABETICAL_INDEX_ENTRY_TEMPLATE="text:alphabetical-index-entry-template";
+ public static final String TEXT_TABLE_OF_CONTENT="text:table-of-content";
+ public static final String TEXT_TABLE_OF_CONTENT_SOURCE="text:table-of-content-source";
+ public static final String TEXT_TABLE_OF_CONTENT_ENTRY_TEMPLATE="text:table-of-content-entry-template";
+ public static final String TEXT_INDEX_SOURCE_STYLES="text:index-source-styles";
+ public static final String TEXT_INDEX_SOURCE_STYLE="text:index-source-style";
+ public static final String TEXT_ILLUSTRATION_INDEX="text:illustration-index";
+ public static final String TEXT_ILLUSTRATION_INDEX_SOURCE="text:illustration-index-source";
+ public static final String TEXT_ILLUSTRATION_INDEX_ENTRY_TEMPLATE="text:illustration-index-entry-template";
+ public static final String TEXT_TABLE_INDEX="text:table-index";
+ public static final String TEXT_TABLE_INDEX_SOURCE="text:table-index-source";
+ public static final String TEXT_TABLE_INDEX_ENTRY_TEMPLATE="text:table-index-entry-template";
+ public static final String TEXT_OBJECT_INDEX="text:object-index";
+ public static final String TEXT_USER_INDEX="text:user-index";
+ public static final String TEXT_BIBLIOGRAPHY="text:bibliography";
+ public static final String TEXT_INDEX_TITLE_TEMPLATE="text:index-title-template";
+ public static final String TEXT_INDEX_BODY="text:index-body";
+ public static final String TEXT_INDEX_TITLE="text:index-title";
+ public static final String TEXT_INDEX_SOURCE="text:index-source";
+ // text namespace - elements (inline text)
+ public static final String TEXT_SPAN="text:span";
+ public static final String TEXT_FOOTNOTE="text:footnote";
+ public static final String TEXT_ENDNOTE="text:endnote";
+ public static final String TEXT_NOTE="text:note"; // oasis
+ public static final String TEXT_FOOTNOTE_CITATION="text:footnote-citation";
+ public static final String TEXT_FOOTNOTE_BODY="text:footnote-body";
+ public static final String TEXT_ENDNOTE_CITATION="text:endnote-citation";
+ public static final String TEXT_ENDNOTE_BODY="text:endnote-body";
+ public static final String TEXT_NOTE_CITATION="text:note-citation"; // oasis
+ public static final String TEXT_NOTE_BODY="text:note-body"; // oasis
+ public static final String TEXT_S="text:s";
+ public static final String TEXT_TAB_STOP="text:tab-stop";
+ public static final String TEXT_TAB="text:tab"; // oasis
+ public static final String TEXT_A="text:a";
+ public static final String TEXT_LINE_BREAK="text:line-break";
+ public static final String TEXT_PAGE_NUMBER="text:page-number";
+ public static final String TEXT_PAGE_COUNT="text:page-count";
+ public static final String TEXT_CHAPTER="text:chapter";
+ public static final String TEXT_SEQUENCE="text:sequence";
+ public static final String TEXT_SEQUENCE_REF="text:sequence-ref";
+ public static final String TEXT_BIBLIOGRAPHY_MARK="text:bibliography-mark";
+ public static final String TEXT_ALPHABETICAL_INDEX_MARK="text:alphabetical-index-mark";
+ public static final String TEXT_ALPHABETICAL_INDEX_MARK_START="text:alphabetical-index-mark-start";
+ public static final String TEXT_ALPHABETICAL_INDEX_MARK_END="text:alphabetical-index-mark-end";
+ public static final String TEXT_TOC_MARK="text:toc-mark";
+ public static final String TEXT_TOC_MARK_START="text:toc-mark-start";
+ public static final String TEXT_TOC_MARK_END="text:toc-mark-end";
+ public static final String TEXT_REFERENCE_MARK="text:reference-mark";
+ public static final String TEXT_REFERENCE_MARK_START="text:reference-mark-start";
+ public static final String TEXT_REFERENCE_REF="text:reference-ref";
+ public static final String TEXT_BOOKMARK="text:bookmark";
+ public static final String TEXT_BOOKMARK_START="text:bookmark-start";
+ public static final String TEXT_BOOKMARK_REF="text:bookmark-ref";
+ public static final String TEXT_FOOTNOTE_REF="text:footnote-ref";
+ public static final String TEXT_ENDNOTE_REF="text:endnote-ref";
+ public static final String TEXT_NOTE_REF="text:note-ref"; // oasis
+ // text namespace - attributes
+ public static final String TEXT_USE_OUTLINE_LEVEL="text:use-outline-level";
+ public static final String TEXT_USE_INDEX_SOURCE_STYLES="text:use-index-source-styles";
+ public static final String TEXT_USE_INDEX_MARKS="text:use-index-marks";
+ public static final String TEXT_INDEX_SCOPE="text:index-scope";
+ public static final String TEXT_OUTLINE_LEVEL="text:outline-level";
+ public static final String TEXT_IS_LIST_HEADER="text:is-list-header";
+ public static final String TEXT_USE_CAPTION="text:use-caption";
+ public static final String TEXT_CAPTION_SEQUENCE_NAME="text:caption-sequence-name";
+ public static final String TEXT_STRING_VALUE="text:string-value";
+ public static final String TEXT_KEY1="text:key1";
+ public static final String TEXT_KEY2="text:key2";
+ public static final String TEXT_LEVEL="text:level";
+ public static final String TEXT_SPACE_BEFORE="text:space-before";
+ public static final String TEXT_MIN_LABEL_WIDTH="text:min-label-width";
+ public static final String TEXT_MIN_LABEL_DISTANCE="text:min-label-distance";
+ public static final String TEXT_STYLE_NAME="text:style-name";
+ public static final String TEXT_VISITED_STYLE_NAME="text:visited-style-name";
+ public static final String TEXT_DISPLAY_LEVELS="text:display-levels";
+ public static final String TEXT_CONTINUE_NUMBERING="text:continue-numbering";
+ public static final String TEXT_C="text:c";
+ public static final String TEXT_ID="text:id";
+ public static final String TEXT_LABEL="text:label";
+ public static final String TEXT_NAME="text:name";
+ public static final String TEXT_REFERENCE_FORMAT="text:reference-format";
+ public static final String TEXT_REF_NAME="text:ref-name";
+ public static final String TEXT_FORMULA="text:formula";
+ public static final String TEXT_NOTE_CLASS="text:note-class";
+ public static final String TEXT_CITATION_BODY_STYLE_NAME="text:citation-body-style-name";
+ public static final String TEXT_CITATION_STYLE_NAME="text:citation-style-name";
+ public static final String TEXT_DEFAULT_STYLE_NAME="text:default-style-name";
+ public static final String TEXT_START_VALUE="text:start-value";
+ public static final String TEXT_START_NUMBERING_AT="text:start-numbering-at";
+ public static final String TEXT_RESTART_NUMBERING="text:restart-numbering";
+ public static final String TEXT_ANCHOR_TYPE="text:anchor-type";
+ public static final String TEXT_BULLET_CHAR="text:bullet-char";
+ public static final String TEXT_DISPLAY="text:display";
+ public static final String TEXT_DISPLAY_OUTLINE_LEVEL="text:display-outline-level";
+ public static final String TEXT_SEPARATION_CHARACTER="text:separation-character";
+
+ public static final String TEXT_IDENTIFIER="text:identifier";
+ public static final String TEXT_BIBLIOGRAPHY_TYPE="text:bibliography-type";
+ public static final String TEXT_BIBILIOGRAPHIC_TYPE="text:bibiliographic-type"; // bug in OOo 1.0
+ public static final String TEXT_ADDRESS="text:address";
+ public static final String TEXT_ANNOTE="text:annote";
+ public static final String TEXT_AUTHOR="text:author";
+ public static final String TEXT_BOOKTITLE="text:booktitle";
+ //public static final String TEXT_CHAPTER="text:chapter";
+ public static final String TEXT_EDITION="text:edition";
+ public static final String TEXT_EDITOR="text:editor";
+ public static final String TEXT_HOWPUBLISHED="text:howpublished";
+ public static final String TEXT_INSTITUTION="text:institution";
+ public static final String TEXT_JOURNAL="text:journal";
+ public static final String TEXT_MONTH="text:month";
+ // public static final String TEXT_NOTE="text:note"; defined above as an element name
+ public static final String TEXT_NUMBER="text:number";
+ public static final String TEXT_ORGANIZATIONS="text:organizations";
+ public static final String TEXT_PAGES="text:pages";
+ public static final String TEXT_PUBLISHER="text:publisher";
+ public static final String TEXT_SCHOOL="text:school";
+ public static final String TEXT_SERIES="text:series";
+ public static final String TEXT_TITLE="text:title";
+ public static final String TEXT_REPORT_TYPE="text:report-type";
+ public static final String TEXT_VOLUME="text:volume";
+ public static final String TEXT_YEAR="text:year";
+ public static final String TEXT_URL="text:url";
+ public static final String TEXT_CUSTOM1="text:custom1";
+ public static final String TEXT_CUSTOM2="text:custom2";
+ public static final String TEXT_CUSTOM3="text:custom3";
+ public static final String TEXT_CUSTOM4="text:custom4";
+ public static final String TEXT_CUSTOM5="text:custom5";
+ public static final String TEXT_ISBN="text:isbn";
+
+ // fo namespace
+ public static final String FO_LANGUAGE="fo:language";
+ public static final String FO_COUNTRY="fo:country";
+ public static final String FO_TEXT_SHADOW="fo:text-shadow";
+ public static final String FO_COLOR="fo:color";
+ public static final String FO_BACKGROUND_COLOR="fo:background-color";
+ public static final String FO_TEXT_TRANSFORM="fo:text-transform";
+ public static final String FO_FONT_FAMILY="fo:font-family";
+ public static final String FO_FONT_SIZE="fo:font-size";
+ public static final String FO_FONT_WEIGHT="fo:font-weight";
+ public static final String FO_FONT_VARIANT="fo:font-variant";
+ public static final String FO_FONT_STYLE="fo:font-style";
+ public static final String FO_LETTER_SPACING="fo:letter-spacing";
+ public static final String FO_VERTICAL_ALIGN="fo:vertical-align";
+ public static final String FO_TEXT_ALIGN="fo:text-align";
+ public static final String FO_TEXT_ALIGN_LAST="fo:text-align-last";
+ public static final String FO_BREAK_BEFORE="fo:break-before";
+ public static final String FO_BREAK_AFTER="fo:break-after";
+ public static final String FO_MARGIN_LEFT="fo:margin-left";
+ public static final String FO_MARGIN_RIGHT="fo:margin-right";
+ public static final String FO_MARGIN_TOP="fo:margin-top";
+ public static final String FO_MARGIN_BOTTOM="fo:margin-bottom";
+ public static final String FO_PAGE_WIDTH="fo:page-width";
+ public static final String FO_PAGE_HEIGHT="fo:page-height";
+ public static final String FO_MIN_HEIGHT="fo:min-height";
+ public static final String FO_BORDER="fo:border";
+ public static final String FO_BORDER_LEFT="fo:border-left";
+ public static final String FO_BORDER_RIGHT="fo:border-right";
+ public static final String FO_BORDER_TOP="fo:border-top";
+ public static final String FO_BORDER_BOTTOM="fo:border-bottom";
+ public static final String FO_PADDING="fo:padding";
+ public static final String FO_PADDING_LEFT="fo:padding-left";
+ public static final String FO_PADDING_RIGHT="fo:padding-right";
+ public static final String FO_PADDING_TOP="fo:padding-top";
+ public static final String FO_PADDING_BOTTOM="fo:padding-bottom";
+ public static final String FO_LINE_HEIGHT="fo:line-height";
+ public static final String FO_TEXT_INDENT="fo:text-indent";
+ public static final String FO_WRAP_OPTION="fo:wrap-option";
+ public static final String FO_COLUMN_COUNT="fo:column-count";
+
+ // svg namespace
+ public static final String SVG_DESC="svg:desc";
+
+ public static final String SVG_FONT_FAMILY="svg:font-family"; // oasis (font declarations only)
+ public static final String SVG_X="svg:x";
+ public static final String SVG_Y="svg:y";
+ public static final String SVG_HEIGHT="svg:height";
+ public static final String SVG_WIDTH="svg:width";
+ // xlink namespace
+ public static final String XLINK_HREF="xlink:href";
+ // math namespace
+ public static final String MATH_MATH="math:math";
+ public static final String MATH_SEMANTICS="math:semantics";
+ public static final String MATH_ANNOTATION="math:annotation";
+
+}
diff --git a/source/java/writer2latex/util/Base64.java b/source/java/writer2latex/util/Base64.java
new file mode 100644
index 0000000..39d77a0
--- /dev/null
+++ b/source/java/writer2latex/util/Base64.java
@@ -0,0 +1,1811 @@
+/**
+ * This is Robert Harders public domain Base64 class. It is unmodified, except for the package name.
+ *
+ * Encodes and decodes to and from Base64 notation.
+ *Homepage: http://iharder.net/base64.
+ * + *The options parameter, which appears in a few places, is used to pass + * several pieces of information to the encoder. In the "higher level" methods such as + * encodeBytes( bytes, options ) the options parameter can be used to indicate such + * things as first gzipping the bytes before encoding them, not inserting linefeeds + * (though that breaks strict Base64 compatibility), and encoding using the URL-safe + * and Ordered dialects.
+ * + *The constants defined in Base64 can be OR-ed together to combine options, so you + * might make a call like this:
+ * + *String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DONT_BREAK_LINES );
+ *
+ * to compress the data before encoding it and then making the output have no newline characters.
+ * + * + *+ * Change Log: + *
+ *+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/base64 + * periodically to check for updates or to contribute improvements. + *
+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.2.2 + */ +package writer2latex.util; + +public class Base64 +{ + +/* ******** P U B L I C F I E L D S ******** */ + + + /** No options specified. Value is zero. */ + public final static int NO_OPTIONS = 0; + + /** Specify encoding. */ + public final static int ENCODE = 1; + + + /** Specify decoding. */ + public final static int DECODE = 0; + + + /** Specify that data should be gzip-compressed. */ + public final static int GZIP = 2; + + + /** Don't break lines when encoding (violates strict Base64 specification) */ + public final static int DONT_BREAK_LINES = 8; + + /** + * Encode using Base64-like encoding that is URL- and Filename-safe as described + * in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * It is important to note that data encoded this way is not officially valid Base64, + * or at the very least should not be called Base64 without also specifying that is + * was encoded using the URL- and Filename-safe dialect. + */ + public final static int URL_SAFE = 16; + + + /** + * Encode using the special "ordered" dialect of Base64 described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + public final static int ORDERED = 32; + + +/* ******** P R I V A T E F I E L D S ******** */ + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "UTF-8"; + + + // I think I end up not using the BAD_ENCODING indicator. + //private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + +/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ + + /** The 64 valid Base64 values. */ + //private final static byte[] ALPHABET; + /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ + private final static byte[] _STANDARD_ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] _STANDARD_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ + + /** + * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash." + */ + private final static byte[] _URL_SAFE_ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_' + }; + + /** + * Used in decoding URL- and Filename-safe dialects of Base64. + */ + private final static byte[] _URL_SAFE_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 62, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 63, // Underscore at decimal 95 + -9, // Decimal 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + + +/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ + + /** + * I don't get the point of this technique, but it is described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + private final static byte[] _ORDERED_ALPHABET = + { + (byte)'-', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', + (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'_', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z' + }; + + /** + * Used in decoding the "ordered" dialect of Base64. + */ + private final static byte[] _ORDERED_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 0, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M' + 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 37, // Underscore at decimal 95 + -9, // Decimal 96 + 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm' + 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ + + + /** + * Returns one of the _SOMETHING_ALPHABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URLSAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getAlphabet( int options ) + { + if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_ALPHABET; + else if( (options & ORDERED) == ORDERED ) return _ORDERED_ALPHABET; + else return _STANDARD_ALPHABET; + + } // end getAlphabet + + + /** + * Returns one of the _SOMETHING_DECODABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URL_SAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getDecodabet( int options ) + { + if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_DECODABET; + else if( (options & ORDERED) == ORDERED ) return _ORDERED_DECODABET; + else return _STANDARD_DECODABET; + + } // end getAlphabet + + + + /** Defeats instantiation. */ + private Base64(){} + + + /** + * Encodes or decodes two files from the command line; + * feel free to delete this method (in fact you probably should) + * if you're embedding this code into a larger program. + */ + public final static void main( String[] args ) + { + if( args.length < 3 ){ + usage("Not enough arguments."); + } // end if: args.length < 3 + else { + String flag = args[0]; + String infile = args[1]; + String outfile = args[2]; + if( flag.equals( "-e" ) ){ + Base64.encodeFileToFile( infile, outfile ); + } // end if: encode + else if( flag.equals( "-d" ) ) { + Base64.decodeFileToFile( infile, outfile ); + } // end else if: decode + else { + usage( "Unknown flag: " + flag ); + } // end else + } // end else + } // end main + + /** + * Prints command line usage. + * + * @param msg A message to include with usage info. + */ + private final static void usage( String msg ) + { + System.err.println( msg ); + System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" ); + } // end usage + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * Code can reuse a byte array by passing a four-byte array as b4. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) + { + encode3to4( threeBytes, 0, numSigBytes, b4, 0, options ); + return b4; + } // end encode3to4 + + + /** + *Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes.
+ *This is the lowest level of the encoding methods with + * all possible parameters.
+ * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset, int options ) + { + byte[] ALPHABET = getAlphabet( options ); + + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) + | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) + | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); + + switch( numSigBytes ) + { + case 3: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; + return destination; + + case 2: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + case 1: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = EQUALS_SIGN; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + * The object is not GZip-compressed before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject ) + { + return encodeObject( serializableObject, NO_OPTIONS ); + } // end encodeObject + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + *+ * Valid options:
+ * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: encodeObject( myObj, Base64.GZIP )
or
+ *
+ * Example: encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ * @param serializableObject The object to encode
+ * @param options Specified options
+ * @return The Base64-encoded object
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeObject( java.io.Serializable serializableObject, int options )
+ {
+ // Streams
+ java.io.ByteArrayOutputStream baos = null;
+ java.io.OutputStream b64os = null;
+ java.io.ObjectOutputStream oos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+
+ // Isolate options
+ int gzip = (options & GZIP);
+ int dontBreakLines = (options & DONT_BREAK_LINES);
+
+ try
+ {
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+
+ // GZip?
+ if( gzip == GZIP )
+ {
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+ oos = new java.io.ObjectOutputStream( gzos );
+ } // end if: gzip
+ else
+ oos = new java.io.ObjectOutputStream( b64os );
+
+ oos.writeObject( serializableObject );
+ } // end try
+ catch( java.io.IOException e )
+ {
+ e.printStackTrace();
+ return null;
+ } // end catch
+ finally
+ {
+ try{ oos.close(); } catch( Exception e ){}
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( baos.toByteArray() );
+ } // end catch
+
+ } // end encode
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source )
+ {
+ return encodeBytes( source, 0, source.length, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ *
+ * Valid options:
+ * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: encodeBytes( myData, Base64.GZIP )
or
+ *
+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ *
+ * @param source The data to convert
+ * @param options Specified options
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int options )
+ {
+ return encodeBytes( source, 0, source.length, options );
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source, int off, int len )
+ {
+ return encodeBytes( source, off, len, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ *
+ * Valid options:
+ * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: encodeBytes( myData, Base64.GZIP )
or
+ *
+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @param options Specified options
+ * @param options alphabet type is pulled from this (standard, url-safe, ordered)
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int off, int len, int options )
+ {
+ // Isolate options
+ int dontBreakLines = ( options & DONT_BREAK_LINES );
+ int gzip = ( options & GZIP );
+
+ // Compress?
+ if( gzip == GZIP )
+ {
+ java.io.ByteArrayOutputStream baos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ Base64.OutputStream b64os = null;
+
+
+ try
+ {
+ // GZip -> Base64 -> ByteArray
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+
+ gzos.write( source, off, len );
+ gzos.close();
+ } // end try
+ catch( java.io.IOException e )
+ {
+ e.printStackTrace();
+ return null;
+ } // end catch
+ finally
+ {
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( baos.toByteArray() );
+ } // end catch
+ } // end if: compress
+
+ // Else, don't compress. Better not to use streams at all then.
+ else
+ {
+ // Convert option to boolean in way that code likes it.
+ boolean breakLines = dontBreakLines == 0;
+
+ int len43 = len * 4 / 3;
+ byte[] outBuff = new byte[ ( len43 ) // Main 4:3
+ + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
+ + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+ int d = 0;
+ int e = 0;
+ int len2 = len - 2;
+ int lineLength = 0;
+ for( ; d < len2; d+=3, e+=4 )
+ {
+ encode3to4( source, d+off, 3, outBuff, e, options );
+
+ lineLength += 4;
+ if( breakLines && lineLength == MAX_LINE_LENGTH )
+ {
+ outBuff[e+4] = NEW_LINE;
+ e++;
+ lineLength = 0;
+ } // end if: end of line
+ } // en dfor: each piece of array
+
+ if( d < len )
+ {
+ encode3to4( source, d+off, len - d, outBuff, e, options );
+ e += 4;
+ } // end if: some padding needed
+
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( outBuff, 0, e, PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( outBuff, 0, e );
+ } // end catch
+
+ } // end else: don't compress
+
+ } // end encodeBytes
+
+
+
+
+
+/* ******** D E C O D I N G M E T H O D S ******** */
+
+
+ /**
+ * Decodes four bytes from array source
+ * and writes the resulting bytes (up to three of them)
+ * to destination.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * srcOffset and destOffset.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate srcOffset + 4 for
+ * the source array or destOffset + 3 for
+ * the destination array.
+ * This method returns the actual number of bytes that
+ * were converted from the Base64 encoding.
+ *
This is the lowest level of the decoding methods with + * all possible parameters.
+ * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param options alphabet type is pulled from this (standard, url-safe, ordered) + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options ) + { + byte[] DECODABET = getDecodabet( options ); + + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); + return 2; + } + + // Example: DkLE + else + { + try{ + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) + | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); + + + destination[ destOffset ] = (byte)( outBuff >> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); + destination[ destOffset + 2 ] = (byte)( outBuff ); + + return 3; + }catch( Exception e){ + System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); + System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); + System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); + System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); + return -1; + } // end catch + } + } // end decodeToBytes + + + + + /** + * Very low-level access to decoding ASCII characters in + * the form of a byte array. Does not support automatically + * gunzipping or any other "fancy" features. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len, int options ) + { + byte[] DECODABET = getDecodabet( options ); + + int len34 = len * 3 / 4; + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for( i = off; i < off+len; i++ ) + { + sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; + + if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better + { + if( sbiDecode >= EQUALS_SIGN_ENC ) + { + b4[ b4Posn++ ] = sbiCrop; + if( b4Posn > 3 ) + { + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else + { + System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); + return null; + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode + + + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s ) + { + return decode( s, NO_OPTIONS ); + } + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @param options encode options such as URL_SAFE + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s, int options ) + { + byte[] bytes; + try + { + bytes = s.getBytes( PREFERRED_ENCODING ); + } // end try + catch( java.io.UnsupportedEncodingException uee ) + { + bytes = s.getBytes(); + } // end catch + // + + // Decode + bytes = decode( bytes, 0, bytes.length, options ); + + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + if( bytes != null && bytes.length >= 4 ) + { + + int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) + { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try + { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream( bytes ); + gzis = new java.util.zip.GZIPInputStream( bais ); + + while( ( length = gzis.read( buffer ) ) >= 0 ) + { + baos.write(buffer,0,length); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch( java.io.IOException e ) + { + // Just return originally-decoded bytes + } // end catch + finally + { + try{ baos.close(); } catch( Exception e ){} + try{ gzis.close(); } catch( Exception e ){} + try{ bais.close(); } catch( Exception e ){} + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @since 1.5 + */ + public static Object decodeToObject( String encodedObject ) + { + // Decode and gunzip if necessary + byte[] objBytes = decode( encodedObject ); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + Object obj = null; + + try + { + bais = new java.io.ByteArrayInputStream( objBytes ); + ois = new java.io.ObjectInputStream( bais ); + + obj = ois.readObject(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + catch( java.lang.ClassNotFoundException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + finally + { + try{ bais.close(); } catch( Exception e ){} + try{ ois.close(); } catch( Exception e ){} + } // end finally + + return obj; + } // end decodeObject + + + + /** + * Convenience method for encoding data to a file. + * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean encodeToFile( byte[] dataToEncode, String filename ) + { + boolean success = false; + Base64.OutputStream bos = null; + try + { + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.ENCODE ); + bos.write( dataToEncode ); + success = true; + } // end try + catch( java.io.IOException e ) + { + + success = false; + } // end catch: IOException + finally + { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end encodeToFile + + + /** + * Convenience method for decoding data to a file. + * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean decodeToFile( String dataToDecode, String filename ) + { + boolean success = false; + Base64.OutputStream bos = null; + try + { + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.DECODE ); + bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) ); + success = true; + } // end try + catch( java.io.IOException e ) + { + success = false; + } // end catch: IOException + finally + { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end decodeToFile + + + + + /** + * Convenience method for reading a base64-encoded + * file and decoding it. + * + * @param filename Filename for reading encoded data + * @return decoded byte array or null if unsuccessful + * + * @since 2.1 + */ + public static byte[] decodeFromFile( String filename ) + { + byte[] decodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if( file.length() > Integer.MAX_VALUE ) + { + System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." ); + return null; + } // end if: file too big for int index + buffer = new byte[ (int)file.length() ]; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.DECODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + decodedData = new byte[ length ]; + System.arraycopy( buffer, 0, decodedData, 0, length ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error decoding from file " + filename ); + } // end catch: IOException + finally + { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return decodedData; + } // end decodeFromFile + + + + /** + * Convenience method for reading a binary file + * and base64-encoding it. + * + * @param filename Filename for reading binary data + * @return base64-encoded string or null if unsuccessful + * + * @since 2.1 + */ + public static String encodeFromFile( String filename ) + { + String encodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1) + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.ENCODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error encoding from file " + filename ); + } // end catch: IOException + finally + { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return encodedData; + } // end encodeFromFile + + + + + /** + * Reads infile and encodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @return true if the operation is successful + * @since 2.2 + */ + public static boolean encodeFileToFile( String infile, String outfile ) + { + boolean success = false; + java.io.InputStream in = null; + java.io.OutputStream out = null; + try{ + in = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( infile ) ), + Base64.ENCODE ); + out = new java.io.BufferedOutputStream( new java.io.FileOutputStream( outfile ) ); + byte[] buffer = new byte[65536]; // 64K + int read = -1; + while( ( read = in.read(buffer) ) >= 0 ){ + out.write( buffer,0,read ); + } // end while: through file + success = true; + } catch( java.io.IOException exc ){ + exc.printStackTrace(); + } finally{ + try{ in.close(); } catch( Exception exc ){} + try{ out.close(); } catch( Exception exc ){} + } // end finally + + return success; + } // end encodeFileToFile + + + + /** + * Reads infile and decodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @return true if the operation is successful + * @since 2.2 + */ + public static boolean decodeFileToFile( String infile, String outfile ) + { + boolean success = false; + java.io.InputStream in = null; + java.io.OutputStream out = null; + try{ + in = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( infile ) ), + Base64.DECODE ); + out = new java.io.BufferedOutputStream( new java.io.FileOutputStream( outfile ) ); + byte[] buffer = new byte[65536]; // 64K + int read = -1; + while( ( read = in.read(buffer) ) >= 0 ){ + out.write( buffer,0,read ); + } // end while: through file + success = true; + } catch( java.io.IOException exc ){ + exc.printStackTrace(); + } finally{ + try{ in.close(); } catch( Exception exc ){} + try{ out.close(); } catch( Exception exc ){} + } // end finally + + return success; + } // end decodeFileToFile + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + + /** + * A {@link Base64.InputStream} will read data from another + * java.io.InputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream + { + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + private int options; // Record options used to create the stream. + private byte[] alphabet; // Local copies to avoid extra method calls + private byte[] decodabet; // Local copies to avoid extra method calls + + + /** + * Constructs a {@link Base64.InputStream} in DECODE mode. + * + * @param in the java.io.InputStream from which to read data. + * @since 1.3 + */ + public InputStream( java.io.InputStream in ) + { + this( in, DECODE ); + } // end constructor + + + /** + * Constructs a {@link Base64.InputStream} in + * either ENCODE or DECODE mode. + *+ * Valid options:
+ * ENCODE or DECODE: Encode or Decode as data is read. + * DONT_BREAK_LINES: don't break lines at 76 characters + * (only meaningful when encoding) + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: new Base64.InputStream( in, Base64.DECODE )
+ *
+ *
+ * @param in the java.io.InputStream from which to read data.
+ * @param options Specified options
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public InputStream( java.io.InputStream in, int options )
+ {
+ super( in );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 4 : 3;
+ this.buffer = new byte[ bufferLength ];
+ this.position = -1;
+ this.lineLength = 0;
+ this.options = options; // Record for later, mostly to determine which alphabet to use
+ this.alphabet = getAlphabet(options);
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+ /**
+ * Reads enough of the input stream to convert
+ * to/from Base64 and returns the next byte.
+ *
+ * @return next byte
+ * @since 1.3
+ */
+ public int read() throws java.io.IOException
+ {
+ // Do we need to get data?
+ if( position < 0 )
+ {
+ if( encode )
+ {
+ byte[] b3 = new byte[3];
+ int numBinaryBytes = 0;
+ for( int i = 0; i < 3; i++ )
+ {
+ try
+ {
+ int b = in.read();
+
+ // If end of stream, b is -1.
+ if( b >= 0 )
+ {
+ b3[i] = (byte)b;
+ numBinaryBytes++;
+ } // end if: not end of stream
+
+ } // end try: read
+ catch( java.io.IOException e )
+ {
+ // Only a problem if we got no data at all.
+ if( i == 0 )
+ throw e;
+
+ } // end catch
+ } // end for: each needed input byte
+
+ if( numBinaryBytes > 0 )
+ {
+ encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
+ position = 0;
+ numSigBytes = 4;
+ } // end if: got data
+ else
+ {
+ return -1;
+ } // end else
+ } // end if: encoding
+
+ // Else decoding
+ else
+ {
+ byte[] b4 = new byte[4];
+ int i = 0;
+ for( i = 0; i < 4; i++ )
+ {
+ // Read four "meaningful" bytes:
+ int b = 0;
+ do{ b = in.read(); }
+ while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
+
+ if( b < 0 )
+ break; // Reads a -1 if end of stream
+
+ b4[i] = (byte)b;
+ } // end for: each needed input byte
+
+ if( i == 4 )
+ {
+ numSigBytes = decode4to3( b4, 0, buffer, 0, options );
+ position = 0;
+ } // end if: got four characters
+ else if( i == 0 ){
+ return -1;
+ } // end else if: also padded correctly
+ else
+ {
+ // Must have broken out from above.
+ throw new java.io.IOException( "Improperly padded Base64 input." );
+ } // end
+
+ } // end else: decode
+ } // end else: get data
+
+ // Got data?
+ if( position >= 0 )
+ {
+ // End of relevant data?
+ if( /*!encode &&*/ position >= numSigBytes )
+ return -1;
+
+ if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ lineLength = 0;
+ return '\n';
+ } // end if
+ else
+ {
+ lineLength++; // This isn't important when decoding
+ // but throwing an extra "if" seems
+ // just as wasteful.
+
+ int b = buffer[ position++ ];
+
+ if( position >= bufferLength )
+ position = -1;
+
+ return b & 0xFF; // This is how you "cast" a byte that's
+ // intended to be unsigned.
+ } // end else
+ } // end if: position >= 0
+
+ // Else error
+ else
+ {
+ // When JDK1.4 is more accepted, use an assertion here.
+ throw new java.io.IOException( "Error in Base64 code reading stream." );
+ } // end else
+ } // end read
+
+
+ /**
+ * Calls {@link #read()} repeatedly until the end of stream
+ * is reached or len bytes are read.
+ * Returns number of bytes read into array or -1 if
+ * end of stream is encountered.
+ *
+ * @param dest array to hold values
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @return bytes read into array or -1 if end of stream is encountered.
+ * @since 1.3
+ */
+ public int read( byte[] dest, int off, int len ) throws java.io.IOException
+ {
+ int i;
+ int b;
+ for( i = 0; i < len; i++ )
+ {
+ b = read();
+
+ //if( b < 0 && i == 0 )
+ // return -1;
+
+ if( b >= 0 )
+ dest[off + i] = (byte)b;
+ else if( i == 0 )
+ return -1;
+ else
+ break; // Out of 'for' loop
+ } // end for: each byte read
+ return i;
+ } // end read
+
+ } // end inner class InputStream
+
+
+
+
+
+
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
+
+
+
+ /**
+ * A {@link Base64.OutputStream} will write data to another
+ * java.io.OutputStream, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class OutputStream extends java.io.FilterOutputStream
+ {
+ private boolean encode;
+ private int position;
+ private byte[] buffer;
+ private int bufferLength;
+ private int lineLength;
+ private boolean breakLines;
+ private byte[] b4; // Scratch used in a few places
+ private boolean suspendEncoding;
+ private int options; // Record for later
+ private byte[] alphabet; // Local copies to avoid extra method calls
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out )
+ {
+ this( out, ENCODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in
+ * either ENCODE or DECODE mode.
+ *
+ * Valid options:
+ * ENCODE or DECODE: Encode or Decode as data is read. + * DONT_BREAK_LINES: don't break lines at 76 characters + * (only meaningful when encoding) + * Note: Technically, this makes your encoding non-compliant. + *+ *
+ * Example: new Base64.OutputStream( out, Base64.ENCODE )
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @param options Specified options.
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out, int options )
+ {
+ super( out );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 3 : 4;
+ this.buffer = new byte[ bufferLength ];
+ this.position = 0;
+ this.lineLength = 0;
+ this.suspendEncoding = false;
+ this.b4 = new byte[4];
+ this.options = options;
+ this.alphabet = getAlphabet(options);
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+
+ /**
+ * Writes the byte to the output stream after
+ * converting to/from Base64 notation.
+ * When encoding, bytes are buffered three
+ * at a time before the output stream actually
+ * gets a write() call.
+ * When decoding, bytes are buffered four
+ * at a time.
+ *
+ * @param theByte the byte to write
+ * @since 1.3
+ */
+ public void write(int theByte) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theByte );
+ return;
+ } // end if: supsended
+
+ // Encode?
+ if( encode )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to encode.
+ {
+ out.write( encode3to4( b4, buffer, bufferLength, options ) );
+
+ lineLength += 4;
+ if( breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ out.write( NEW_LINE );
+ lineLength = 0;
+ } // end if: end of line
+
+ position = 0;
+ } // end if: enough to output
+ } // end if: encoding
+
+ // Else, Decoding
+ else
+ {
+ // Meaningful Base64 character?
+ if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to output.
+ {
+ int len = Base64.decode4to3( buffer, 0, b4, 0, options );
+ out.write( b4, 0, len );
+ //out.write( Base64.decode4to3( buffer ) );
+ position = 0;
+ } // end if: enough to output
+ } // end if: meaningful base64 character
+ else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
+ {
+ throw new java.io.IOException( "Invalid character in Base64 data." );
+ } // end else: not white space either
+ } // end else: decoding
+ } // end write
+
+
+
+ /**
+ * Calls {@link #write(int)} repeatedly until len
+ * bytes are written.
+ *
+ * @param theBytes array from which to read bytes
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @since 1.3
+ */
+ public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theBytes, off, len );
+ return;
+ } // end if: supsended
+
+ for( int i = 0; i < len; i++ )
+ {
+ write( theBytes[ off + i ] );
+ } // end for: each byte written
+
+ } // end write
+
+
+
+ /**
+ * Method added by PHIL. [Thanks, PHIL. -Rob]
+ * This pads the buffer without closing the stream.
+ */
+ public void flushBase64() throws java.io.IOException
+ {
+ if( position > 0 )
+ {
+ if( encode )
+ {
+ out.write( encode3to4( b4, buffer, position, options ) );
+ position = 0;
+ } // end if: encoding
+ else
+ {
+ throw new java.io.IOException( "Base64 input not properly padded." );
+ } // end else: decoding
+ } // end if: buffer partially full
+
+ } // end flush
+
+
+ /**
+ * Flushes and closes (I think, in the superclass) the stream.
+ *
+ * @since 1.3
+ */
+ public void close() throws java.io.IOException
+ {
+ // 1. Ensure that pending characters are written
+ flushBase64();
+
+ // 2. Actually close the stream
+ // Base class both flushes and closes.
+ super.close();
+
+ buffer = null;
+ out = null;
+ } // end close
+
+
+
+ /**
+ * Suspends encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void suspendEncoding() throws java.io.IOException
+ {
+ flushBase64();
+ this.suspendEncoding = true;
+ } // end suspendEncoding
+
+
+ /**
+ * Resumes encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void resumeEncoding()
+ {
+ this.suspendEncoding = false;
+ } // end resumeEncoding
+
+
+
+ } // end inner class OutputStream
+
+
+} // end class Base64
diff --git a/source/java/writer2latex/util/CSVList.java b/source/java/writer2latex/util/CSVList.java
new file mode 100644
index 0000000..858286d
--- /dev/null
+++ b/source/java/writer2latex/util/CSVList.java
@@ -0,0 +1,69 @@
+/************************************************************************
+ *
+ * CSVList.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 0.4 (2004-08-10)
+ *
+ */
+
+package writer2latex.util;
+
+// Create a list of values separated by commas or another seperation character
+public class CSVList{
+ private String sSep;
+ private String sNameValueSep;
+ private boolean bEmpty = true;
+ private StringBuffer buf = new StringBuffer();
+
+ public CSVList(String sSep, String sNameValueSep) {
+ this.sSep=sSep;
+ this.sNameValueSep=sNameValueSep;
+ }
+
+ public CSVList(String sSep) {
+ this(sSep,":");
+ }
+
+ public CSVList(char cSep) {
+ this(Character.toString(cSep),":");
+ }
+
+ public void addValue(String sVal){
+ if (sVal==null) { return; }
+ if (bEmpty) { bEmpty=false; } else { buf.append(sSep); }
+ buf.append(sVal);
+ }
+
+ public void addValue(String sName, String sVal) {
+ if (sName==null) { return; }
+ if (bEmpty) { bEmpty=false; } else { buf.append(sSep); }
+ buf.append(sName).append(sNameValueSep).append(sVal);
+ }
+
+ public String toString() {
+ return buf.toString();
+ }
+
+ public boolean isEmpty() {
+ return bEmpty;
+ }
+
+}
diff --git a/source/java/writer2latex/util/ExportNameCollection.java b/source/java/writer2latex/util/ExportNameCollection.java
new file mode 100644
index 0000000..50110d1
--- /dev/null
+++ b/source/java/writer2latex/util/ExportNameCollection.java
@@ -0,0 +1,102 @@
+/************************************************************************
+ *
+ * ExportNameCollection.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2007 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 0.5 (2007-02-25)
+ *
+ */
+
+package writer2latex.util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+// Collection of export names
+// Used for mapping named collections to simpler names (only A-Z, a-z and 0-9)
+public class ExportNameCollection{
+ private Hashtable exportNames = new Hashtable();
+ private String sPrefix;
+ private boolean bAcceptNumbers;
+
+ public ExportNameCollection(String sPrefix, boolean b) {
+ this.sPrefix=sPrefix;
+ bAcceptNumbers = b;
+ }
+
+ public ExportNameCollection(boolean b) {
+ this("",b);
+ }
+
+ public Enumeration keys() {
+ return exportNames.keys();
+ }
+
+ public void addName(String sName){
+ if (containsName(sName)) { return; }
+ StringBuffer outbuf=new StringBuffer();
+ SimpleInputBuffer inbuf=new SimpleInputBuffer(sName);
+
+ // Don't start with a digit
+ if (bAcceptNumbers && inbuf.peekChar()>='0' && inbuf.peekChar()<='9') {
+ outbuf.append('a');
+ }
+
+ char c;
+ // convert numbers to roman numbers and discard unwanted characters
+ while ((c=inbuf.peekChar())!='\0'){
+ if ((c>='a' && c<='z') || (c>='A' && c<='Z')) {
+ outbuf.append(inbuf.getChar());
+ }
+ else if (c>='0' && c<='9'){
+ if (bAcceptNumbers) {
+ outbuf.append(inbuf.getInteger());
+ }
+ else {
+ outbuf.append(Misc.int2roman(
+ Integer.parseInt(inbuf.getInteger())));
+ }
+ }
+ else {
+ inbuf.getChar(); // ignore this character
+ }
+ }
+ String sExportName=outbuf.toString();
+ // the result may exist in the collecion; add a's at the end
+ while (exportNames.containsValue(sExportName)){
+ sExportName+="a";
+ }
+ exportNames.put(sName,sExportName);
+ }
+
+ public String getExportName(String sName) {
+ // add the name, if it does not exist
+ if (!containsName(sName)) { addName(sName); }
+ return sPrefix + (String) exportNames.get(sName);
+ }
+
+ public boolean containsName(String sName) {
+ return exportNames.containsKey(sName);
+ }
+
+ public boolean isEmpty() {
+ return exportNames.size()==0;
+ }
+}
diff --git a/source/java/writer2latex/util/Misc.java b/source/java/writer2latex/util/Misc.java
new file mode 100644
index 0000000..d368585
--- /dev/null
+++ b/source/java/writer2latex/util/Misc.java
@@ -0,0 +1,356 @@
+/************************************************************************
+ *
+ * Misc.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.Math;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+//import java.util.Hashtable;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+// This class contains some usefull, but unrelated static methods
+public class Misc{
+
+ private final static int BUFFERSIZE = 1024;
+
+ public static final int[] doubleIntArray(int[] array) {
+ int n = array.length;
+ int[] newArray = new int[2*n];
+ for (int i=0; iInputStream
into a byte
array
InputStream
to read
+ * @return a byte array with the contents read from the stream
+ * @throws IOException in case of any I/O errors.
+ */
+ public static byte[] inputStreamToByteArray(InputStream is) throws IOException {
+ if (is==null) {
+ throw new IOException ("No input stream to read");
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ int nLen = 0;
+ byte buffer[] = new byte[BUFFERSIZE];
+ while ((nLen = is.read(buffer)) > 0) {
+ baos.write(buffer, 0, nLen);
+ }
+ return baos.toByteArray();
+ }
+
+
+
+}
diff --git a/source/java/writer2latex/util/Package.html b/source/java/writer2latex/util/Package.html
new file mode 100644
index 0000000..3536243
--- /dev/null
+++ b/source/java/writer2latex/util/Package.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Some general utility classes.
+ + diff --git a/source/java/writer2latex/util/SimpleInputBuffer.java b/source/java/writer2latex/util/SimpleInputBuffer.java new file mode 100644 index 0000000..a511577 --- /dev/null +++ b/source/java/writer2latex/util/SimpleInputBuffer.java @@ -0,0 +1,106 @@ +/************************************************************************ + * + * SimpleInputBuffer.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2007-11-22) + * + */ + +package writer2latex.util; + +/** This class provides a simple string input buffer; it can be used as the + * basis of a tokenizer. + */ +public class SimpleInputBuffer { + + private String sContent; + private int nIndex, nLen; + + /*private static boolean isEndOrLineEnd(char cChar) { + switch (cChar){ + case '\0': + case '\n': + case '\r': + return true; + default: + return false; + } + }*/ + + private static boolean isDigitOrDot(char cChar) { + return (cChar>='0' && cChar<='9') || cChar=='.'; + } + + private static boolean isDigitOrDotOrComma(char cChar) { + return isDigitOrDot(cChar) || cChar==','; + } + + public SimpleInputBuffer(String sContent) { + this.sContent=sContent; + nLen=sContent.length(); + nIndex=0; + } + + public int getIndex() { return nIndex; } + + public boolean atEnd() { + return nIndex>=nLen; + } + + public char peekChar() { + return nIndexOfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public CellStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ // Style maps for Cells are currently not supported.
+ // (In OOo, cell styles are only supported by Calc)
+ this.styleMap = new XhtmlStyleMap();
+ this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Get the family of cell styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getCellStyles();
+ }
+
+ /** Create default tag name to represent a Cell object
+ * @param style to use
+ * @return the tag name.
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "td";
+ }
+
+ /** Convert formatting properties for a specific Cell style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ // Apply "inner" box properties (no margins)
+ getFrameSc().cssBorder(style,props,bInherit);
+ getFrameSc().cssPadding(style,props,bInherit);
+ getFrameSc().cssBackground(style,props,bInherit);
+ // only relevant for spreadsheets
+ getParSc().cssPar(style,props,bInherit);
+ getTextSc().cssTextCommon(style,props,bInherit);
+ // Cell-specific properties (vertical alignment)
+ cssCell(style,props,bInherit);
+ }
+
+ private void cssCell(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Vertical align: Some values fit with css
+ String s = ofr.isOpenDocument() ?
+ style.getProperty(XMLString.STYLE_VERTICAL_ALIGN,bInherit) :
+ style.getProperty(XMLString.FO_VERTICAL_ALIGN,bInherit);
+ if ("middle".equals(s)) { props.addValue("vertical-align","middle"); }
+ else if ("bottom".equals(s)) { props.addValue("vertical-align","bottom"); }
+ else if ("top".equals(s)) { props.addValue("vertical-align","top"); }
+ else {
+ // No value or "automatic" means, according to the spec,
+ //"The application decide how to align the text."
+ // We treat this case like OOo does:
+ props.addValue("vertical-align", ofr.isSpreadsheet() ? "bottom" : "top");
+ }
+ }
+
+}
diff --git a/source/java/writer2latex/xhtml/Converter.java b/source/java/writer2latex/xhtml/Converter.java
new file mode 100644
index 0000000..9bcc643
--- /dev/null
+++ b/source/java/writer2latex/xhtml/Converter.java
@@ -0,0 +1,628 @@
+/************************************************************************
+ *
+ * Converter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-16)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ListIterator;
+import java.util.LinkedList;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import writer2latex.api.Config;
+import writer2latex.api.ConverterFactory;
+//import writer2latex.api.ConverterResult;
+import writer2latex.base.ConverterBase;
+//import writer2latex.latex.LaTeXDocumentPortion;
+//import writer2latex.latex.util.Context;
+import writer2latex.office.MIMETypes;
+import writer2latex.office.OfficeReader;
+import writer2latex.office.StyleWithProperties;
+import writer2latex.office.XMLString;
+import writer2latex.util.ExportNameCollection;
+import writer2latex.util.Misc;
+
+/**
+ * This class converts an OpenDocument file to an XHTML(+MathML) document<.
+ * + */ +public class Converter extends ConverterBase { + // Config + private XhtmlConfig config; + + public Config getConfig() { return config; } + + // The locale + private L10n l10n; + + // The helpers + private StyleConverter styleCv; + private TextConverter textCv; + private TableConverter tableCv; + private DrawConverter drawCv; + private MathConverter mathCv; + + // The template + private XhtmlDocument template = null; + + // The xhtml output file(s) + protected int nType = XhtmlDocument.XHTML10; // the doctype + Vector outFiles; + private int nOutFileIndex; + private XhtmlDocument htmlDoc; // current outfile + private Document htmlDOM; // current DOM, usually within htmlDoc + private boolean bNeedHeaderFooter = false; + + // Hyperlinks + Hashtable targets = new Hashtable(); + LinkedList links = new LinkedList(); + // Strip illegal characters from internal hyperlink targets + private ExportNameCollection targetNames = new ExportNameCollection(true); + + // Constructor setting the DOCTYPE + public Converter(int nType) { + super(); + config = new XhtmlConfig(); + this.nType = nType; + } + + // override + public void readTemplate(InputStream is) throws IOException { + template = new XhtmlDocument("Template",nType); + template.read(is); + } + + public void readTemplate(File file) throws IOException { + readTemplate(new FileInputStream(file)); + } + + protected StyleConverter getStyleCv() { return styleCv; } + + protected TextConverter getTextCv() { return textCv; } + + protected TableConverter getTableCv() { return tableCv; } + + protected DrawConverter getDrawCv() { return drawCv; } + + protected MathConverter getMathCv() { return mathCv; } + + protected int getType() { return nType; } + + protected int getOutFileIndex() { return nOutFileIndex; } + + protected Element createElement(String s) { return htmlDOM.createElement(s); } + + protected Text createTextNode(String s) { return htmlDOM.createTextNode(s); } + + protected Node importNode(Node node, boolean bDeep) { return htmlDOM.importNode(node,bDeep); } + + protected L10n getL10n() { return l10n; } + + // override + public void convertInner() throws IOException { + sTargetFileName = Misc.trimDocumentName(sTargetFileName,XhtmlDocument.getExtension(nType)); + + outFiles = new Vector(); + nOutFileIndex = -1; + + bNeedHeaderFooter = ofr.isSpreadsheet() || ofr.isPresentation() || config.getXhtmlSplitLevel()>0 || config.getXhtmlUplink().length()>0; + + l10n = new L10n(); + + imageLoader.setUseSubdir(config.saveImagesInSubdir()); + + imageLoader.setDefaultFormat(MIMETypes.PNG); + imageLoader.addAcceptedFormat(MIMETypes.JPEG); + imageLoader.addAcceptedFormat(MIMETypes.GIF); + + styleCv = new StyleConverter(ofr,config,this,nType); + textCv = new TextConverter(ofr,config,this); + tableCv = new TableConverter(ofr,config,this); + drawCv = new DrawConverter(ofr,config,this); + mathCv = new MathConverter(ofr,config,this,nType!=XhtmlDocument.XHTML10); + + // Set locale to document language + StyleWithProperties style = ofr.isSpreadsheet() ? ofr.getDefaultCellStyle() : ofr.getDefaultParStyle(); + if (style!=null) { + String sLang = style.getProperty(XMLString.FO_LANGUAGE); + String sCountry = style.getProperty(XMLString.FO_COUNTRY); + if (sLang!=null) { + if (sCountry==null) { l10n.setLocale(sLang); } + else { l10n.setLocale(sLang+"-"+sCountry); } + } + } + + //NodeList list; + // Traverse the body + Element body = ofr.getContent(); + if (ofr.isSpreadsheet()) { tableCv.convertTableContent(body); } + else if (ofr.isPresentation()) { drawCv.convertDrawContent(body); } + else { textCv.convertTextContent(body); } + + // Add footnotes and endnotes + textCv.insertFootnotes(htmlDoc.getContentNode()); + textCv.insertEndnotes(htmlDoc.getContentNode()); + + // Resolve links + ListIterator iter = links.listIterator(); + while (iter.hasNext()) { + LinkDescriptor ld = (LinkDescriptor) iter.next(); + Integer targetIndex = (Integer) targets.get(ld.sId); + if (targetIndex!=null) { + int nTargetIndex = targetIndex.intValue(); + if (nTargetIndex == ld.nIndex) { // same file + ld.element.setAttribute("href","#"+targetNames.getExportName(ld.sId)); + } + else { + ld.element.setAttribute("href",getOutFileName(nTargetIndex,true) + +"#"+targetNames.getExportName(ld.sId)); + } + } + } + + // Export styles (temp.) + for (int i=0; i<=nOutFileIndex; i++) { + Document dom = ((XhtmlDocument) outFiles.get(i)).getContentDOM(); + NodeList hlist = dom.getElementsByTagName("head"); + Node styles = styleCv.exportStyles(dom); + if (styles!=null) { + hlist.item(0).appendChild(styles); + } + } + + // Create headers & footers (if nodes are available) + if (ofr.isSpreadsheet()) { + for (int i=0; i<=nOutFileIndex; i++) { + + XhtmlDocument doc = (XhtmlDocument) outFiles.get(i); + Document dom = doc.getContentDOM(); + Element header = doc.getHeaderNode(); + Element footer = doc.getFooterNode(); + Element headerPar = dom.createElement("p"); + Element footerPar = dom.createElement("p"); + footerPar.setAttribute("style","clear:both"); // no floats may pass! + + // Add uplink + if (config.getXhtmlUplink().length()>0) { + Element a = dom.createElement("a"); + a.setAttribute("href",config.getXhtmlUplink()); + a.appendChild(dom.createTextNode(l10n.get(L10n.UP))); + headerPar.appendChild(a); + headerPar.appendChild(dom.createTextNode(" ")); + a = dom.createElement("a"); + a.setAttribute("href",config.getXhtmlUplink()); + a.appendChild(dom.createTextNode(l10n.get(L10n.UP))); + footerPar.appendChild(a); + footerPar.appendChild(dom.createTextNode(" ")); + } + // Add links to all sheets: + int nSheets = tableCv.sheetNames.size(); + for (int j=0; j A draw element with a hyperlink is represented as two elements,
+ * eg. <draw:a><draw:image/></draw:a>
.
+ * We thus need methods to switch between the two elements.
This method takes a draw
-element.
+ * If this element is a hyperlink, the child element is returned.
+ * Otherwise the argument is returned unchanged.
draw:a
element
+ * @return the corresponding element
+ */
+ public Element getRealDrawElement(Element onode) {
+ if (XMLString.DRAW_A.equals(onode.getTagName())) {
+ Node child = onode.getFirstChild();
+ while (child!=null) {
+ if (OfficeReader.isDrawElement(child)) { return (Element) child; }
+ child = child.getNextSibling();
+ }
+ return null; // empty anchor
+ }
+ return onode;
+ }
+
+ /** A draw element with a hyperlink is represented as two elements,
+ * eg. <draw:a><draw:image/></draw:a>
.
+ * We thus need methods to switch between the two elements.
This method takes a draw
-element.
+ * If this element is contained in a hyperlink, the hyperlink is returned.
+ * Otherwise null is returned.
draw:a
element
+ * @return the hyperlink element, if any
+ */
+ public Element getDrawAnchor(Element onode) {
+ Element parent = (Element) onode.getParentNode();
+ // in oasis format, we need to skip the frame as well
+ if (XMLString.DRAW_FRAME.equals(parent.getTagName())) {
+ parent = (Element) parent.getParentNode();
+ }
+ if (XMLString.DRAW_A.equals(parent.getTagName())) { return parent; }
+ return null;
+ }
+
+ private Element getFrame(Element onode) {
+ if (ofr.isOpenDocument()) return (Element) onode.getParentNode();
+ else return onode;
+ }
+
+ public void flushFrames(Element hnode) {
+ bCollectFrames = false;
+ int nCount = frames.size();
+ for (int i=0; inMode
:
+ * DrawConverter.INLINE
: Presented inline. The hnode
+ * must accept inline content. An inline container must be
+ * provided.DrawConverter.FLOAT
: Presented as a float. The hnode
+ * must accept block/flow content. A block container must be
+ * provided.DrawConverter.ABSOLUTE
: Presented at an absolute
+ * position. A block container must be provided.Containers for block and inline elements should be supplied. + * The containers may be identical (flow container).
+ *Note: A draw:text-box will be ignored in inline mode.
+ * @param onode the draw element + * @param hnodeBlock the xhtml element to attach the converted element to if it's a block element + * @param hnodeInline the xhtml element to attach the converted element to if it's an inline element + * @param nMode identifies how the element should be presented + */ + public void handleDrawElement(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + if (bCollectFrames) { + frames.add(onode); + return; + } + String sName = onode.getNodeName(); + if (sName.equals(XMLString.DRAW_OBJECT)) { + handleDrawObject(onode,hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_OBJECT_OLE)) { + handleDrawObject(onode,hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_IMAGE)) { + handleDrawImage(onode,hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_TEXT_BOX)) { + handleDrawTextBox(onode,hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_A)) { + Element elm = getRealDrawElement(onode); + if (elm!=null) { + handleDrawElement(elm,hnodeBlock,hnodeInline,nMode); + } + } + else if (sName.equals(XMLString.DRAW_FRAME)) { + // OpenDocument embeds the draw element in a frame element + handleDrawElement(Misc.getFirstChildElement(onode),hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_G)) { + handleDrawGroup(onode,hnodeBlock,hnodeInline,nMode); + } + else if (sName.equals(XMLString.DRAW_CONTROL)) { + handleDrawControl(onode,hnodeBlock,hnodeInline,nMode); + } + } + + private void handleDrawObject(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + // TODO: Placement if not inline + // If possible, add the object inline. In pure block context, add a div. + Element hnode; + if (hnodeInline!=null) { + hnode = hnodeInline; + } + else { + Element div = converter.createElement("div"); + hnodeBlock.appendChild(div); + hnode = div; + } + + String sHref = Misc.getAttribute(onode, XMLString.XLINK_HREF); + if (sHref!=null) { // Embedded object in package or linked object + if (ofr.isInPackage(sHref)) { // Embedded object in package + if (sHref.startsWith("#")) { sHref=sHref.substring(1); } + if (sHref.startsWith("./")) { sHref=sHref.substring(2); } + EmbeddedObject object = converter.getEmbeddedObject(sHref); + if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula! + EmbeddedXMLObject xmlObject = (EmbeddedXMLObject) object; + // Document settings = object.getSettingsDOM(); + try { + hnode.appendChild(converter.createTextNode(" ")); + getMathCv().convert(xmlObject.getContentDOM().getDocumentElement(),hnode); + hnode.appendChild(converter.createTextNode(" ")); + } + catch (SAXException e) { + e.printStackTrace(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + else { // unsupported object + boolean bIgnore = true; + if (ofr.isOpenDocument()) { // look for replacement image + Element replacementImage = Misc.getChildByTagName(getFrame(onode),XMLString.DRAW_IMAGE); + if (replacementImage!=null) { + handleDrawImage(replacementImage,hnodeBlock,hnodeInline,nMode); + bIgnore = false; + } + } + if (bIgnore) { + hnode.appendChild( converter.createTextNode("[Warning: object ignored]")); + } + } + } + else { // TODO: Linked object + hnode.appendChild( converter.createTextNode("[Warning: Linked object ignored]")); + } + } + else { // flat xml format + Node formula = Misc.getChildByTagName(onode,XMLString.MATH_MATH); + if (formula != null) { + hnode.appendChild(converter.createTextNode(" ")); + getMathCv().convert(formula,hnode); + hnode.appendChild(converter.createTextNode(" ")); + } + else { // unsupported object + boolean bIgnore = true; + if (ofr.isOpenDocument()) { // look for replacement image + Element replacementImage = Misc.getChildByTagName(getFrame(onode),XMLString.DRAW_IMAGE); + if (replacementImage!=null) { + handleDrawImage(replacementImage,hnodeBlock,hnodeInline,nMode); + bIgnore = false; + } + } + if (bIgnore) { + hnode.appendChild( converter.createTextNode("[Warning: object ignored]")); + } + } + } + } + + private void handleDrawImage(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + // Get the image from the ImageLoader + String sFileName = null; + String sHref = Misc.getAttribute(onode,XMLString.XLINK_HREF); + if (sHref!=null && sHref.length()>0 && !ofr.isInPackage(sHref)) { + // Linked image is not yet handled by ImageLoader. This is a temp. + // solution (will go away when ImageLoader is finished) + sFileName = sHref; + // In OpenDocument *package* format ../ means "leave the package" + if (ofr.isOpenDocument() && ofr.isPackageFormat() && sFileName.startsWith("../")) { + sFileName=sFileName.substring(3); + } + //String sExt = sHref.substring(sHref.lastIndexOf(".")).toLowerCase(); + } + else { // embedded or base64 encoded image + BinaryGraphicsDocument bgd = converter.getImageLoader().getImage(onode); + if (bgd!=null) { + converter.addDocument(bgd); + sFileName = bgd.getFileName(); + } + } + + if (sFileName==null) { return; } // TODO: Add warning? + + // Create the image (sFileName contains the file name) + Element image = converter.createElement("img"); + String sName = Misc.getAttribute(getFrame(onode),XMLString.DRAW_NAME); + converter.addTarget(image,sName+"|graphic"); + image.setAttribute("src",sFileName); + + // Add alternative text, using either alt.text, name or file name + Element frame = getFrame(onode); + Element desc = Misc.getChildByTagName(frame,XMLString.SVG_DESC); + String sAltText = desc!=null ? Misc.getPCDATA(desc) : (sName!=null ? sName : sFileName); + image.setAttribute("alt",sAltText); + + // Now style it + StyleInfo info = new StyleInfo(); + String sStyleName = Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME); + getFrameSc().applyStyle(sStyleName,info); + if (!bOriginalImageSize) { applySize(frame,info.props,false); } + + // Apply placement + applyPlacement(frame, hnodeBlock, hnodeInline, nMode, image, info); + + applyStyle(info,image); + addLink(onode,image); + } + + private void handleDrawTextBox(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + // Create the div with id=name + Element textbox = converter.createElement("div"); + if (hnodeBlock!=null) { + hnodeBlock.appendChild(textbox); + } + else { // cannot include the div inline, ignore + return; + } + // Add name, if defined + String sName = Misc.getAttribute(getFrame(onode),XMLString.DRAW_NAME); + if (sName!=null) { converter.addTarget(textbox,sName+"|frame"); } + + // Now style it + Element frame = getFrame(onode); + StyleInfo info = new StyleInfo(); + // Draw frame style + String sStyleName = Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME); + if (sStyleName!=null) { + getFrameSc().applyStyle(sStyleName,info); + } + // Presentation frame style + sStyleName = Misc.getAttribute(frame, XMLString.PRESENTATION_STYLE_NAME); + if (sStyleName!=null) { + if ("outline".equals(Misc.getAttribute(frame, XMLString.PRESENTATION_CLASS))) { + getPresentationSc().enterOutline(sStyleName); + } + getPresentationSc().applyStyle(sStyleName,info); + } + // Additional text formatting + sStyleName = Misc.getAttribute(frame, XMLString.DRAW_TEXT_STYLE_NAME); + if (sStyleName!=null) { + //getStyleCv().applyParStyle(sStyleName,info); + } + + // Apply placement + switch (nMode) { + case INLINE: + break; + case ABSOLUTE: + applySize(frame,info.props,false); + applyPosition(frame,info.props); + break; + case CENTERED: + info.props.addValue("maring-top","2px"); + info.props.addValue("maring-bottom","2px"); + info.props.addValue("margin-left","auto"); + info.props.addValue("margin-right","auto"); + applySize(frame,info.props,true); + break; + case FLOATING: + applySize(frame,info.props,true); + StyleWithProperties style = ofr.getFrameStyle(sStyleName); + if (style!=null) { + String sPos = style.getProperty(XMLString.STYLE_HORIZONTAL_POS); + String sWrap = style.getProperty(XMLString.STYLE_WRAP); + if (isLeft(sPos) && mayWrapRight(sWrap)) { + info.props.addValue("float","left"); + } + else if (isRight(sPos) && mayWrapLeft(sWrap)) { + info.props.addValue("float","right"); + } + else if (isFromLeft(sPos)) { + if (mayWrapRight(sWrap)) { + info.props.addValue("float","left"); + } + String sX = frame.getAttribute(XMLString.SVG_X); + if (sX!=null && sX.length()>0) { + info.props.addValue("margin-left",scale(sX)); + } + } + } + } + + //Finish + applyStyle(info,textbox); + getTextCv().traverseBlockText(onode,textbox); + getPresentationSc().exitOutline(); + } + + private void handleDrawGroup(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + // TODO: style-name and z-index should be transferred to children + Node child = onode.getFirstChild(); + while (child!=null) { + if (OfficeReader.isDrawElement(child)) { + handleDrawElement((Element) child, hnodeBlock, hnodeInline, nMode); + } + child = child.getNextSibling(); + } + } + + ////////////////////////////////////////////////////////////////////////// + // Forms + + private void handleDrawControl(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) { + // Get the control, if possible + if (form==null) { return; } + ControlReader control = ofr.isOpenDocument() ? + ofr.getForms().getControl(Misc.getAttribute(onode,XMLString.DRAW_CONTROL)) : + ofr.getForms().getControl(Misc.getAttribute(onode,XMLString.FORM_ID)); + if (control==null || control.getOwnerForm()!=form) { return; } + + // Create the control element + Element hcontrol = null; + String sType = control.getControlType(); + + if (XMLString.FORM_TEXT.equals(sType)) { + hcontrol = createInputText(control,false); + } + else if (XMLString.FORM_PASSWORD.equals(sType)) { + hcontrol = createInputText(control,true); + } + else if (XMLString.FORM_FILE.equals(sType)) { + hcontrol = createInputFile(control); + } + else if (XMLString.FORM_IMAGE.equals(sType)) { + hcontrol = createInput(control,"image"); + } + else if (XMLString.FORM_HIDDEN.equals(sType)) { + hcontrol = createInput(control,"hidden"); + } + else if (XMLString.FORM_CHECKBOX.equals(sType)) { + hcontrol = createInputCheck(control,false); + } + else if (XMLString.FORM_RADIO.equals(sType)) { + hcontrol = createInputCheck(control,true); + } + else if (XMLString.FORM_BUTTON.equals(sType)) { + hcontrol = createInputButton(control); + } + else if (XMLString.FORM_FIXED_TEXT.equals(sType)) { + hcontrol = createLabel(control); + } + else if (XMLString.FORM_TEXTAREA.equals(sType)) { + hcontrol = createTextarea(control); + } + else if (XMLString.FORM_LISTBOX.equals(sType)) { + hcontrol = createSelect(control); + } + // ignore other controls + + if (hcontrol!=null) { + Element frame = onode; // controls are *not* contained in a draw:frame! + StyleInfo info = new StyleInfo(); + getFrameSc().applyStyle(frame.getAttribute(XMLString.DRAW_STYLE_NAME),info); + applySize(frame,info.props,false); + applyPlacement(frame,hnodeBlock,hnodeInline,nMode,hcontrol,info); + applyStyle(info,hcontrol); + } + + } + + private Element createInput(ControlReader control, String sType) { + // Create the element + Element input = converter.createElement("input"); + input.setAttribute("type",sType); + return input; + } + + private Element createInputFile(ControlReader control) { + Element input = converter.createElement("input"); + input.setAttribute("type","file"); + setCommonAttributes(control,input); + setDisabled(control,input); + setReadonly(control,input); + setValue(control,input); + return input; + } + + private Element createInputText(ControlReader control, boolean bPassword) { + Element input = converter.createElement("input"); + input.setAttribute("type",bPassword ? "password" : "text"); + setCommonAttributes(control,input); + setName(control,input,true); + setValue(control,input); + setMaxLength(control,input); + setDisabled(control,input); + setReadonly(control,input); + return input; + } + + private Element createInputCheck(ControlReader control, boolean bRadio) { + Element input = converter.createElement("input"); + input.setAttribute("type",bRadio ? "radio" : "checkbox"); + setCommonAttributes(control,input); + setName(control,input,true); + setValue(control,input); + setChecked(control,input); + setDisabled(control,input); + setReadonly(control,input); + // Add a label for the check/radio + Element label = converter.createElement("label"); + setFor(control,label); + label.appendChild(input); + label.appendChild(converter.createTextNode(control.getTypeAttribute(XMLString.FORM_LABEL))); + return label; + } + + private Element createInputButton(ControlReader control) { + Element input = converter.createElement("input"); + String sButtonType = control.getTypeAttribute(XMLString.FORM_BUTTON_TYPE); + if ("submit".equals(sButtonType)) { + input.setAttribute("type","submit"); + } + else if ("reset".equals(sButtonType)) { + input.setAttribute("type","reset"); + } + else { // TODO: url button (using javascript) + input.setAttribute("type","button"); + } + setCommonAttributes(control,input); + setName(control,input,true); + input.setAttribute("value",control.getTypeAttribute(XMLString.FORM_LABEL)); + setDisabled(control,input); + return input; + } + + private Element createLabel(ControlReader control) { + Element label = converter.createElement("label"); + setCommonAttributes(control,label); + setFor(control,label); + label.setAttribute("value",control.getTypeAttribute(XMLString.FORM_LABEL)); + label.appendChild(converter.createTextNode(control.getTypeAttribute(XMLString.FORM_LABEL))); + return label; + } + + private Element createTextarea(ControlReader control) { + Element textarea = converter.createElement("textarea"); + setCommonAttributes(control,textarea); + setName(control,textarea,true); + setDisabled(control,textarea); + setReadonly(control,textarea); + // rows & cols are required - but css will override them! + textarea.setAttribute("rows","10"); + textarea.setAttribute("cols","5"); + // The value attribute should be used as content + String s = control.getTypeAttribute(XMLString.FORM_VALUE); + if (s!=null) { + textarea.appendChild(converter.createTextNode(s)); + } + return textarea; + } + + private Element createSelect(ControlReader control) { + Element select = converter.createElement("select"); + setCommonAttributes(control,select); + setName(control,select,false); + setSize(control,select); + setMultiple(control,select); + setDisabled(control,select); + // Add options + int nCount = control.getItemCount(); + for (int i=0; iFrameStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public FrameStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ this.styleMap = config.getXFrameStyleMap();
+ this.bConvertStyles = config.xhtmlFrameFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFrameFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlFrameFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFrameFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line
+ */
+ public String getStyleDeclarations(String sIndent) {
+ if (bConvertStyles) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(super.getStyleDeclarations(sIndent));
+ Enumeration names = styleNames.keys();
+ while (names.hasMoreElements()) {
+ String sDisplayName = (String) names.nextElement();
+ StyleWithProperties style = (StyleWithProperties)
+ getStyles().getStyleByDisplayName(sDisplayName);
+ if (!style.isAutomatic()) {
+ // Apply style to paragraphs contained in this frame
+ CSVList props = new CSVList(";");
+ getFrameSc().cssMargins(style,props,true);
+ getParSc().cssPar(style,props,true);
+ getTextSc().cssTextCommon(style,props,true);
+ if (!props.isEmpty()) {
+ buf.append(sIndent)
+ .append(getDefaultTagName(null))
+ .append(".").append(getClassNamePrefix())
+ .append(styleNames.getExportName(sDisplayName))
+ .append(" p {").append(props.toString()).append("}\n");
+ }
+ }
+ }
+ return buf.toString();
+ }
+ else {
+ return "";
+ }
+ }
+
+ /** Return a prefix to be used in generated css class names
+ * @return the prefix
+ */
+ public String getClassNamePrefix() { return "frame"; }
+
+ /** Get the family of frame styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getFrameStyles();
+ }
+
+ /** Create default tag name to represent a frame
+ * @param style to use
+ * @return the tag name.
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "";
+ }
+
+ /** Convert formatting properties for a specific frame style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ cssBox(style,props,bInherit);
+ getTextSc().cssTextCommon(style,props,bInherit); // only in presentations
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // OpenDocument frame properties
+
+ public void cssBox(StyleWithProperties style, CSVList props, boolean bInherit){
+ // translates "box" style properties.
+ // these can be applied to paragraph styles, frame styles and page styles.
+ // The following properties are not supported by CSS2:
+ // style:border-line-width and style:border-line-width-*
+ // TODO: What about shadow?
+ cssMargins(style,props,bInherit);
+ cssBorder(style,props,bInherit);
+ cssPadding(style,props,bInherit);
+ cssBackground(style,props,bInherit);
+ }
+
+ public void cssMargins(StyleWithProperties style, CSVList props, boolean bInherit){
+ // *Absolute* values fit with css
+ String s;
+ if (bInherit || style.getProperty(XMLString.FO_MARGIN_LEFT,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
+ if (s!=null) { props.addValue("margin-left",scale(s)); }
+ else { props.addValue("margin-left","0"); }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_MARGIN_RIGHT,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
+ if (s!=null) { props.addValue("margin-right",scale(s)); }
+ else { props.addValue("margin-right","0"); }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_MARGIN_TOP,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
+ if (s!=null) { props.addValue("margin-top",scale(s)); }
+ else { props.addValue("margin-top","0"); }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_MARGIN_BOTTOM,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
+ if (s!=null) { props.addValue("margin-bottom",scale(s)); }
+ else { props.addValue("margin-bottom","0"); }
+ }
+ }
+
+ public void cssBorder(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Same as in css
+ boolean bHasBorder = false;
+ String s=null;
+ if (bInherit || style.getProperty(XMLString.FO_BORDER,false)!=null) {
+ s = style.getProperty(XMLString.FO_BORDER);
+ }
+ if (s!=null) {
+ props.addValue("border",borderScale(s)); bHasBorder = true;
+ }
+ else { // apply individual borders
+ if (bInherit || style.getProperty(XMLString.FO_BORDER_TOP,false)!=null) {
+ s = style.getProperty(XMLString.FO_BORDER_TOP);
+ if (s!=null) { props.addValue("border-top",borderScale(s)); bHasBorder=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_BORDER_BOTTOM,false)!=null) {
+ s = style.getProperty(XMLString.FO_BORDER_BOTTOM);
+ if (s!=null) { props.addValue("border-bottom",borderScale(s)); bHasBorder=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_BORDER_LEFT,false)!=null) {
+ s = style.getProperty(XMLString.FO_BORDER_LEFT);
+ if (s!=null) { props.addValue("border-left",borderScale(s)); bHasBorder=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_BORDER_RIGHT,false)!=null) {
+ s = style.getProperty(XMLString.FO_BORDER_RIGHT);
+ if (s!=null) { props.addValue("border-right",borderScale(s)); bHasBorder=true; }
+ }
+ }
+ // Default to no border:
+ if (bInherit && !bHasBorder) { props.addValue("border","none"); }
+ }
+
+ public void cssPadding(StyleWithProperties style, CSVList props, boolean bInherit){
+ // *Absolute* values fit with css
+ String s=null;
+ if (bInherit || style.getProperty(XMLString.FO_PADDING,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_PADDING);
+ }
+ if (s!=null) {
+ props.addValue("padding",scale(s));
+ }
+ else { // apply individual paddings
+ boolean bTop = false;
+ boolean bBottom = false;
+ boolean bLeft = false;
+ boolean bRight = false;
+ if (bInherit || style.getProperty(XMLString.FO_PADDING_TOP,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_PADDING_TOP);
+ if (s!=null) { props.addValue("padding-top",scale(s)); bTop=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_PADDING_BOTTOM,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_PADDING_BOTTOM);
+ if (s!=null) { props.addValue("padding-bottom",scale(s)); bBottom=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_PADDING_LEFT,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_PADDING_LEFT);
+ if (s!=null) { props.addValue("padding-left",scale(s)); bLeft=true; }
+ }
+ if (bInherit || style.getProperty(XMLString.FO_PADDING_RIGHT,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_PADDING_RIGHT);
+ if (s!=null) { props.addValue("padding-right",scale(s)); bRight=true; }
+ }
+ if (bInherit) { // must specify padding
+ if (!bTop && !bBottom && !bLeft && !bRight) {
+ props.addValue("padding","0");
+ }
+ else {
+ if (!bTop) { props.addValue("padding-top","0"); }
+ if (!bBottom) { props.addValue("padding-bottom","0"); }
+ if (!bLeft) { props.addValue("padding-left","0"); }
+ if (!bRight) { props.addValue("padding-right","0"); }
+ }
+ }
+ }
+ }
+
+ // parapgrah styles need this for special treatment of background color
+ public void cssBackgroundCommon(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Background image:
+ String sUrl = style.getBackgroundImageProperty(XMLString.XLINK_HREF);
+ if (sUrl!=null) { // currently only support for linked image
+ props.addValue("background-image","url("+escapeUrl(sUrl)+")");
+
+ String sRepeat = style.getBackgroundImageProperty(XMLString.STYLE_REPEAT);
+ if ("no-repeat".equals(sRepeat) || "stretch".equals(sRepeat)) {
+ props.addValue("background-repeat","no-repeat");
+ }
+ else {
+ props.addValue("background-repeat","repeat");
+ }
+
+ String sPosition = style.getBackgroundImageProperty(XMLString.STYLE_POSITION);
+ if (sPosition!=null) { props.addValue("background-position",sPosition); }
+ }
+ }
+
+ public void cssBackground(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Background color: Same as in css
+ String s = style.getProperty(XMLString.FO_BACKGROUND_COLOR,bInherit);
+ if (s!=null) { props.addValue("background-color",s); }
+ cssBackgroundCommon(style,props,bInherit);
+ }
+
+ // Scale the border with while preserving the rest of the attribute
+ public String borderScale(String sBorder) {
+ SimpleInputBuffer in = new SimpleInputBuffer(sBorder);
+ StringBuffer out = new StringBuffer();
+ while (in.peekChar()!='\0') {
+ // Skip spaces
+ while(in.peekChar()==' ') { out.append(" "); in.getChar(); }
+ // If it's a number it must be a unit -> convert it
+ if ('0'<=in.peekChar() && in.peekChar()<='9') {
+ out.append(scale(in.getNumber()+in.getIdentifier()));
+ }
+ // skip other characters
+ while (in.peekChar()!=' ' && in.peekChar()!='\0') {
+ out.append(in.getChar());
+ }
+ }
+ return out.toString();
+ }
+
+ // Must escape certain characters in the url property
+ private String escapeUrl(String sUrl) {
+ StringBuffer buf = new StringBuffer();
+ int nLen = sUrl.length();
+ for (int i=0; iOfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public ListStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ this.styleMap = config.getXListStyleMap();
+ this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ public void applyStyle(int nLevel, String sStyleName, StyleInfo info) {
+ ListStyle style = ofr.getListStyle(sStyleName);
+ if (style!=null) {
+ if (style.isAutomatic()) {
+ applyStyle(nLevel,style.getParentName(),info);
+ if (bConvertHard) { cssList(style,nLevel,info.props); }
+ }
+ else {
+ String sDisplayName = style.getDisplayName();
+ if (styleMap.contains(sDisplayName)) {
+ info.sTagName = styleMap.getElement(sDisplayName);
+ if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
+ info.sClass = styleMap.getCss(sDisplayName);
+ }
+ }
+ else {
+ info.sClass = "listlevel"+Integer.toString(nLevel)
+ +styleNames.getExportName(sDisplayName);
+ }
+ }
+ }
+ }
+
+
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line + */ + public String getStyleDeclarations(String sIndent) { + if (bConvertStyles) { + StringBuffer buf = new StringBuffer(); + Enumeration names = styleNames.keys(); + while (names.hasMoreElements()) { + String sDisplayName = (String) names.nextElement(); + ListStyle style = (ListStyle) + getStyles().getStyleByDisplayName(sDisplayName); + if (!style.isAutomatic()) { + for (int nLevel=1; nLevel<10; nLevel++) { + CSVList props = new CSVList(";"); + cssList(style,nLevel,props); + buf.append(sIndent); + buf.append(".listlevel"); + buf.append(nLevel); + buf.append(styleNames.getExportName(sDisplayName)); + buf.append(" {"); + buf.append(props.toString()); + buf.append("}\n"); + } + } + } + return buf.toString(); + } + else { + return ""; + } + } + + /** Get the family of list styles + * @return the style family + */ + public OfficeStyleFamily getStyles() { + return ofr.getListStyles(); + } + + private void cssList(ListStyle style, int nLevel, CSVList props){ + // translates "list" style properties for a particular level + // Mozilla does not seem to support the "marker" mechanism of CSS2 + // so we will stick with the simpler CSS1-like list style properties + props.addValue("margin-top","0"); + props.addValue("margin-bottom","0"); + String sLevelType = style.getLevelType(nLevel); + if (XMLString.TEXT_LIST_LEVEL_STYLE_NUMBER.equals(sLevelType)) { + // Numbering style, get number format + String sNumFormat = style.getLevelProperty(nLevel,XMLString.STYLE_NUM_FORMAT); + if ("1".equals(sNumFormat)) { props.addValue("list-style-type","decimal"); } + else if ("i".equals(sNumFormat)) { props.addValue("list-style-type","lower-roman"); } + else if ("I".equals(sNumFormat)) { props.addValue("list-style-type","upper-roman"); } + else if ("a".equals(sNumFormat)) { props.addValue("list-style-type","lower-alpha"); } + else if ("A".equals(sNumFormat)) { props.addValue("list-style-type","upper-alpha"); } + } + else if (XMLString.TEXT_LIST_LEVEL_STYLE_BULLET.equals(sLevelType)) { + // Bullet. We can only choose from disc, bullet and square + switch (nLevel % 3) { + case 1: props.addValue("list-style-type","disc"); break; + case 2: props.addValue("list-style-type","bullet"); break; + case 0: props.addValue("list-style-type","square"); break; + } + } + else if (XMLString.TEXT_LIST_LEVEL_STYLE_IMAGE.equals(sLevelType)) { + // Image. TODO: Handle embedded images + String sHref = style.getLevelProperty(nLevel,XMLString.XLINK_HREF); + if (sHref!=null) { props.addValue("list-style-image","url('"+sHref+"')"); } + } + // We don't want floats to pass a list to the left (Mozilla and IE both + //handles this terribly!) + props.addValue("clear:left"); + } + + + +} diff --git a/source/java/writer2latex/xhtml/MathConverter.java b/source/java/writer2latex/xhtml/MathConverter.java new file mode 100644 index 0000000..6c5f29a --- /dev/null +++ b/source/java/writer2latex/xhtml/MathConverter.java @@ -0,0 +1,238 @@ +/************************************************************************ + * + * MathConverter.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2009 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2009-02-19) + * + */ + +package writer2latex.xhtml; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; + +import writer2latex.office.*; + +public class MathConverter extends ConverterHelper { + + private boolean bSupportMathML; + + public MathConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, + boolean bSupportMathML) { + + super(ofr,config,converter); + this.bSupportMathML = bSupportMathML; + } + + public void convert(Node onode, Node hnode) { + if (bSupportMathML) { + convertNode(onode,hnode); + } + else { + Document htmlDOM = hnode.getOwnerDocument(); + NodeList annotationList + = ((Element) onode).getElementsByTagName(XMLString.MATH_ANNOTATION); + if (annotationList.getLength()>0 && annotationList.item(0).hasChildNodes()) { + // Insert the StarMath annotation as a kbd element + Element kbd = htmlDOM.createElement("kbd"); + hnode.appendChild(kbd); + NodeList list = annotationList.item(0).getChildNodes(); + int nLen = list.getLength(); + for (int i=0; iThis package contains xhtml specific code.
+It contains a writerlatex.api.Converter
implementation for
+conversion into xhtml and xhtml+MathML.
Since version 1.0 you can build Writer2LaTeX without this package if you +don't need xhtml support.
+ + diff --git a/source/java/writer2latex/xhtml/PageStyleConverter.java b/source/java/writer2latex/xhtml/PageStyleConverter.java new file mode 100644 index 0000000..67adc28 --- /dev/null +++ b/source/java/writer2latex/xhtml/PageStyleConverter.java @@ -0,0 +1,137 @@ +/************************************************************************ + * + * PageStyleConverter.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-09-08) + * + */ + +package writer2latex.xhtml; + +import java.util.Enumeration; + +import writer2latex.office.MasterPage; +import writer2latex.office.OfficeReader; +import writer2latex.office.OfficeStyleFamily; +import writer2latex.office.PageLayout; +import writer2latex.office.StyleWithProperties; +import writer2latex.office.XMLString; +import writer2latex.util.CSVList; + +/** + * This class converts OpenDocument page styles to CSS2 styles. + * A page style in a presentation is represented through the master page, + * which links to a page layout defining the geometry and optionally a drawing + * page defining the drawing background. + * In a presentation document we export the full page style, in a text + * document we only export the background. + */ +public class PageStyleConverter extends StyleConverterHelper { + + /** Create a newPageStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public PageStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ }
+
+ public void applyStyle(String sStyleName, StyleInfo info) {
+ MasterPage masterPage = ofr.getMasterPage(sStyleName);
+ String sDisplayName = masterPage.getDisplayName();
+ if (masterPage!=null) {
+ if (ofr.isPresentation()) {
+ // Always generates class name
+ info.sClass="masterpage"+styleNames.getExportName(sDisplayName);
+ }
+ else {
+ // For text documents only writing direction and background
+ String sPageLayout = masterPage.getPageLayoutName();
+ PageLayout pageLayout = ofr.getPageLayout(sPageLayout);
+ if (pageLayout!=null) {
+ applyDirection(pageLayout,info);
+ if (bConvertStyles) {
+ getFrameSc().cssBackground(pageLayout,info.props,true);
+ }
+ }
+ }
+ }
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line
+ */
+ public String getStyleDeclarations(String sIndent) {
+ StringBuffer buf = new StringBuffer();
+ Enumeration names = styleNames.keys();
+ while (names.hasMoreElements()) {
+ // This will be master pages for presentations only
+ String sDisplayName = (String) names.nextElement();
+ MasterPage style = (MasterPage)
+ getStyles().getStyleByDisplayName(sDisplayName);
+ StyleInfo info = new StyleInfo();
+ // First apply page layout (size)
+ PageLayout pageLayout = ofr.getPageLayout(style.getPageLayoutName());
+ if (pageLayout!=null) {
+ applyDirection(pageLayout,info);
+ cssPageSize(pageLayout,info.props);
+ getFrameSc().cssBackground(pageLayout,info.props,true);
+ }
+ // Next apply drawing-page style (draw background)
+ StyleWithProperties drawingPage = ofr.getDrawingPageStyle(style.getProperty(XMLString.DRAW_STYLE_NAME));
+ if (drawingPage!=null) {
+ cssDrawBackground(drawingPage,info.props,true);
+ }
+ // The export the results
+ buf.append(sIndent)
+ .append(".masterpage").append(styleNames.getExportName(sDisplayName))
+ .append(" {").append(info.props.toString()).append("}\n");
+ }
+ return buf.toString();
+ }
+
+ /** Get the family of page styles (master pages)
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getMasterPages();
+ }
+
+ // Background properties in draw: Color, gradient, hatching or bitmap
+ private void cssDrawBackground(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Fill color: Same as in css
+ String s = style.getProperty(XMLString.DRAW_FILL_COLOR,bInherit);
+ if (s!=null) { props.addValue("background-color",s); }
+ }
+
+
+ private void cssPageSize(PageLayout style, CSVList props) {
+ String sWidth = style.getProperty(XMLString.FO_PAGE_WIDTH);
+ if (sWidth!=null) { props.addValue("width",scale(sWidth)); }
+ String sHeight = style.getProperty(XMLString.FO_PAGE_HEIGHT);
+ if (sHeight!=null) { props.addValue("height",scale(sHeight)); }
+ }
+
+
+
+}
diff --git a/source/java/writer2latex/xhtml/ParStyleConverter.java b/source/java/writer2latex/xhtml/ParStyleConverter.java
new file mode 100644
index 0000000..267f2b7
--- /dev/null
+++ b/source/java/writer2latex/xhtml/ParStyleConverter.java
@@ -0,0 +1,195 @@
+/************************************************************************
+ *
+ * ParStyleConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-09-08)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import writer2latex.office.OfficeReader;
+import writer2latex.office.OfficeStyleFamily;
+import writer2latex.office.StyleWithProperties;
+import writer2latex.office.XMLString;
+import writer2latex.util.CSVList;
+
+ /*
+ TODO: drop caps (contained in a child of the style:properties element)
+ The CSS attributes should be applied to the :first-letter
+ pseudo-element or to an additional inline element.
+ */
+
+
+/**
+ * This class converts OpenDocument paragraph styles to CSS2 styles for
+ * use in paragraphs and headings.
+ * This also includes conversion of paragraph properties in other styles
+ * (cell styles).
+ */
+public class ParStyleConverter extends StyleWithPropertiesConverterHelper {
+
+ // Some bookkeeping for headings
+ private String[] sHeadingStyles = new String[7];
+
+ /** Create a new ParStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public ParStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ this.styleMap = config.getXParStyleMap();
+ this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ // TODO: Remove me, OfficeReader takes care of this
+ public void setHeadingStyle(int nLevel, String sStyleName) {
+ if (sHeadingStyles[nLevel]==null) {
+ sHeadingStyles[nLevel] = sStyleName;
+ }
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line
+ */
+ public String getStyleDeclarations(String sIndent) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(super.getStyleDeclarations(sIndent));
+ if (bConvertStyles) {
+ // Styles for headings
+ for (int i=1; i<=6; i++) {
+ if (sHeadingStyles[i]!=null) {
+ StyleWithProperties style = ofr.getParStyle(sHeadingStyles[i]);
+ if (style!=null) {
+ CSVList props = new CSVList(";");
+ applyProperties(style,props,true);
+ props.addValue("clear","left");
+ buf.append(sIndent).append("h").append(i)
+ .append(" {").append(props.toString()).append("}\n");
+ }
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ /** Get the family of paragraph styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getParStyles();
+ }
+
+ /** Create default tag name to represent a paragraph
+ * @param style to use
+ * @return the tag name.
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "p";
+ }
+
+ /** Convert formatting properties for a specific Par style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ getFrameSc().cssMargins(style,props,bInherit);
+ getFrameSc().cssBorder(style,props,bInherit);
+ getFrameSc().cssPadding(style,props,bInherit);
+ getFrameSc().cssBackgroundCommon(style,props,bInherit);
+ cssPar(style,props,bInherit);
+ getTextSc().cssTextCommon(style,props,bInherit);
+ }
+
+ public String getTextBackground(String sStyleName) {
+ CSVList props = new CSVList(";");
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ if (style!=null) {
+ getTextSc().cssTextBackground(style,props,true);
+ }
+ return props.toString();
+ }
+
+ // TODO: get rid of this
+ public String getRealParStyleName(String sStyleName) {
+ if (sStyleName==null) { return sStyleName; }
+ StyleWithProperties style = ofr.getParStyle(sStyleName);
+ if (style==null || !style.isAutomatic()) { return sStyleName; }
+ return style.getParentName();
+ }
+
+ public void cssPar(StyleWithProperties style, CSVList props, boolean bInherit){
+ String s;
+
+ // translates paragraph style properties.
+ // The following properties are not supported by CSS2:
+ // style:justify-single-word and style:text-align-last
+
+/* problem: 120% times normal makes no sense...
+ s = style.getProperty(XMLString.FO_LINE_HEIGHT);
+ if (s!=null && s.equals("normal")) {
+ props.addValue("line-height:normal;";
+ }
+ else { // length or percentage
+ s = style.getAbsoluteProperty(XMLString.FO_LINE_HEIGHT);
+ if (s!=null) { props.addValue("line-height",s); }
+ }
+ */
+ // TODO: style:line-height-at-least and stype:line-spacing
+
+ // Background color fits with css (note: Paragraph property!)
+ s = style.getParProperty(XMLString.FO_BACKGROUND_COLOR,bInherit);
+ if (s!=null) { props.addValue("background-color",s); }
+
+ // Indentation: Absolute values of this property fit with css...
+ if (bInherit || style.getProperty(XMLString.FO_TEXT_INDENT,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_TEXT_INDENT);
+ if (s!=null) {
+ props.addValue("text-indent",scale(s));
+ }
+ else { // ... but css doesn't have this one
+ s = style.getProperty(XMLString.STYLE_AUTO_TEXT_INDENT);
+ if ("true".equals(s)) { props.addValue("text-indent","2em"); }
+ }
+ }
+
+ // Alignment: This property fit with css, but two values have different names
+ s = style.getProperty(XMLString.FO_TEXT_ALIGN,bInherit);
+ if (s!=null) { // rename two property values:
+ if (s.equals("start")) { s="left"; }
+ else if (s.equals("end")) { s="right"; }
+ props.addValue("text-align",s);
+ }
+
+ // Wrap (only in table cells, only in spreadsheets):
+ if (ofr.isSpreadsheet()) {
+ s = style.getProperty(XMLString.FO_WRAP_OPTION,bInherit);
+ if ("no-wrap".equals(s)) props.addValue("white-space","nowrap");
+ else if ("wrap".equals(s)) props.addValue("white-space","normal");
+ }
+ }
+
+
+}
diff --git a/source/java/writer2latex/xhtml/PresentationStyleConverter.java b/source/java/writer2latex/xhtml/PresentationStyleConverter.java
new file mode 100644
index 0000000..e2312a4
--- /dev/null
+++ b/source/java/writer2latex/xhtml/PresentationStyleConverter.java
@@ -0,0 +1,157 @@
+/************************************************************************
+ *
+ * PresentationStyleConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import writer2latex.office.OfficeReader;
+import writer2latex.office.OfficeStyleFamily;
+import writer2latex.office.StyleWithProperties;
+//import writer2latex.office.XMLString;
+import writer2latex.util.CSVList;
+import writer2latex.util.ExportNameCollection;
+
+/**
+ * This class converts OpenDocument presentation styles to CSS2 styles.
+ * Presentation styles are special frame styles, used to style the standard
+ * elements in a presentation (title, subtitle and textbox)
+ */
+public class PresentationStyleConverter extends FrameStyleConverter {
+
+ // Data about outline styles
+ String sCurrentOutlineStyle = null;
+ Hashtable outlineStyles = new Hashtable();
+ ExportNameCollection outlineStyleNames = new ExportNameCollection(true);
+
+ /** Create a new PresentationStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public PresentationStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ // style maps for presentations are currently not supported:
+ this.styleMap = new XhtmlStyleMap();
+ }
+
+ /** Return a prefix to be used in generated css class names
+ * @return the prefix
+ */
+ public String getClassNamePrefix() { return "prsnt"; }
+
+ /** Get the family of presentation styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getPresentationStyles();
+ }
+
+ /** Create default tag name to represent a presentation object
+ * @param style to use
+ * @return the tag name.
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "div";
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line + */ + public String getStyleDeclarations(String sIndent) { + if (bConvertStyles) { + StringBuffer buf = new StringBuffer(); + buf.append(super.getStyleDeclarations(sIndent)); + Enumeration names = outlineStyleNames.keys(); + while (names.hasMoreElements()) { + String sDisplayName = (String) names.nextElement(); + StyleWithProperties style = (StyleWithProperties) + getStyles().getStyleByDisplayName(sDisplayName); + if (!style.isAutomatic()) { + // Apply style to paragraphs within a list item with this class + CSVList props = new CSVList(";"); + getFrameSc().cssMargins(style,props,true); + getParSc().cssPar(style,props,true); + getTextSc().cssTextCommon(style,props,true); + if (!props.isEmpty()) { + buf.append(sIndent) + .append("li.outline") + .append(styleNames.getExportName(sDisplayName)) + .append(" p {").append(props.toString()).append("}\n"); + } + } + } + return buf.toString(); + } + else { + return ""; + } + } + + + public void enterOutline(String sStyleName) { + sCurrentOutlineStyle = sStyleName; + if (!outlineStyles.containsKey(sCurrentOutlineStyle)) { + String[] sNames = new String[10]; + outlineStyles.put(sCurrentOutlineStyle,sNames); + StyleWithProperties style1 = ofr.getPresentationStyle(sCurrentOutlineStyle); + if (style1!=null) { + String sCurrentOutlineStyle1 = sCurrentOutlineStyle; + if (style1.isAutomatic()) { sCurrentOutlineStyle1 = style1.getParentName(); } + sNames[1] = sCurrentOutlineStyle1; + String sBaseName = sCurrentOutlineStyle1.substring(0,sCurrentOutlineStyle1.length()-1); + for (int i=2; i<10; i++) { + String sName = sBaseName + Integer.toString(i); + StyleWithProperties style = ofr.getPresentationStyle(sName); + if (style!=null && style.getParentName().equals(sNames[i-1])) { + sNames[i] = sName; + } + else { + break; + } + } + sNames[1] = null; + } + } + } + + public void exitOutline() { + sCurrentOutlineStyle = null; + } + + public void applyOutlineStyle(int nLevel, StyleInfo info) { + if (2<=nLevel && nLevel<=9 && sCurrentOutlineStyle!=null) { + if (outlineStyles.containsKey(sCurrentOutlineStyle)) { + info.sClass = "outline"+outlineStyleNames.getExportName(((String[]) outlineStyles.get(sCurrentOutlineStyle))[nLevel]); + } + } + } + + + +} diff --git a/source/java/writer2latex/xhtml/RowStyleConverter.java b/source/java/writer2latex/xhtml/RowStyleConverter.java new file mode 100644 index 0000000..af20959 --- /dev/null +++ b/source/java/writer2latex/xhtml/RowStyleConverter.java @@ -0,0 +1,80 @@ +/************************************************************************ + * + * RowStyleConverter.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-22) + * + */ + +package writer2latex.xhtml; + +import writer2latex.office.OfficeReader; +import writer2latex.office.OfficeStyleFamily; +import writer2latex.office.StyleWithProperties; +//import writer2latex.office.XMLString; +import writer2latex.util.CSVList; + +/** + * This class converts OpenDocument row styles to CSS2 styles. + * Rows formatting includes background, and also height, + * which is considered elsewhere. + */ +public class RowStyleConverter extends StyleWithPropertiesConverterHelper { + + /** Create a newRowStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public RowStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ // Style maps for rows are currently not supported.
+ this.styleMap = new XhtmlStyleMap();
+ this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Get the family of row styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getRowStyles();
+ }
+
+ /** Create default tag name to represent a row object
+ * @param style to use
+ * @return the tag name.
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "tr";
+ }
+
+ /** Convert formatting properties for a specific Row style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ getFrameSc().cssBackground(style,props,bInherit);
+ }
+
+}
diff --git a/source/java/writer2latex/xhtml/SectionStyleConverter.java b/source/java/writer2latex/xhtml/SectionStyleConverter.java
new file mode 100644
index 0000000..919cd26
--- /dev/null
+++ b/source/java/writer2latex/xhtml/SectionStyleConverter.java
@@ -0,0 +1,84 @@
+/************************************************************************
+ *
+ * SectionStyleConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import writer2latex.office.OfficeReader;
+import writer2latex.office.OfficeStyleFamily;
+import writer2latex.office.StyleWithProperties;
+//import writer2latex.office.XMLString;
+import writer2latex.util.CSVList;
+
+/**
+ * This class converts OpenDocument section styles to CSS2 styles.
+ * Sections are formatted using (a subset of) box properties and with columns.
+ * The latter would require css3 to be converted (column-count property)
+ */
+public class SectionStyleConverter extends StyleWithPropertiesConverterHelper {
+
+ /** Create a new SectionStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public SectionStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ // Style maps for sections are currently not supported.
+ // (Section styles are not supported by OOo yet)
+ this.styleMap = new XhtmlStyleMap();
+ this.bConvertStyles = config.xhtmlSectionFormatting()==XhtmlConfig.CONVERT_ALL
+ || config.xhtmlSectionFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlSectionFormatting()==XhtmlConfig.CONVERT_ALL
+ || config.xhtmlSectionFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Get the family of section styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getSectionStyles();
+ }
+
+ /** Create default tag name to represent a section object
+ * @param style to use + * @return the tag name. If the style is null, a default result should be + * returned. + */ + public String getDefaultTagName(StyleWithProperties style) { + return "div"; + } + + /**Convert formatting properties for a specific section style.
+ * @param style the style to convert + * @param props theCSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ getFrameSc().cssBox(style,props,bInherit);
+ }
+
+}
diff --git a/source/java/writer2latex/xhtml/StyleConverter.java b/source/java/writer2latex/xhtml/StyleConverter.java
new file mode 100644
index 0000000..3ff1660
--- /dev/null
+++ b/source/java/writer2latex/xhtml/StyleConverter.java
@@ -0,0 +1,175 @@
+/************************************************************************
+ *
+ * StyleConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.xhtml;
+
+//import java.util.Enumeration;
+//import java.util.Hashtable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import writer2latex.office.*;
+import writer2latex.util.*;
+
+/**
+ * This class converts OpenDocument styles to CSS2 styles.
+ *Note that some elements in OpenDocument has attributes that also maps + * to CSS2 properties. Example: the width of a text box.
+ *Also note, that some OpenDocument style properties cannot be mapped to + * CSS2 without creating an additional inline element.
+ *The class uses one helper class per OpenDocument style family + * (paragraph, frame etc.)
+ */ +class StyleConverter extends ConverterHelper { + + // Helpers for text styles + private TextStyleConverter textSc; + private ParStyleConverter parSc; + private ListStyleConverter listSc; + private SectionStyleConverter sectionSc; + + // Helpers for table styles + private TableStyleConverter tableSc; + private RowStyleConverter rowSc; + private CellStyleConverter cellSc; + + // Helpers for drawing styles + private FrameStyleConverter frameSc; + private PresentationStyleConverter presentationSc; + + // Helper for page styles + private PageStyleConverter pageSc; + + /**Create a new StyleConverter
This is an abstract base class to convert an OpenDocument style family to + * CSS2 styles.
+ */ +public abstract class StyleConverterHelper extends ConverterHelper { + + // Translation of OpenDocument style names to CSS class names + protected ExportNameCollection styleNames = new ExportNameCollection(true); + + // Style map to use + protected XhtmlStyleMap styleMap; + + // Should we convert styles resp. hard formatting? + protected boolean bConvertStyles = true; + protected boolean bConvertHard = true; + + // The type of xhtml document + protected int nType; + + // Scaling and unit transformation to use + private String sScale; + private String sColScale; + private boolean bConvertToPx; + + /** Create a newStyleConverterHelper
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public StyleConverterHelper(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter);
+ this.nType = nType;
+ sScale = config.getXhtmlScaling();
+ sColScale = config.getXhtmlColumnScaling();
+ bConvertToPx = config.xhtmlConvertToPx();
+ }
+
+ protected String scale(String s) {
+ if (bConvertToPx) {
+ return Misc.length2px(Misc.multiply(sScale,s));
+ }
+ else {
+ return Misc.multiply(sScale,s);
+ }
+ }
+
+ protected String colScale(String s) {
+ return scale(Misc.multiply(sColScale,s));
+ }
+
+ /** Apply the writing direction (ltr or rtl) attribute from a style
+ * @param style the OpenDocument style to use
+ * @param info the StyleInfo
object to add information to
+ */
+ protected static void applyDirection(StyleWithProperties style, StyleInfo info) {
+ String sDir = style.getProperty(XMLString.STYLE_WRITING_MODE);
+ if ("lr-tb".equals(sDir)) { info.sDir="ltr"; }
+ else if ("rl-tb".equals(sDir)) { info.sDir="rtl"; }
+ }
+
+ /** Apply language+country from a style
+ * @param style the OpenDocument style to use
+ * @param info the StyleInfo
object to add information to
+ */
+ protected static void applyLang(StyleWithProperties style, StyleInfo info) {
+ String sLang = style.getProperty(XMLString.FO_LANGUAGE);
+ String sCountry = style.getProperty(XMLString.FO_COUNTRY);
+ if (sLang!=null) {
+ if (sCountry==null) { info.sLang = sLang; }
+ else { info.sLang = sLang+"-"+sCountry; }
+ }
+ }
+
+ /** Get the OpenDocument style family associated with this
+ * StyleConverterHelper
+ * @return the style family
+ */
+ public abstract OfficeStyleFamily getStyles();
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line + */ + public abstract String getStyleDeclarations(String sIndent); + +} diff --git a/source/java/writer2latex/xhtml/StyleInfo.java b/source/java/writer2latex/xhtml/StyleInfo.java new file mode 100644 index 0000000..bf5d911 --- /dev/null +++ b/source/java/writer2latex/xhtml/StyleInfo.java @@ -0,0 +1,41 @@ +/************************************************************************ + * + * StyleInfo.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2007 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.5 (2007-02-27) + * + */ + +package writer2latex.xhtml; + +import writer2latex.util.CSVList; + +public class StyleInfo { + public String sTagName = null; + public String sClass = null; + public CSVList props = new CSVList(";"); + public String sLang = null; + public String sDir = null; + + public boolean hasAttributes() { + return !props.isEmpty() || sClass!=null || sLang!=null || sDir!=null; + } +} diff --git a/source/java/writer2latex/xhtml/StyleWithPropertiesConverterHelper.java b/source/java/writer2latex/xhtml/StyleWithPropertiesConverterHelper.java new file mode 100644 index 0000000..133ddfd --- /dev/null +++ b/source/java/writer2latex/xhtml/StyleWithPropertiesConverterHelper.java @@ -0,0 +1,144 @@ +/************************************************************************ + * + * StyleWithPropertiesConverterHelper.java + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright: 2002-2008 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.0 (2008-11-22) + * + */ + +package writer2latex.xhtml; + +import java.util.Enumeration; +//import java.util.Hashtable; + +//import writer2latex.latex.util.Info; +import writer2latex.office.OfficeReader; +import writer2latex.office.StyleWithProperties; +import writer2latex.util.CSVList; +//import writer2latex.util.ExportNameCollection; + +/** + *This is an abstract class to convert an OpenDocument style family
+ * represented by StyleWithProperties
to CSS2 styles.
StyleWithPropertiesConverterHelper
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public StyleWithPropertiesConverterHelper(OfficeReader ofr, XhtmlConfig config,
+ Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ }
+
+ /** Apply a style, either by converting the style or by applying the
+ * style map from the configuarion
+ * @param sStyleName name of the OpenDocument style
+ * @param info the StyleInfo
object to add information to
+ */
+ public void applyStyle(String sStyleName, StyleInfo info) {
+ StyleWithProperties style = (StyleWithProperties) getStyles().getStyle(sStyleName);
+ info.sTagName = getDefaultTagName(style);
+ if (style!=null) {
+ applyLang(style,info);
+ applyDirection(style,info);
+ if (style.isAutomatic()) {
+ // Apply parent style + hard formatting
+ applyStyle(style.getParentName(),info);
+ if (bConvertHard) { applyProperties(style,info.props,false); }
+ }
+ else {
+ String sDisplayName = style.getDisplayName();
+ if (styleMap.contains(sDisplayName)) {
+ // Apply attributes as specified in style map from user
+ info.sTagName = styleMap.getElement(sDisplayName);
+ if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
+ info.sClass = styleMap.getCss(sDisplayName);
+ }
+ }
+ else {
+ // Generate class name from display name
+ info.sClass = getClassNamePrefix()
+ + styleNames.getExportName(sDisplayName);
+ }
+ }
+ }
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line
+ */
+ public String getStyleDeclarations(String sIndent) {
+ if (bConvertStyles) {
+ StringBuffer buf = new StringBuffer();
+ Enumeration names = styleNames.keys();
+ while (names.hasMoreElements()) {
+ String sDisplayName = (String) names.nextElement();
+ StyleWithProperties style = (StyleWithProperties)
+ getStyles().getStyleByDisplayName(sDisplayName);
+ if (!style.isAutomatic()) {
+ CSVList props = new CSVList(";");
+ applyProperties(style,props,true);
+ buf.append(sIndent);
+ buf.append(getDefaultTagName(null));
+ buf.append(".");
+ buf.append(getClassNamePrefix());
+ buf.append(styleNames.getExportName(sDisplayName));
+ buf.append(" {");
+ buf.append(props.toString());
+ buf.append("}\n");
+ // TODO: Create a method "getStyleDeclarationsInner"
+ // to be used by eg. FrameStyleConverter
+ }
+ }
+ return buf.toString();
+ }
+ else {
+ return "";
+ }
+ }
+
+ /** Return a prefix to be used in generated css class names
+ * @return the prefix
+ */
+ public String getClassNamePrefix() { return ""; }
+
+ /** Create default tag name to represent a specific style, e.g.
+ * span
(text style) or ul
(unordered list)
+ * @param style to use
+ * @return the tag name. If the style is null, a default result should be
+ * returned.
+ */
+ public abstract String getDefaultTagName(StyleWithProperties style);
+
+ /** Convert formatting properties for a specific style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public abstract void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit);
+
+
+}
diff --git a/source/java/writer2latex/xhtml/TableConverter.java b/source/java/writer2latex/xhtml/TableConverter.java
new file mode 100644
index 0000000..474efea
--- /dev/null
+++ b/source/java/writer2latex/xhtml/TableConverter.java
@@ -0,0 +1,453 @@
+/************************************************************************
+ *
+ * TableConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-12-15)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import java.util.Vector;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+
+import writer2latex.util.Misc;
+import writer2latex.util.SimpleInputBuffer;
+import writer2latex.office.XMLString;
+import writer2latex.office.StyleWithProperties;
+import writer2latex.office.OfficeReader;
+//import writer2latex.office.TableLine;
+import writer2latex.office.TableRange;
+import writer2latex.office.TableReader;
+import writer2latex.office.TableView;
+
+public class TableConverter extends ConverterHelper {
+
+ // The collection of all table names
+ // TODO: Navigation should be handled here rather than in Converter.java
+ protected Vector sheetNames = new Vector();
+
+ public TableConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
+ super(ofr,config,converter);
+ }
+
+ /** Converts an office node as a complete table (spreadsheet) document
+ *
+ * @param onode the Office node containing the content to convert
+ */
+ public void convertTableContent(Element onode) {
+ Element hnode = null;
+ if (!onode.hasChildNodes()) { return; }
+ if (!config.xhtmlCalcSplit()) { hnode = nextOutFile(); }
+ NodeList nList = onode.getChildNodes();
+ int nLen = nList.getLength();
+ for (int i=0; iTableStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public TableStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ // Style maps for tables are currently not supported.
+ this.styleMap = new XhtmlStyleMap();
+ this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Get the family of table styles
+ * @return the style family
+ */
+ public OfficeStyleFamily getStyles() {
+ return ofr.getTableStyles();
+ }
+
+ /** Create default tag name to represent a table object
+ * @param style to use
+ * @return the tag name
+ */
+ public String getDefaultTagName(StyleWithProperties style) {
+ return "table";
+ }
+
+ /** Convert formatting properties for a specific table style.
+ * @param style the style to convert
+ * @param props the CSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ // Apply background
+ getFrameSc().cssBackground(style,props,bInherit);
+ // Table-specific properties
+ cssTable(style,props,bInherit);
+ }
+
+ private void cssTable(StyleWithProperties style, CSVList props, boolean bInherit){
+ // Top and bottom margins
+ String sMarginTop = style.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
+ if (sMarginTop!=null) { props.addValue("margin-top",scale(sMarginTop)); }
+ else { props.addValue("margin-top","0"); }
+
+ String sMarginBottom = style.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
+ if (sMarginBottom!=null) { props.addValue("margin-bottom",scale(sMarginBottom)); }
+ else { props.addValue("margin-bottom","0"); }
+
+ // Left and right margins and horizontal alignment
+ String sAlign = style.getProperty(XMLString.TABLE_ALIGN);
+ String sMarginLeft = style.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
+ if (sMarginLeft!=null) { sMarginLeft = scale(sMarginLeft); }
+ String sMarginRight = style.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
+ if (sMarginRight!=null) { sMarginRight = scale(sMarginRight); }
+
+ if ("center".equals(sAlign)) {
+ sMarginLeft = "auto"; sMarginRight = "auto";
+ }
+ else if ("right".equals(sAlign)) {
+ sMarginLeft = "auto";
+ }
+ else if ("left".equals(sAlign)) {
+ sMarginRight = "auto";
+ }
+
+ if (sMarginLeft!=null) { props.addValue("margin-left",sMarginLeft); }
+ if (sMarginRight!=null) { props.addValue("margin-right",sMarginRight); }
+ }
+
+}
diff --git a/source/java/writer2latex/xhtml/TextConverter.java b/source/java/writer2latex/xhtml/TextConverter.java
new file mode 100644
index 0000000..636a896
--- /dev/null
+++ b/source/java/writer2latex/xhtml/TextConverter.java
@@ -0,0 +1,1811 @@
+/************************************************************************
+ *
+ * TextConverter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-22)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.LinkedList;
+import java.util.Locale;
+
+import java.text.Collator;
+
+//import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+
+import writer2latex.util.Misc;
+import writer2latex.office.XMLString;
+import writer2latex.office.IndexMark;
+import writer2latex.office.ListCounter;
+import writer2latex.office.ListStyle;
+import writer2latex.office.PropertySet;
+import writer2latex.office.StyleWithProperties;
+import writer2latex.office.OfficeReader;
+import writer2latex.office.TocReader;
+
+// Helper class (a struct) to contain information about an alphabetical
+// index entry.
+final class AlphabeticalEntry {
+ String sWord; // the word for the index
+ int nIndex; // the original index of this entry
+}
+
+// Helper class (a struct) to contain information about a toc entry
+// (ie. a heading, other paragraph or toc-mark)
+final class TocEntry {
+ Element onode; // the original node
+ String sLabel = null; // generated label for the entry
+ int nFileIndex; // the file index for the generated content
+ int nOutlineLevel; // the outline level for this heading
+ int[] nOutlineNumber; // the natural outline number for this heading
+}
+
+// Helper class (a struct) to point back to indexes that should be processed
+final class IndexData {
+ int nOutFileIndex; // the index of the out file containing the index
+ Element onode; // the original node
+ Element chapter; // the chapter containing this toc
+ Element hnode; // a div node where the index should be added
+}
+
+public class TextConverter extends ConverterHelper {
+
+ // Data used to handle splitting over several files
+ // TODO: Accessor methods for sections
+ int nSplit = 0; // The outline level at which to split files (0=no split)
+ int nRepeatLevels = 5; // The number of levels to repeat when splitting (0=no repeat)
+ private int nLastSplitLevel = 1; // The outline level at which the last split occured
+ private int nDontSplitLevel = 0; // if > 0 splitting is forbidden
+ boolean bAfterHeading=false; // last element was a top level heading
+ protected Stack sections = new Stack(); // stack of nested sections
+ Element[] currentHeading = new Element[7]; // Last headings (repeated when splitting)
+
+ // Counters for generated numbers
+ private ListCounter outlineNumbering;
+ private Hashtable listCounters = new Hashtable();
+ private String sCurrentListLabel = null;
+
+ // Mode used to handle floats (depends on source doc type and config)
+ private int nFloatMode;
+
+ // Data used for index bookkeeping
+ private Vector indexes = new Vector();
+
+ // Data used to handle Alphabetical Index
+ Vector index = new Vector(); // All words for the index
+ private int nIndexIndex = -1; // Current index used for id's (of form idxN)
+ private int nAlphabeticalIndex = -1; // File containing alphabetical index
+
+ // Data used to handle Table of Contents
+ private Vector tocEntries = new Vector(); // All potential(!) toc items
+ private int nTocFileIndex = -1; // file index for main toc
+ private Element currentChapter = null; // Node for the current chapter (level 1) heading
+ private int nTocIndex = -1; // Current index for id's (of form tocN)
+ private ListCounter naturalOutline = new ListCounter(); // Current "natural" outline number
+
+ // Style names for foot- and endnotes
+ private String sFntCitBodyStyle = null;
+ private String sFntCitStyle = null;
+ private String sEntCitBodyStyle = null;
+ private String sEntCitStyle = null;
+
+ // Gather the footnotes and endnotes
+ private LinkedList footnotes = new LinkedList();
+ private LinkedList endnotes = new LinkedList();
+
+ // Sometimes we have to create an inlinenode in a block context
+ // (labels for footnotes and endnotes)
+ // We put it here and insert it in the first paragraph/heading to come:
+ private Node asapNode = null;
+
+ // When generating toc, a few things should be done differently
+ private boolean bInToc = false;
+
+ public TextConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
+ super(ofr,config,converter);
+ nSplit = config.getXhtmlSplitLevel();
+ nRepeatLevels = config.getXhtmlRepeatLevels();
+ nFloatMode = ofr.isText() && config.xhtmlFloatObjects() ?
+ DrawConverter.FLOATING : DrawConverter.ABSOLUTE;
+ outlineNumbering = new ListCounter(ofr.getOutlineStyle());
+ // Styles for footnotes and endnotes
+ PropertySet notes = ofr.getFootnotesConfiguration();
+ if (notes!=null) {
+ sFntCitBodyStyle = notes.getProperty(XMLString.TEXT_CITATION_BODY_STYLE_NAME);
+ sFntCitStyle = notes.getProperty(XMLString.TEXT_CITATION_STYLE_NAME);
+ }
+ notes = ofr.getEndnotesConfiguration();
+ if (notes!=null) {
+ sEntCitBodyStyle = notes.getProperty(XMLString.TEXT_CITATION_BODY_STYLE_NAME);
+ sEntCitStyle = notes.getProperty(XMLString.TEXT_CITATION_STYLE_NAME);
+ }
+ }
+
+ /** Converts an office node as a complete text document
+ *
+ * @param onode the Office node containing the content to convert
+ */
+ public void convertTextContent(Element onode) {
+ Element hnode = converter.nextOutFile();
+
+ // Create form
+ if (nSplit==0) {
+ Element form = getDrawCv().createForm();
+ if (form!=null) {
+ hnode.appendChild(form);
+ hnode = form;
+ }
+ }
+
+ // Convert content
+ traverseBlockText(onode,hnode);
+
+ // Generate all indexes
+ int nIndexCount = indexes.size();
+ for (int i=0; iTextStyleConverter
+ * @param ofr an OfficeReader
to read style information from
+ * @param config the configuration to use
+ * @param converter the main Converter
class
+ * @param nType the type of xhtml to use
+ */
+ public TextStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
+ super(ofr,config,converter,nType);
+ this.styleMap = config.getXTextStyleMap();
+ this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
+ this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
+ }
+
+ /** Apply a link style, using a combination of two text styles
+ * @param sStyleName name of the OpenDocument style
+ * @param sVisitedStyleName name of the OpenDocument style for visited links
+ * @param info the StyleInfo
object to add information to
+ */
+ public void applyAnchorStyle(String sStyleName, String sVisitedStyleName,
+ StyleInfo info) {
+ if (sStyleName==null || sVisitedStyleName==null) { return; }
+ if (sStyleName.length()==0 || sVisitedStyleName.length()==0) { return; }
+ // Look for a style map
+ String sDisplayName = ofr.getTextStyles().getDisplayName(sStyleName);
+ if (styleMap.contains(sDisplayName)) { // class name from config
+ if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
+ info.sClass = styleMap.getCss(sDisplayName);
+ }
+ return;
+ }
+
+ String sName = sStyleName+sVisitedStyleName;
+ if (!anchorCombinedStyleNames.containsKey(sName)) {
+ String sExportName;
+ // This combination is not seen before, but the base style may be known
+ // In that case, use the visited style name as well
+ if (anchorStyleNames.containsName(sStyleName)) {
+ sExportName = anchorStyleNames.getExportName(sStyleName)
+ +anchorVisitedStyleNames.getExportName(sVisitedStyleName);
+ }
+ else {
+ sExportName = anchorStyleNames.getExportName(sStyleName);
+ }
+ anchorCombinedStyleNames.put(sName,sExportName);
+ orgAnchorStyleNames.put(sExportName,sStyleName);
+ orgAnchorVisitedStyleNames.put(sExportName,sVisitedStyleName);
+ }
+ info.sClass = (String)anchorCombinedStyleNames.get(sName);
+ }
+
+ /** Convert style information for used styles
+ * @param sIndent a String of spaces to add before each line + */ + public String getStyleDeclarations(String sIndent) { + StringBuffer buf = new StringBuffer(); + buf.append(super.getStyleDeclarations(sIndent)); + if (bConvertStyles) { + // Export anchor styles + // Default is always the styles "Internet link" and "Visited Internet Link"(?) + StyleWithProperties defaultLinkStyle = (StyleWithProperties) + getStyles().getStyleByDisplayName(DEFAULT_LINK_STYLE); + if (defaultLinkStyle!=null) { + CSVList props = new CSVList(";"); + cssText(defaultLinkStyle,props,true); + cssHyperlink(defaultLinkStyle,props); + buf.append(sIndent) + .append("a:link {").append(props.toString()).append("}\n"); + } + + defaultLinkStyle = (StyleWithProperties) + getStyles().getStyleByDisplayName(DEFAULT_VISITED_LINK_STYLE); + if (defaultLinkStyle!=null) { + CSVList props = new CSVList(";"); + cssText(defaultLinkStyle,props,true); + cssHyperlink(defaultLinkStyle,props); + buf.append(sIndent) + .append("a:visited {").append(props.toString()).append("}\n"); + } + + // Remaining link styles... + Enumeration enumer = anchorCombinedStyleNames.elements(); + while (enumer.hasMoreElements()) { + String sExportName = (String) enumer.nextElement(); + String sStyleName = (String) orgAnchorStyleNames.get(sExportName); + String sVisitedStyleName = (String) orgAnchorVisitedStyleNames.get(sExportName); + + StyleWithProperties style = ofr.getTextStyle(sStyleName); + + if (style!=null) { + CSVList props = new CSVList(";"); + cssText(style,props,true); + cssHyperlink(style,props); + buf.append(sIndent).append("a.").append(sExportName) + .append(":link {").append(props.toString()).append("}\n"); + } + + style = ofr.getTextStyle(sVisitedStyleName); + if (style!=null) { + CSVList props = new CSVList(";"); + cssText(style,props,true); + cssHyperlink(style,props); + buf.append(sIndent).append("a.").append(sExportName) + .append(":visited {").append(props.toString()).append("}\n"); + } + } + } + return buf.toString(); + + } + + /** Get the family of text (character) styles + * @return the style family + */ + public OfficeStyleFamily getStyles() { + return ofr.getTextStyles(); + } + + /** Create default tag name to represent a text + * @param style to use + * @return the tag name. + */ + public String getDefaultTagName(StyleWithProperties style) { + return "span"; + } + + /** Convert formatting properties for a specific text style. + * @param style the style to convert + * @param props theCSVList
object to add information to
+ * @param bInherit true if properties should be inherited from parent style(s)
+ */
+ public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
+ cssText(style,props,bInherit);
+ }
+
+ // Methods to query individual formatting properties (no inheritance)
+
+ // Does this style contain the bold attribute?
+ public boolean isBold(StyleWithProperties style) {
+ String s = style.getProperty(XMLString.FO_FONT_WEIGHT,false);
+ return s!=null && "bold".equals(s);
+ }
+
+ // Does this style contain the italics/oblique attribute?
+ public boolean isItalics(StyleWithProperties style) {
+ String s = style.getProperty(XMLString.FO_FONT_STYLE,false);
+ return s!=null && !"normal".equals(s);
+ }
+
+ // Does this style contain a fixed pitch font?
+ public boolean isFixed(StyleWithProperties style) {
+ String s = style.getProperty(XMLString.STYLE_FONT_NAME,false);
+ String s2 = null;
+ String s3 = null;
+ if (s!=null) {
+ FontDeclaration fd = (FontDeclaration) ofr.getFontDeclarations().getStyle(s);
+ if (fd!=null) {
+ s2 = fd.getFontFamilyGeneric();
+ s3 = fd.getFontPitch();
+ }
+ }
+ else {
+ s = style.getProperty(XMLString.FO_FONT_FAMILY,false);
+ s2 = style.getProperty(XMLString.STYLE_FONT_FAMILY_GENERIC,false);
+ s3 = style.getProperty(XMLString.STYLE_FONT_PITCH,false);
+ }
+ if ("fixed".equals(s3)) { return true; }
+ if ("modern".equals(s2)) { return true; }
+ return false;
+ }
+
+ // Does this style specify superscript?
+ public boolean isSuperscript(StyleWithProperties style) {
+ String sPos = style.getProperty(XMLString.STYLE_TEXT_POSITION,false);
+ if (sPos==null) return false;
+ if (sPos.startsWith("sub")) return false;
+ if (sPos.startsWith("-")) return false;
+ return true;
+ }
+
+ // Does this style specify subscript?
+ public boolean isSubscript(StyleWithProperties style) {
+ String sPos = style.getProperty(XMLString.STYLE_TEXT_POSITION,false);
+ if (sPos==null) return false;
+ if (sPos.startsWith("sub")) return true;
+ if (sPos.startsWith("-")) return true;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // OpenDocument text properties
+ // Text properties can be applied to text, paragraph, cell, graphic and
+ // presentation styles.
+ // Language and country attributes are handled elsewhere
+ // The following attributes are currently not supported:
+ // - style:use-window-font-color ("automatic color")
+ // - style:font-charset (other encoding)
+ // - style:font-size-rel
+ // - text:display
+ // - text:condition
+ // Also all attributes for CJK and CTL text are currently ignored:
+ // style:font-name-*, style:font-family-*, style:font-family-generic-*,
+ // style:font-style-name-*, style:font-pitch-*, style:font-charset-*,
+ // style:font-size-*, style:font-size-rel-*, style:script-type
+ // The following attributes cannot be supported using CSS2:
+ // - style:text-outline
+ // - style:font-relief
+ // - style:text-line-trough-* (formatting of line through)
+ // - style:text-underline-* (formatting of underline)
+ // - style:letter-kerning
+ // - style:text-combine-*
+ // - style:text-emphasis
+ // - style:text-scale
+ // - style:text-rotation-*
+ // - fo:hyphenate
+ // - fo:hyphenation-*
+ //
+
+ public void cssText(StyleWithProperties style, CSVList props, boolean bInherit) {
+ cssTextCommon(style,props,bInherit);
+ cssTextBackground(style,props,bInherit);
+ }
+
+ public void cssTextCommon(StyleWithProperties style, CSVList props, boolean bInherit) {
+ String s=null,s2=null,s3=null,s4=null;
+ CSVList val;
+
+ // Font family
+ if (bInherit || style.getProperty(XMLString.STYLE_FONT_NAME,false)!=null) {
+ val = new CSVList(","); // multivalue property!
+ // Get font family information from font declaration or from style
+ s = style.getProperty(XMLString.STYLE_FONT_NAME);
+ if (s!=null) {
+ FontDeclaration fd = (FontDeclaration) ofr.getFontDeclarations().getStyle(s);
+ if (fd!=null) {
+ s = fd.getFontFamily();
+ s2 = fd.getFontFamilyGeneric();
+ s3 = fd.getFontPitch();
+ }
+ }
+ else {
+ s = style.getProperty(XMLString.FO_FONT_FAMILY);
+ s2 = style.getProperty(XMLString.STYLE_FONT_FAMILY_GENERIC);
+ s3 = style.getProperty(XMLString.STYLE_FONT_PITCH);
+ }
+
+ // Add the western font family (CJK and CTL is more complicated)
+ if (s!=null) { val.addValue(s); }
+ // Add generic font family
+ if ("fixed".equals(s3)) { val.addValue("monospace"); }
+ else if ("roman".equals(s2)) { val.addValue("serif"); }
+ else if ("swiss".equals(s2)) { val.addValue("sans-serif"); }
+ else if ("modern".equals(s2)) { val.addValue("monospace"); }
+ else if ("decorative".equals(s2)) { val.addValue("fantasy"); }
+ else if ("script".equals(s2)) { val.addValue("cursive"); }
+ else if ("system".equals(s2)) { val.addValue("serif"); } // System default font
+ if (!val.isEmpty()) { props.addValue("font-family",val.toString()); }
+ }
+
+ // Font style (italics): This property fit with css2
+ s = style.getProperty(XMLString.FO_FONT_STYLE,bInherit);
+ if (s!=null) { props.addValue("font-style",s); }
+
+ // Font variant (small caps): This property fit with css2
+ s = style.getProperty(XMLString.FO_FONT_VARIANT,bInherit);
+ if (s!=null) { props.addValue("font-variant",s); }
+
+ // Font weight (bold): This property fit with css2
+ s = style.getProperty(XMLString.FO_FONT_WEIGHT,bInherit);
+ if (s!=null) { props.addValue("font-weight",s); }
+
+ // Font size: Absolute values of this property fit with css2
+ // this is handled together with sub- and superscripts (style:text-position)
+ // First value: sub, super or percentage (raise/lower relative to font height)
+ // Second value (optional): percentage (relative size);
+ if (bInherit || style.getProperty(XMLString.FO_FONT_SIZE,false)!=null
+ || style.getProperty(XMLString.STYLE_TEXT_POSITION,false)!=null) {
+ s = style.getAbsoluteProperty(XMLString.FO_FONT_SIZE);
+ s2 = style.getProperty(XMLString.STYLE_TEXT_POSITION);
+ if (s2!=null) {
+ s2 = s2.trim();
+ int i = s2.indexOf(" ");
+ if (i>0) { // two values
+ s3 = s2.substring(0,i);
+ s4 = s2.substring(i+1);
+ }
+ else { // one value
+ s3 = s2; s4="100%";
+ }
+ if (s!=null) { props.addValue("font-size",Misc.multiply(s4,scale(s))); }
+ else { props.addValue("font-size",s4); }
+ props.addValue("vertical-align",s3);
+ }
+ else if (s!=null) {
+ props.addValue("font-size",scale(s));
+ }
+ }
+
+ // Color: This attribute fit with css2
+ s = style.getProperty(XMLString.FO_COLOR,bInherit);
+ if (s!=null) { props.addValue("color",s); }
+
+ // Shadow: This attribute fit with css2
+ // (Currently OOo has only one shadow style, which is saved as 1pt 1pt)
+ s = style.getProperty(XMLString.FO_TEXT_SHADOW,bInherit);
+ if (s!=null) { props.addValue("text-shadow",s); }
+
+ // Text decoration. Here OOo is more flexible that CSS2.
+ if (ofr.isOpenDocument()) {
+ s = style.getProperty(XMLString.STYLE_TEXT_LINE_THROUGH_STYLE,bInherit);
+ s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE_STYLE,bInherit);
+ }
+ else {
+ s = style.getProperty(XMLString.STYLE_TEXT_CROSSING_OUT,bInherit);
+ s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE,bInherit);
+ }
+ s3 = style.getProperty(XMLString.STYLE_TEXT_BLINKING,bInherit);
+ // Issue: Since these three properties all maps to the single CSS property
+ // text-decoration, there is no way to turn on one kind of decoration and
+ // turn another one off (without creating another inline element).
+ // If one decoration is turned of, we turn them all off:
+ if ("none".equals(s) || "none".equals(s2) || "false".equals(s3)) {
+ props.addValue("text-decoration","none");
+ }
+ else { // set the required properties
+ val = new CSVList(" "); // multivalue property!
+ if (s!=null && !"none".equals(s)) { val.addValue("line-through"); }
+ if (s2!=null && !"none".equals(s2)) { val.addValue("underline"); }
+ if (s3!=null && "true".equals(s3)) { val.addValue("blink"); }
+ if (!val.isEmpty()) { props.addValue("text-decoration",val.toString()); }
+ }
+
+ // Letter spacing: This property fit with css
+ s = style.getProperty(XMLString.FO_LETTER_SPACING,bInherit);
+ if (s!=null) { props.addValue("letter-spacing",scale(s)); }
+
+ // Capitalization: This property fit with css
+ s = style.getProperty(XMLString.FO_TEXT_TRANSFORM,bInherit);
+ if (s!=null) { props.addValue("text-transform",s); }
+ }
+
+ public void cssTextBackground(StyleWithProperties style, CSVList props, boolean bInherit) {
+ // Background color: This attribute fit with css when applied to inline text
+ String s =ofr.isOpenDocument() ?
+ style.getTextProperty(XMLString.FO_BACKGROUND_COLOR,bInherit) :
+ style.getTextProperty(XMLString.STYLE_TEXT_BACKGROUND_COLOR,bInherit);
+ if (s!=null) { props.addValue("background-color",s); }
+ }
+
+ private void cssHyperlink(StyleWithProperties style, CSVList props) {
+ String s1,s2;
+ // For hyperlinks, export text-decoration:none even if nothing is defined in source
+ if (ofr.isOpenDocument()) {
+ s1 = style.getProperty(XMLString.STYLE_TEXT_LINE_THROUGH_STYLE,true);
+ s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE_STYLE,true);
+ }
+ else {
+ s1 = style.getProperty(XMLString.STYLE_TEXT_CROSSING_OUT,true);
+ s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE,true);
+ }
+ String s3 = style.getProperty(XMLString.STYLE_TEXT_BLINKING,true);
+ if (s1==null && s2==null && s3==null) {
+ props.addValue("text-decoration","none");
+ }
+ }
+
+}
diff --git a/source/java/writer2latex/xhtml/Xhtml10Converter.java b/source/java/writer2latex/xhtml/Xhtml10Converter.java
new file mode 100644
index 0000000..d9f9f5d
--- /dev/null
+++ b/source/java/writer2latex/xhtml/Xhtml10Converter.java
@@ -0,0 +1,35 @@
+/************************************************************************
+ *
+ * Xhtml10Converter.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-09-09)
+ *
+ */
+
+package writer2latex.xhtml;
+
+public class Xhtml10Converter extends Converter {
+
+ public Xhtml10Converter() {
+ super(XhtmlDocument.XHTML10);
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/xhtml/XhtmlConfig.java b/source/java/writer2latex/xhtml/XhtmlConfig.java
new file mode 100644
index 0000000..2b93bad
--- /dev/null
+++ b/source/java/writer2latex/xhtml/XhtmlConfig.java
@@ -0,0 +1,255 @@
+/************************************************************************
+ *
+ * XhtmlConfig.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2008 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2008-11-14)
+ *
+ */
+
+package writer2latex.xhtml;
+
+import java.util.Enumeration;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import writer2latex.base.BooleanOption;
+import writer2latex.base.IntegerOption;
+import writer2latex.base.Option;
+import writer2latex.util.Misc;
+
+public class XhtmlConfig extends writer2latex.base.ConfigBase {
+ // Implement configuration methods
+ protected int getOptionCount() { return 36; }
+ protected String getDefaultConfigPath() { return "/writer2latex/xhtml/config/"; }
+
+ // Override setOption: To be backwards compatible, we must accept options
+ // with the prefix xhtml_
+ public void setOption(String sName,String sValue) {
+ if (sName.startsWith("xhtml_")) { sName = sName.substring(6); }
+ // this option has been renamed:
+ if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
+ super.setOption(sName, sValue);
+ }
+
+ // Formatting
+ public static final int IGNORE_ALL = 0;
+ public static final int IGNORE_STYLES = 1;
+ public static final int IGNORE_HARD = 2;
+ public static final int CONVERT_ALL = 3;
+
+ // Options
+ private static final int IGNORE_HARD_LINE_BREAKS = 0;
+ private static final int IGNORE_EMPTY_PARAGRAPHS = 1;
+ private static final int IGNORE_DOUBLE_SPACES = 2;
+ private static final int ORIGINAL_IMAGE_SIZE = 3;
+ private static final int NO_DOCTYPE = 4;
+ private static final int ADD_BOM = 5;
+ private static final int ENCODING = 6;
+ private static final int USE_NAMED_ENTITIES = 7;
+ private static final int CUSTOM_STYLESHEET = 8;
+ private static final int FORMATTING = 9;
+ private static final int FRAME_FORMATTING = 10;
+ private static final int SECTION_FORMATTING = 11;
+ private static final int TABLE_FORMATTING = 12;
+ private static final int IGNORE_TABLE_DIMENSIONS = 13;
+ private static final int USE_DUBLIN_CORE = 14;
+ private static final int NOTES = 15;
+ private static final int CONVERT_TO_PX = 16;
+ private static final int SCALING = 17;
+ private static final int COLUMN_SCALING = 18;
+ private static final int FLOAT_OBJECTS = 19;
+ private static final int TABSTOP_STYLE = 20;
+ private static final int USE_LIST_HACK = 21;
+ private static final int SPLIT_LEVEL = 22;
+ private static final int REPEAT_LEVELS = 23;
+ private static final int CALC_SPLIT = 24;
+ private static final int DISPLAY_HIDDEN_SHEETS = 25;
+ private static final int DISPLAY_HIDDEN_ROWS_COLS = 26;
+ private static final int DISPLAY_FILTERED_ROWS_COLS = 27;
+ private static final int APPLY_PRINT_RANGES = 28;
+ private static final int USE_TITLE_AS_HEADING = 29;
+ private static final int USE_SHEET_NAMES_AS_HEADINGS = 30;
+ private static final int XSLT_PATH = 31;
+ private static final int SAVE_IMAGES_IN_SUBDIR = 32;
+ private static final int UPLINK = 33;
+ private static final int DIRECTORY_ICON = 34;
+ private static final int DOCUMENT_ICON = 35;
+
+ protected XhtmlStyleMap xpar = new XhtmlStyleMap();
+ protected XhtmlStyleMap xtext = new XhtmlStyleMap();
+ protected XhtmlStyleMap xframe = new XhtmlStyleMap();
+ protected XhtmlStyleMap xlist = new XhtmlStyleMap();
+ protected XhtmlStyleMap xattr = new XhtmlStyleMap();
+
+ public XhtmlConfig() {
+ super();
+ // create options with default values
+ options[IGNORE_HARD_LINE_BREAKS] = new BooleanOption("ignore_hard_line_breaks","false");
+ options[IGNORE_EMPTY_PARAGRAPHS] = new BooleanOption("ignore_empty_paragraphs","false");
+ options[IGNORE_DOUBLE_SPACES] = new BooleanOption("ignore_double_spaces","false");
+ options[ORIGINAL_IMAGE_SIZE] = new BooleanOption("original_image_size","false");
+ options[NO_DOCTYPE] = new BooleanOption("no_doctype","false");
+ options[ADD_BOM] = new BooleanOption("add_bom","false");
+ options[ENCODING] = new Option("encoding","UTF-8");
+ options[USE_NAMED_ENTITIES] = new BooleanOption("use_named_entities","false");
+ options[CUSTOM_STYLESHEET] = new Option("custom_stylesheet","");
+ options[FORMATTING] = new XhtmlFormatOption("formatting","convert_all");
+ options[FRAME_FORMATTING] = new XhtmlFormatOption("frame_formatting","convert_all");
+ options[SECTION_FORMATTING] = new XhtmlFormatOption("section_formatting","convert_all");
+ options[TABLE_FORMATTING] = new XhtmlFormatOption("table_formatting","convert_all");
+ options[IGNORE_TABLE_DIMENSIONS] = new BooleanOption("ignore_table_dimensions","false");
+ options[USE_DUBLIN_CORE] = new BooleanOption("use_dublin_core","true");
+ options[NOTES] = new BooleanOption("notes","true");
+ options[CONVERT_TO_PX] = new BooleanOption("convert_to_px","true");
+ options[SCALING] = new Option("scaling","100%");
+ options[COLUMN_SCALING] = new Option("column_scaling","100%");
+ options[FLOAT_OBJECTS] = new BooleanOption("float_objects","true");
+ options[TABSTOP_STYLE] = new Option("tabstop_style","");
+ options[USE_LIST_HACK] = new BooleanOption("use_list_hack","false");
+ options[SPLIT_LEVEL] = new IntegerOption("split_level","0") {
+ public void setString(String sValue) {
+ super.setString(sValue);
+ nValue = Misc.getPosInteger(sValue,0);
+ }
+ };
+ options[REPEAT_LEVELS] = new IntegerOption("repeat_levels","5") {
+ public void setString(String sValue) {
+ super.setString(sValue);
+ nValue = Misc.getPosInteger(sValue,0);
+ }
+ };
+ options[CALC_SPLIT] = new BooleanOption("calc_split","false");
+ options[DISPLAY_HIDDEN_SHEETS] = new BooleanOption("display_hidden_sheets","false");
+ options[DISPLAY_HIDDEN_ROWS_COLS] = new BooleanOption("display_hidden_rows_cols","false");
+ options[DISPLAY_FILTERED_ROWS_COLS] = new BooleanOption("display_filtered_rows_cols","false");
+ options[APPLY_PRINT_RANGES] = new BooleanOption("apply_print_ranges","false");
+ options[USE_TITLE_AS_HEADING] = new BooleanOption("use_title_as_heading","true");
+ options[USE_SHEET_NAMES_AS_HEADINGS] = new BooleanOption("use_sheet_names_as_headings","true");
+ options[XSLT_PATH] = new Option("xslt_path","");
+ options[SAVE_IMAGES_IN_SUBDIR] = new BooleanOption("save_images_in_subdir","false");
+ options[UPLINK] = new Option("uplink","");
+ options[DIRECTORY_ICON] = new Option("directory_icon","");
+ options[DOCUMENT_ICON] = new Option("document_icon","");
+ }
+
+ protected void readInner(Element elm) {
+ if (elm.getTagName().equals("xhtml-style-map")) {
+ String sName = elm.getAttribute("name");
+ String sFamily = elm.getAttribute("family");
+ if (sFamily.length()==0) { // try old name
+ sFamily = elm.getAttribute("class");
+ }
+ String sBlockElement = elm.getAttribute("block-element");
+ String sBlockCss = elm.getAttribute("block-css");
+ if (sBlockCss.length()==0) { sBlockCss="(none)"; }
+ String sElement = elm.getAttribute("element");
+ String sCss = elm.getAttribute("css");
+ if (sCss.length()==0) { sCss="(none)"; }
+ if ("paragraph".equals(sFamily)) {
+ xpar.put(sName,sBlockElement,sBlockCss,sElement,sCss);
+ }
+ else if ("text".equals(sFamily)) {
+ xtext.put(sName,sBlockElement,sBlockCss,sElement,sCss);
+ }
+ else if ("frame".equals(sFamily)) {
+ xframe.put(sName,sBlockElement,sBlockCss,sElement,sCss);
+ }
+ else if ("list".equals(sFamily)) {
+ xlist.put(sName,sBlockElement,sBlockCss,sElement,sCss);
+ }
+ else if ("attribute".equals(sFamily)) {
+ xattr.put(sName,sBlockElement,sBlockCss,sElement,sCss);
+ }
+ }
+ }
+
+ protected void writeInner(Document dom) {
+ writeXStyleMap(dom,xpar,"paragraph");
+ writeXStyleMap(dom,xtext,"text");
+ writeXStyleMap(dom,xlist,"list");
+ writeXStyleMap(dom,xframe,"frame");
+ writeXStyleMap(dom,xframe,"attribute");
+ }
+
+ private void writeXStyleMap(Document dom, XhtmlStyleMap sm, String sFamily) {
+ Enumeration smEnum = sm.getNames();
+ while (smEnum.hasMoreElements()) {
+ String sName = (String) smEnum.nextElement();
+ Element smNode = dom.createElement("xhtml-style-map");
+ smNode.setAttribute("name",sName);
+ smNode.setAttribute("family",sFamily);
+ smNode.setAttribute("element",sm.getElement(sName));
+ smNode.setAttribute("css",sm.getCss(sName));
+ String sBlockElement = sm.getBlockElement(sName);
+ if (sBlockElement!=null) { smNode.setAttribute("block-element",sm.getCss(sBlockElement)); }
+ String sBlockCss = sm.getBlockCss(sName);
+ if (sBlockCss!=null) { smNode.setAttribute("block-css",sm.getCss(sBlockCss)); }
+ dom.getDocumentElement().appendChild(smNode);
+ }
+ }
+
+ // Convenience accessor methods
+ public boolean ignoreHardLineBreaks() { return ((BooleanOption) options[IGNORE_HARD_LINE_BREAKS]).getValue(); }
+ public boolean ignoreEmptyParagraphs() { return ((BooleanOption) options[IGNORE_EMPTY_PARAGRAPHS]).getValue(); }
+ public boolean ignoreDoubleSpaces() { return ((BooleanOption) options[IGNORE_DOUBLE_SPACES]).getValue(); }
+ public boolean originalImageSize() { return ((BooleanOption) options[ORIGINAL_IMAGE_SIZE]).getValue(); }
+ public boolean xhtmlNoDoctype() { return ((BooleanOption) options[NO_DOCTYPE]).getValue(); }
+ public boolean xhtmlAddBOM() { return ((BooleanOption) options[ADD_BOM]).getValue(); }
+ public String xhtmlEncoding() { return options[ENCODING].getString(); }
+ public boolean useNamedEntities() { return ((BooleanOption) options[USE_NAMED_ENTITIES]).getValue(); }
+ public String xhtmlCustomStylesheet() { return options[CUSTOM_STYLESHEET].getString(); }
+ public int xhtmlFormatting() { return ((XhtmlFormatOption) options[FORMATTING]).getValue(); }
+ public int xhtmlFrameFormatting() { return ((XhtmlFormatOption) options[FRAME_FORMATTING]).getValue(); }
+ public int xhtmlSectionFormatting() { return ((XhtmlFormatOption) options[SECTION_FORMATTING]).getValue(); }
+ public int xhtmlTableFormatting() { return ((XhtmlFormatOption) options[TABLE_FORMATTING]).getValue(); }
+ public boolean xhtmlIgnoreTableDimensions() { return ((BooleanOption) options[IGNORE_TABLE_DIMENSIONS]).getValue(); }
+ public boolean xhtmlUseDublinCore() { return ((BooleanOption) options[USE_DUBLIN_CORE]).getValue(); }
+ public boolean xhtmlNotes() { return ((BooleanOption) options[NOTES]).getValue(); }
+ public boolean xhtmlConvertToPx() { return ((BooleanOption) options[CONVERT_TO_PX]).getValue(); }
+ public String getXhtmlScaling() { return options[SCALING].getString(); }
+ public String getXhtmlColumnScaling() { return options[COLUMN_SCALING].getString(); }
+ public boolean xhtmlFloatObjects() { return ((BooleanOption) options[FLOAT_OBJECTS]).getValue(); }
+ public String getXhtmlTabstopStyle() { return options[TABSTOP_STYLE].getString(); }
+ public boolean xhtmlUseListHack() { return ((BooleanOption) options[USE_LIST_HACK]).getValue(); }
+ public int getXhtmlSplitLevel() { return ((IntegerOption) options[SPLIT_LEVEL]).getValue(); }
+ public int getXhtmlRepeatLevels() { return ((IntegerOption) options[REPEAT_LEVELS]).getValue(); }
+ public boolean xhtmlCalcSplit() { return ((BooleanOption) options[CALC_SPLIT]).getValue(); }
+ public boolean xhtmlDisplayHiddenSheets() { return ((BooleanOption) options[DISPLAY_HIDDEN_SHEETS]).getValue(); }
+ public boolean displayHiddenRowsCols() { return ((BooleanOption) options[DISPLAY_HIDDEN_ROWS_COLS]).getValue(); }
+ public boolean displayFilteredRowsCols() { return ((BooleanOption) options[DISPLAY_FILTERED_ROWS_COLS]).getValue(); }
+ public boolean applyPrintRanges() { return ((BooleanOption) options[APPLY_PRINT_RANGES]).getValue(); }
+ public boolean xhtmlUseTitleAsHeading() { return ((BooleanOption) options[USE_TITLE_AS_HEADING]).getValue(); }
+ public boolean xhtmlUseSheetNamesAsHeadings() { return ((BooleanOption) options[USE_SHEET_NAMES_AS_HEADINGS]).getValue(); }
+ public String getXsltPath() { return options[XSLT_PATH].getString(); }
+ public boolean saveImagesInSubdir() { return ((BooleanOption) options[SAVE_IMAGES_IN_SUBDIR]).getValue(); }
+ public String getXhtmlUplink() { return options[UPLINK].getString(); }
+ public String getXhtmlDirectoryIcon() { return options[DIRECTORY_ICON].getString(); }
+ public String getXhtmlDocumentIcon() { return options[DOCUMENT_ICON].getString(); }
+
+ public XhtmlStyleMap getXParStyleMap() { return xpar; }
+ public XhtmlStyleMap getXTextStyleMap() { return xtext; }
+ public XhtmlStyleMap getXFrameStyleMap() { return xframe; }
+ public XhtmlStyleMap getXListStyleMap() { return xlist; }
+ public XhtmlStyleMap getXAttrStyleMap() { return xattr; }
+
+}
+
diff --git a/source/java/writer2latex/xhtml/XhtmlDocument.java b/source/java/writer2latex/xhtml/XhtmlDocument.java
new file mode 100644
index 0000000..9717b98
--- /dev/null
+++ b/source/java/writer2latex/xhtml/XhtmlDocument.java
@@ -0,0 +1,782 @@
+/************************************************************************
+ *
+ * XhtmlDocument.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2009 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 1.0 (2009-02-19)
+ *
+ */
+
+ //TODO: Remove redundant lang and dir attributes
+ //TODO: Add named entities outside ISO-latin 1
+
+package writer2latex.xhtml;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+//import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.DOMImplementation;
+//import org.xml.sax.SAXException;
+//import org.xml.sax.SAXParseException;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+//import javax.xml.parsers.ParserConfigurationException;
+
+import writer2latex.xmerge.DOMDocument;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+
+/**
+ * An implementation of Document
for
+ * XHTML documents.
+ */
+public class XhtmlDocument extends DOMDocument {
+
+ /** Constant to identify XHTML 1.0 strict documents */
+ public static final int XHTML10 = 0;
+
+ /** Constant to identify XHTML 1.1 documents (not used currently) */
+ public static final int XHTML11 = 1;
+
+ /** Constant to identify XHTML + MathML documents */
+ public static final int XHTML_MATHML = 2;
+
+ /** Constant to identify XHTML + MathML documents using the xsl transformations
+ * from w3c's math working group (http://www.w3.org/Math/XSL/)
+ */
+ public static final int XHTML_MATHML_XSL = 3;
+
+ private static final String[] sExtension = { ".html", ".html", ".xhtml", ".xml" };
+
+ private static final String[] sEmpty = { "base", "meta", "link", "hr", "br", "param", "img", "area", "input", "col" };
+
+ private static String[] entities; // Not convenient to define directly due to a lot of null values
+
+ // Type of document
+ private int nType;
+
+ // Configuration
+ private String sEncoding = "UTF-8";
+ private boolean bUseNamedEntities = false;
+ private char cLimit = 65535;
+ private boolean bNoDoctype = false;
+ private boolean bAddBOM = false;
+ private String sXsltPath = "";
+
+ // Content
+ private Element headNode = null;
+ private Element bodyNode = null;
+ private Element titleNode = null;
+ private Element contentNode = null;
+ private Element panelNode = null;
+ private Element headerNode = null;
+ private Element footerNode = null;
+
+ public static final String getExtension(int nType) {
+ return sExtension[nType];
+ }
+
+ /**
+ * Constructor. This constructor also creates the DOM (minimal: root, head,
+ * title and body node only) - unlike the constructors in
+ * writer2latex.xmerge.DOMDocument.
+ * @param name Document
name.
+ * @param nType the type of document
+ */
+ public XhtmlDocument(String name, int nType) {
+ super(name,sExtension[nType]);
+ this.nType = nType;
+ // Define publicId and systemId
+ String sPublicId = null;
+ String sSystemId = null;
+ switch (nType) {
+ case XHTML10 :
+ sPublicId = "-//W3C//DTD XHTML 1.0 Strict//EN";
+ sSystemId = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
+ break;
+ case XHTML11 :
+ sPublicId = "-//W3C//DTD XHTML 1.1//EN";
+ sSystemId = "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd";
+ break;
+ case XHTML_MATHML :
+ case XHTML_MATHML_XSL :
+ sPublicId = "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN";
+ sSystemId = "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd";
+ //sSystemId = "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd"; (old version)
+ /* An alternative is to use XHTML + MathML + SVG:
+ sPublicId = "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN",
+ sSystemId = "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd"); */
+ }
+
+ // create DOM
+ Document contentDOM = null;
+ try {
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = builderFactory.newDocumentBuilder();
+ DOMImplementation domImpl = builder.getDOMImplementation();
+ DocumentType doctype = domImpl.createDocumentType("html", sPublicId, sSystemId);
+ contentDOM = domImpl.createDocument("http://www.w3.org/1999/xhtml","html",doctype);
+ }
+ catch (Throwable t) {
+ t.printStackTrace();
+ }
+ contentDOM.getDocumentElement().setAttribute("xmlns","http://www.w3.org/1999/xhtml");
+ // add head, title and body
+ headNode = contentDOM.createElement("head");
+ titleNode = contentDOM.createElement("title");
+ bodyNode = contentDOM.createElement("body");
+ contentDOM.getDocumentElement().appendChild(headNode);
+ headNode.appendChild(titleNode);
+ contentDOM.getDocumentElement().appendChild(bodyNode);
+ contentNode = bodyNode;
+ setContentDOM(contentDOM);
+
+ }
+
+ public Element getHeadNode() { return headNode; }
+
+ public Element getBodyNode() { return bodyNode; }
+
+ public Element getTitleNode() { return titleNode; }
+
+ public Element getContentNode() { return contentNode; }
+
+ public void setContentNode(Element contentNode) { this.contentNode = contentNode; }
+
+ public Element getPanelNode() { return panelNode; }
+
+ public Element getHeaderNode() { return headerNode; }
+
+ public Element getFooterNode() { return footerNode; }
+
+ public void createHeaderFooter() {
+ headerNode = getContentDOM().createElement("div");
+ headerNode.setAttribute("id","header");
+ bodyNode.appendChild(headerNode);
+ contentNode = getContentDOM().createElement("div");
+ contentNode.setAttribute("id","content");
+ bodyNode.appendChild(contentNode);
+ footerNode = getContentDOM().createElement("div");
+ footerNode.setAttribute("id","footer");
+ bodyNode.appendChild(footerNode);
+ }
+
+ public void setContentDOM(Document doc) {
+ super.setContentDOM(doc);
+ collectNodes();
+ }
+
+ public void read(InputStream is) throws IOException {
+ super.read(is);
+ collectNodes();
+ }
+
+ public void readFromTemplate(XhtmlDocument template) {
+ // Remove all current child nodes
+ Element root = getContentDOM().getDocumentElement();
+ Node child = root.getFirstChild();
+ while (child!=null) {
+ root.removeChild(child);
+ child = root.getFirstChild();
+ }
+
+ // Import all child nodes from template
+ Element templateRoot = template.getContentDOM().getDocumentElement();
+ NodeList children = templateRoot.getChildNodes();
+ int nLen = children.getLength();
+ for (int i=0; iOutputStream
.
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ // Prepare named entities
+ prepareEntities();
+
+ OutputStreamWriter osw = new OutputStreamWriter(os,sEncoding);
+ // Add a BOM if the user desires so
+ if (bAddBOM) { osw.write("\uFEFF"); }
+
+ // Omit xml prolog for pure xhtml documents (to be browser safe)
+ if (nType==XHTML_MATHML || nType==XHTML_MATHML_XSL) {
+ osw.write("\n");
+ }
+ // Either specify doctype or xsl transformation (the user may require
+ // that no doctype is used; this may be desirable for further transformations)
+ if (nType==XHTML_MATHML_XSL) {
+ // Original url: http://www.w3.org/Math/XSL/pmathml.xsl
+ // Add trailing slash if needed
+ String sSlash = sXsltPath.length()>0 && !sXsltPath.endsWith("/") ? "/" : "";
+ osw.write("\n");
+ }
+ else if (!bNoDoctype) {
+ osw.write("\n");
+ }
+ write(getContentDOM().getDocumentElement(),0,osw);
+ osw.flush();
+ osw.close();
+ }
+
+ private boolean isEmpty(String sTagName) {
+ for (int i=0; iClass representing a binary graphics document. + * This class is used for representing graphics documents that are not + * interpreted in any way, but simply copied verbatim from the source format + * to the target format.
+ * + *GraphicsDocument
is used to create new graphics documents.
Constructs a new graphics document.
+ * + *This new document does not contain any information. Document data must
+ * either be added using appropriate methods, or an existing file can be
+ * {@link #read(InputStream) read} from an InputStream
.
GraphicsDocument
.
+ */
+ public BinaryGraphicsDocument(String name, String sFileExtension, String sMimeType) {
+ this.sFileExtension = sFileExtension;
+ this.sMimeType = sMimeType;
+ docName = trimDocumentName(name);
+ }
+
+
+ /**
+ * This method reads byte
data from the InputStream.
Returns the Document
name with no file extension.
Document
name with no file extension.
+ */
+ public String getName() {
+ return docName;
+ }
+
+ /**
+ * Returns the Document
name with file extension.
Document
name with file extension.
+ */
+ public String getFileName() {
+ return new String(docName + getFileExtension());
+ }
+
+
+ /**
+ * Writes out the Document
content to the specified
+ * OutputStream
.
This method may not be thread-safe. + * Implementations may or may not synchronize this + * method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.
+ * + * @param osOutputStream
to write out the
+ * Document
content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ os.write(data, nOff, nLen);
+ }
+
+ /**
+ * Returns the file extension for this type of
+ * Document
.
+ *
+ * @return The file extension of Document
.
+ */
+ public String getFileExtension(){ return sFileExtension; }
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ public String getDocumentMIMEType(){ return sMimeType; }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/xmerge/ConvertData.java b/source/java/writer2latex/xmerge/ConvertData.java
new file mode 100644
index 0000000..c28dbe5
--- /dev/null
+++ b/source/java/writer2latex/xmerge/ConvertData.java
@@ -0,0 +1,179 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for Writer2LaTeX
+// Change: The first document added will become the "master document" 2006/10/05
+// Version 1.0 (2008-11-24)
+
+package writer2latex.xmerge;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Iterator;
+
+import writer2latex.api.ConverterResult;
+import writer2latex.api.OutputFile;
+
+/**
+ * ConvertData
is used as a container for passing
+ * OutputFile
objects in and out of the Convert
+ * class. The ConvertData
contains a String
+ * name and a Vector
of OutputFile
objects.
OutputFile
objects.
+ */
+ private Vector v = new Vector();
+
+ /** Master doc */
+ private OutputFile masterDoc = null;
+
+ /**
+ * Name of the ConvertData
object.
+ */
+ private String name;
+
+
+ /**
+ * Resets ConvertData. This empties all OutputFile
+ * objects from this class. This allows reuse of a
+ * ConvertData
.
+ */
+ public void reset() {
+ name = null;
+ v.removeAllElements();
+ }
+
+ /**
+ * Returns the OutputFile
name.
+ *
+ * @return The OutputFile
name.
+ */
+ public String getName() {
+ return name;
+ }
+
+
+ /**
+ * Sets the OutputFile
name.
+ *
+ * @param docName The name of the OutputFile
.
+ */
+ public void setName(String docName) {
+ name = docName;
+ }
+
+ /**
+ * Adds a OutputFile
to the vector.
+ *
+ * @param doc The OutputFile
to add.
+ */
+ public void addDocument(OutputFile doc) {
+ if (v.size()==0) { masterDoc = doc; }
+ v.add(doc);
+ }
+
+ /** Get the master document
+ * @return OutputFile
the master document
+ */
+ public OutputFile getMasterDocument() {
+ return masterDoc;
+ }
+
+ /** Check if a given document is the master document
+ * @param doc The OutputFile
to check
+ * @return true if this is the master document
+ */
+ public boolean isMasterDocument(OutputFile doc) {
+ return doc == masterDoc;
+ }
+
+
+ /**
+ * Gets an Iterator
to access the Vector
+ * of OutputFile
objects
+ *
+ * @return The Iterator
to access the
+ * Vector
of OutputFile
objects.
+ */
+ public Iterator iterator() {
+ return v.iterator();
+ }
+
+
+ /**
+ * Gets the number of OutputFile
objects currently stored
+ *
+ * @return The number of OutputFile
objects currently
+ * stored.
+ */
+ public int getNumDocuments() {
+ return (v.size());
+ }
+
+ public void write(File dir) throws IOException {
+ if (dir!=null && !dir.exists()) throw new IOException("Directory does not exist");
+ Iterator docEnum = iterator();
+ while (docEnum.hasNext()) {
+ OutputFile docOut = (OutputFile) docEnum.next();
+ String sDirName = "";
+ String sFileName = docOut.getFileName();
+ File subdir = dir;
+ int nSlash = sFileName.indexOf("/");
+ if (nSlash>-1) {
+ sDirName = sFileName.substring(0,nSlash);
+ sFileName = sFileName.substring(nSlash+1);
+ subdir = new File(dir,sDirName);
+ if (!subdir.exists()) { subdir.mkdir(); }
+ }
+ File outfile = new File (subdir,sFileName);
+ FileOutputStream fos = new FileOutputStream(outfile);
+ docOut.write(fos);
+ fos.flush();
+ fos.close();
+ }
+
+ }
+}
+
diff --git a/source/java/writer2latex/xmerge/DOMDocument.java b/source/java/writer2latex/xmerge/DOMDocument.java
new file mode 100644
index 0000000..04f2acd
--- /dev/null
+++ b/source/java/writer2latex/xmerge/DOMDocument.java
@@ -0,0 +1,400 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for writer2latex
+// Version 1.0 (2008-11-23)
+
+package writer2latex.xmerge;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+//import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+//import java.io.ByteArrayInputStream;
+//import java.io.IOException;
+
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+//import org.xml.sax.SAXParseException;
+
+/**
+ * An implementation of Document
for
+ * StarOffice documents.
+ */
+public class DOMDocument
+ implements writer2latex.xmerge.Document {
+
+ /** Factory for DocumentBuilder
objects. */
+ private static DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+
+ /** DOM Document
of content.xml. */
+ private Document contentDoc = null;
+
+ /** DOM Document
of styles.xml. */
+ //private Document styleDoc = null;
+
+ private String documentName = null;
+ private String fileName = null;
+ private String fileExt = null;
+
+ /** Resources object. */
+ //private Resources res = null;
+
+
+ /**
+ * Default constructor.
+ *
+ * @param name Document
name.
+ * @param ext Document
extension.
+ */
+ public DOMDocument(String name,String ext)
+ {
+ this(name,ext,true, false);
+ }
+
+ /**
+ * Returns the file extension of the Document
+ * represented.
+ *
+ * @return file extension of the Document
.
+ */
+ protected String getFileExtension() {
+ return fileExt;
+ }
+
+
+ /**
+ * Constructor with arguments to set namespaceAware
+ * and validating
flags.
+ *
+ * @param name Document
name (may or may not
+ * contain extension).
+ * @param ext Document
extension.
+ * @param namespaceAware Value for namespaceAware
flag.
+ * @param validating Value for validating
flag.
+ */
+ public DOMDocument(String name, String ext,boolean namespaceAware, boolean validating) {
+
+ //res = Resources.getInstance();
+ factory.setValidating(validating);
+ factory.setNamespaceAware(namespaceAware);
+ this.fileExt = ext;
+ this.documentName = trimDocumentName(name);
+ this.fileName = documentName + getFileExtension();
+ }
+
+
+ /**
+ * Removes the file extension from the Document
+ * name.
+ *
+ * @param name Full Document
name with extension.
+ *
+ * @return Name of Document
without the extension.
+ */
+ private String trimDocumentName(String name) {
+ String temp = name.toLowerCase();
+ String ext = getFileExtension();
+
+ if (temp.endsWith(ext)) {
+ // strip the extension
+ int nlen = name.length();
+ int endIndex = nlen - ext.length();
+ name = name.substring(0,endIndex);
+ }
+
+ return name;
+ }
+
+
+ /**
+ * Return a DOM Document
object of the document content
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the read
method or the
+ * initContentDOM
method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM Document
object.
+ */
+ public Document getContentDOM() {
+
+ return contentDoc;
+ }
+
+ /**
+ * Sets the Content of the Document
to the contents of the
+ * supplied Node
list.
+ *
+ * @param newDom DOM Document
object.
+ */
+ public void setContentDOM( Node newDom) {
+ contentDoc=(Document)newDom;
+ }
+
+
+ /**
+ * Return the name of the Document
.
+ *
+ * @return The name of Document
.
+ */
+ public String getName() {
+
+ return documentName;
+ }
+
+
+ /**
+ * Return the file name of the Document
, possibly
+ * with the standard extension.
+ *
+ * @return The file name of Document
.
+ */
+ public String getFileName() {
+
+ return fileName;
+ }
+
+
+ /**
+ * Read the Office Document
from the specified
+ * InputStream
.
+ *
+ * @param is Office document InputStream
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException {
+ DocumentBuilder builder = null;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ throw new IOException(ex.getMessage());
+ }
+ try {
+ contentDoc= builder.parse(is);
+ } catch (SAXException ex) {
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+
+ /**
+ * Write out content to the supplied OutputStream
.
+ *
+ * @param os XML OutputStream
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+
+ // set bytes for writing to output stream
+ byte contentBytes[] = docToBytes(contentDoc);
+
+ os.write(contentBytes);
+ }
+
+
+ /**
+ * Write out a org.w3c.dom.Document
object into a
+ * byte
array.
TODO: remove dependency on com.sun.xml.tree.XmlDocument + * package!
+ * + * @param Document DOMDocument
object.
+ *
+ * @return byte
array of DOM Document
+ * object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private byte[] docToBytes(Document doc)
+ throws IOException {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ java.lang.reflect.Constructor con;
+ java.lang.reflect.Method meth;
+
+ String domImpl = doc.getClass().getName();
+
+ /*
+ * We may have multiple XML parsers in the Classpath.
+ * Depending on which one is first, the actual type of
+ * doc may vary. Need a way to find out which API is being
+ * used and use an appropriate serialization method.
+ */
+ try {
+ // First of all try for JAXP 1.0
+ if (domImpl.equals("com.sun.xml.tree.XmlDocument")) {
+ Class jaxpDoc = Class.forName("com.sun.xml.tree.XmlDocument");
+
+ // The method is in the XMLDocument class itself, not a helper
+ meth = jaxpDoc.getMethod("write",
+ new Class[] { Class.forName("java.io.OutputStream") } );
+
+ meth.invoke(doc, new Object [] { baos } );
+ }
+ else if (domImpl.equals("org.apache.crimson.tree.XmlDocument"))
+ {
+ Class crimsonDoc = Class.forName("org.apache.crimson.tree.XmlDocument");
+ // The method is in the XMLDocument class itself, not a helper
+ meth = crimsonDoc.getMethod("write",
+ new Class[] { Class.forName("java.io.OutputStream") } );
+
+ meth.invoke(doc, new Object [] { baos } );
+ }
+ else if (domImpl.equals("org.apache.xerces.dom.DocumentImpl")
+ || domImpl.equals("org.apache.xerces.dom.DeferredDocumentImpl")) {
+ // Try for Xerces
+ Class xercesSer =
+ Class.forName("org.apache.xml.serialize.XMLSerializer");
+
+ // Get the OutputStream constructor
+ // May want to use the OutputFormat parameter at some stage too
+ con = xercesSer.getConstructor(new Class []
+ { Class.forName("java.io.OutputStream"),
+ Class.forName("org.apache.xml.serialize.OutputFormat") } );
+
+
+ // Get the serialize method
+ meth = xercesSer.getMethod("serialize",
+ new Class [] { Class.forName("org.w3c.dom.Document") } );
+
+
+ // Get an instance
+ Object serializer = con.newInstance(new Object [] { baos, null } );
+
+
+ // Now call serialize to write the document
+ meth.invoke(serializer, new Object [] { doc } );
+ }
+ else if (domImpl.equals("gnu.xml.dom.DomDocument")) {
+
+ Class gnuSer = Class.forName("gnu.xml.dom.ls.DomLSSerializer");
+
+ // Get the serialize method
+ meth = gnuSer.getMethod("serialize",
+ new Class [] { Class.forName("org.w3c.dom.Node"),
+ Class.forName("java.io.OutputStream") } );
+
+ // Get an instance
+ Object serializer = gnuSer.newInstance();
+
+ // Now call serialize to write the document
+ meth.invoke(serializer, new Object [] { doc, baos } );
+ }
+ else {
+ // We dont have another parser
+ throw new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl);
+ }
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new IOException(cnfe.toString());
+ }
+ catch (Exception e) {
+ // We may get some other errors, but the bottom line is that
+ // the steps being executed no longer work
+ throw new IOException(e.toString());
+ }
+
+ byte bytes[] = baos.toByteArray();
+
+ return bytes;
+ }
+
+
+ /**
+ * Initializes a new DOM Document
with the content
+ * containing minimum XML tags.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public final void initContentDOM() throws IOException {
+ contentDoc = createDOM("");
+
+ }
+
+ /**
+ * Creates a new DOM Document
containing minimum
+ * OpenOffice XML tags.
This method uses the subclass
+ * getOfficeClassAttribute
method to get the
+ * attribute for office:class.
Document
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private final Document createDOM(String rootName) throws IOException {
+
+ Document doc = null;
+
+ try {
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ doc = builder.newDocument();
+
+ } catch (ParserConfigurationException ex) {
+ System.err.println("Error:"+ ex);
+
+
+ }
+
+ Element root = (Element) doc.createElement(rootName);
+ doc.appendChild(root);
+
+
+ return doc;
+ }
+
+}
+
+
+
+
diff --git a/source/java/writer2latex/xmerge/Document.java b/source/java/writer2latex/xmerge/Document.java
new file mode 100644
index 0000000..1a54ec6
--- /dev/null
+++ b/source/java/writer2latex/xmerge/Document.java
@@ -0,0 +1,86 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ * This version is adapted for Writer2LaTeX
+ * version 1.0 (2008-11-22)
+ *
+ ************************************************************************/
+
+package writer2latex.xmerge;
+
+//import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import writer2latex.api.OutputFile;
+
+/**
+ * A Document
represents any Document
+ * to be converted and the resulting Document
from any
+ * conversion.
Reads the content from the InputStream
into
+ * the Document
.
This method may not be thread-safe. + * Implementations may or may not synchronize this + * method. User code (i.e. caller) must make sure that + * calls to this method are thread-safe.
+ * + * @param isInputStream
to read in the
+ * Document
content.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException;
+
+
+ /**
+ * Returns the Document
name with no file extension.
+ *
+ * @return The Document
name with no file extension.
+ */
+ public String getName();
+
+
+}
+
diff --git a/source/java/writer2latex/xmerge/EmbeddedBinaryObject.java b/source/java/writer2latex/xmerge/EmbeddedBinaryObject.java
new file mode 100644
index 0000000..6f31b38
--- /dev/null
+++ b/source/java/writer2latex/xmerge/EmbeddedBinaryObject.java
@@ -0,0 +1,143 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for Writer2LaTeX
+// Version 1.0 (2008-11-22)
+
+package writer2latex.xmerge;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+//import org.w3c.dom.Node;
+
+
+/**
+ * This class represents embedded object's in an OpenOffice.org document that
+ * have a binary representation.
+ */
+public class EmbeddedBinaryObject extends EmbeddedObject {
+
+ /** The object's binary representation. */
+ protected byte[] objData = null;
+
+ /**
+ * Constructor for an embedded object stored using an XML representation.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ */
+ public EmbeddedBinaryObject(String name, String type) {
+ super(name, type);
+ }
+
+
+ /**
+ * Package private constructor for use when reading an object from a
+ * compressed SX? file.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ * @param source The OfficeZip representation of the SX? file that stores
+ * the object.
+ */
+ EmbeddedBinaryObject(String name, String type, OfficeZip source) {
+ super(name, type, source);
+ }
+
+
+ /**
+ * This method returns the data for this object.
+ *
+ * @return A byte
array containing the object's data.
+ */
+ public byte[] getBinaryData() {
+
+ if (objData == null) {
+ // See if we came from a Zip file
+ if (zipFile != null) {
+ objData = zipFile.getNamedBytes(objName);
+ }
+ }
+
+ return objData;
+ }
+
+
+ /**
+ * Sets the data for this object.
+ *
+ * @param data A byte
array containing data for the object.
+ */
+ public void setBinaryData(byte[] data) {
+ objData = data;
+ hasChanged = true;
+ }
+
+ /**
+ * Package private method for writing the data of the EmbeddedObject to a
+ * SX? file.
+ *
+ * @param zip An OfficeZip
instance representing the file
+ * the data is to be written to.
+ */
+ void write(OfficeZip zip) {
+ if (hasChanged) {
+ zip.setNamedBytes(objName, objData);
+ }
+ }
+
+
+ /**
+ * Package private method that constructs the manifest.xml entries for this
+ * embedded object.
+ *
+ * @return Document Document
containing the manifest entries.
+ */
+ void writeManifestData(Document manifestDoc) throws DOMException {
+ Element objNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
+
+ objNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, objType);
+ objNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH, objName);
+
+ manifestDoc.getDocumentElement().appendChild(objNode);
+ }
+
+}
+
diff --git a/source/java/writer2latex/xmerge/EmbeddedObject.java b/source/java/writer2latex/xmerge/EmbeddedObject.java
new file mode 100644
index 0000000..1d8cad8
--- /dev/null
+++ b/source/java/writer2latex/xmerge/EmbeddedObject.java
@@ -0,0 +1,129 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for Writer2LaTeX
+
+package writer2latex.xmerge;
+
+import java.io.IOException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+
+
+public abstract class EmbeddedObject {
+ protected String objName;
+ protected String objType;
+
+ /** Representation of the file from which this object was read. */
+ protected OfficeZip zipFile = null;
+
+ /** Flag indicating if this document has changed since reading or is new. */
+ protected boolean hasChanged = false;
+
+ /**
+ * Constructor for an embedded object stored using an XML representation.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ */
+ public EmbeddedObject(String name, String type) {
+ objName = name;
+ objType = type;
+
+ hasChanged = true;
+ }
+
+
+ /**
+ * Package private constructor for use when reading an object from a
+ * compressed SX? file.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ * @param source The OfficeZip representation of the SX? file that stores
+ * the object.
+ */
+ EmbeddedObject(String name, String type, OfficeZip source) {
+ this(name, type);
+ zipFile = source;
+ }
+
+
+ /**
+ * Retrieves the name of the embedded object represented by an instance of
+ * this class.
+ *
+ * N.B.The name referes to the name as found in the
+ * META-INF/manifest.xml
file.
+ *
+ * @return The name of the object.
+ */
+ public final String getName() {
+ return objName;
+ }
+
+
+ /**
+ * Retrieves the type of the embedded object represented by an instance of
+ * this class.
+ *
+ * The META-INF/manifest.xml
file currently represents the
+ * type of an object using MIME types.
+ */
+ public final String getType() {
+ return objType;
+ }
+
+ /**
+ * Package private method for writing the data of the EmbeddedObject to a
+ * SX? file.
+ *
+ * @param zip An OfficeZip
instance representing the file
+ * the data is to be written to.
+ */
+ abstract void write(OfficeZip zip) throws IOException;
+
+ /**
+ * Package private method that constructs the manifest.xml entries for this
+ * embedded object.
+ *
+ * @return Document Document
containing the manifest entries.
+ */
+ abstract void writeManifestData(Document manifestDoc) throws DOMException;
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/xmerge/EmbeddedXMLObject.java b/source/java/writer2latex/xmerge/EmbeddedXMLObject.java
new file mode 100644
index 0000000..6f497e7
--- /dev/null
+++ b/source/java/writer2latex/xmerge/EmbeddedXMLObject.java
@@ -0,0 +1,312 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for Writer2LaTeX
+// Version 1.0 (2008-11-23)
+
+package writer2latex.xmerge;
+
+//import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+//import org.xml.sax.EntityResolver;
+//import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * This class represents those embedded objects in an OpenOffice.org document
+ * that have an XML representation. Currently, according to the OpenOffice.org
+ * File Format 1.0 document, there are 6 such objects:
+ *
+ * Formulae created with Math (application/vnd.sun.xml.math)
+ * Charts created with Chart (application/vnd.sun.xml.chart)
+ * Spreadsheets created with Calc (application/vnd.sun.xml.calc)
+ * Text created with Writer (application/vnd.sun.xml.writer)
+ * Drawings created with Draw (application/vnd.sun.xml.draw)
+ * Presentations created with Impress (application/vnd.sun.xml.impress)
+ *
+ * These object types are stored using a combination of content, settings and styles
+ * XML files.
+ */
+public class EmbeddedXMLObject extends EmbeddedObject {
+
+ // Entries for the subdocuments that constitute this object;
+ protected Document contentDOM = null;
+ protected Document settingsDOM = null;
+ protected Document stylesDOM = null;
+
+ private DocumentBuilder builder = null;
+
+ /**
+ * Constructor for an embedded object stored using an XML representation.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ */
+ public EmbeddedXMLObject(String name, String type) {
+ super(name, type);
+ }
+
+ /**
+ * Package private constructor for use when reading an object from a
+ * compressed SX? file.
+ *
+ * @param name The name of the object.
+ * @param type The mime-type of the object. See the class summary.
+ * @param source The OfficeZip representation of the SX? file that stores
+ * the object.
+ */
+ EmbeddedXMLObject(String name, String type, OfficeZip source) {
+ super(name, type, source);
+ }
+
+
+ /**
+ * Returns the content data for this embedded object.
+ *
+ * @return DOM represenation of "content.xml"
+ *
+ * @throws SAXException If any parser error occurs
+ * @throws IOException If any IO error occurs
+ */
+ public Document getContentDOM() throws SAXException, IOException {
+
+ if (contentDOM == null) {
+ contentDOM = getNamedDOM("content.xml");
+ }
+
+ return contentDOM;
+ }
+
+
+ /**
+ * Sets the content data for the embedded object.
+ *
+ * @param content DOM representation of the object's content.
+ */
+ public void setContentDOM(Document content) {
+ contentDOM = content;
+ hasChanged = true;
+ }
+
+
+ /**
+ * Returns the settings data for this embedded object.
+ *
+ * @return DOM represenation of "settings.xml"
+ *
+ * @throws SAXException If any parser error occurs
+ * @throws IOException If any IO error occurs
+ */
+ public Document getSettingsDOM() throws SAXException, IOException {
+
+ if (settingsDOM == null) {
+ settingsDOM = getNamedDOM("settings.xml");
+ }
+
+ return settingsDOM;
+ }
+
+
+ /**
+ * Sets the settings data for the embedded object.
+ *
+ * @param settings DOM representation of the object's settings.
+ */
+ public void setSettingsDOM(Document settings) {
+ settingsDOM = settings;
+ hasChanged = true;
+ }
+
+
+ /**
+ * Returns the style data for this embedded object.
+ *
+ * @return DOM represenation of "styles.xml"
+ *
+ * @throws SAXException If any parser error occurs
+ * @throws IOException If any IO error occurs
+ */
+ public Document getStylesDOM() throws SAXException, IOException {
+
+ if (stylesDOM == null) {
+ stylesDOM = getNamedDOM("styles.xml");
+ }
+
+ return stylesDOM;
+ }
+
+
+ /**
+ * Sets the styles data for the embedded object.
+ *
+ * @param styles DOM representation of the object's styles.
+ */
+ public void setStylesDOM(Document styles) {
+ stylesDOM = styles;
+ hasChanged = true;
+ }
+
+
+ /**
+ * This method extracts the data for the given XML file from the SX? file
+ * and creates a DOM representation of it.
+ *
+ * @param name The name of the XML file to retrieve. It is paired with
+ * the object name to access the SX? file.
+ *
+ * @return DOM representation of the named XML file.
+ *
+ * @throws SAXException If any parser error occurs
+ * @throws IOException If any IO error occurs
+ */
+ private Document getNamedDOM(String name) throws SAXException, IOException {
+ if (zipFile == null) {
+ return null;
+ }
+
+ try {
+ if (builder == null) {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ factory.setValidating(false);
+ builder = factory.newDocumentBuilder();
+ }
+
+ byte[] data = zipFile.getNamedBytes(new String(objName + "/" + name));
+ if (data != null) {
+ return OfficeDocument.parse(builder, data);
+ }
+ else {
+ return null;
+ }
+
+ }
+ catch (SAXException se) {
+ throw se;
+ }
+ catch (IOException ioe) {
+ throw ioe;
+ }
+ catch (ParserConfigurationException pce) {
+ throw new SAXException(pce);
+ }
+ }
+
+
+ /**
+ * Package private method for writing the data of the EmbeddedObject to a
+ * SX? file.
+ *
+ * @param zip An OfficeZip
instance representing the file
+ * the data is to be written to.
+ */
+ void write(OfficeZip zip) throws IOException {
+ if (hasChanged == true) {
+ if (contentDOM != null) {
+ zip.setNamedBytes(new String(objName + "/content.xml"),
+ OfficeDocument.docToBytes(contentDOM));
+ }
+ if (settingsDOM != null) {
+ zip.setNamedBytes(new String(objName + "/settings.xml"),
+ OfficeDocument.docToBytes(settingsDOM));
+ }
+ if (stylesDOM != null) {
+ zip.setNamedBytes(new String(objName + "/styles.xml"),
+ OfficeDocument.docToBytes(stylesDOM));
+ }
+ }
+ }
+
+ /**
+ * Package private method that constructs the manifest.xml entries for this
+ * embedded object.
+ *
+ * @param manifestDoc Document
containing the manifest entries.
+ */
+ void writeManifestData(Document manifestDoc) throws DOMException {
+ Node root = manifestDoc.getDocumentElement();
+
+ if (contentDOM != null) {
+ Element contentNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
+
+ contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
+ new String(objName + "/content.xml"));
+
+ root.appendChild(contentNode);
+ }
+
+ if (settingsDOM != null) {
+ Element settingsNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
+
+ settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
+ new String(objName + "/settings.xml"));
+
+ root.appendChild(settingsNode);
+ }
+
+ if (stylesDOM != null) {
+ Element stylesNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
+
+ stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
+ new String(objName + "/styles.xml"));
+ }
+
+
+ Element objectNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
+
+ objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, objType);
+ objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
+ new String(objName + "/"));
+
+ root.appendChild(objectNode);
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/writer2latex/xmerge/NewDOMDocument.java b/source/java/writer2latex/xmerge/NewDOMDocument.java
new file mode 100644
index 0000000..5bd28f3
--- /dev/null
+++ b/source/java/writer2latex/xmerge/NewDOMDocument.java
@@ -0,0 +1,160 @@
+/************************************************************************
+ *
+ * NewDOMDocument.java
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Copyright: 2002-2006 by Henrik Just
+ *
+ * All Rights Reserved.
+ *
+ * Version 0.5 (2006-10-01)
+ *
+ */
+
+package writer2latex.xmerge;
+
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+
+import writer2latex.xmerge.DOMDocument;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+
+/**
+ * An extension of DOMDocument
+ * that overrides the write method.
+ * (This method fails with the version of xerces shipped with jre 1.5)
+ */
+public class NewDOMDocument extends DOMDocument {
+
+ /** Constructor
+ */
+ public NewDOMDocument(String sFileName, String sExtension) {
+ super(sFileName,sExtension);
+ }
+
+ /**
+ * Write out content to the supplied OutputStream
.
+ * (with pretty printing)
+ * @param os XML OutputStream
.
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
+ osw.write("\n");
+ write(getContentDOM().getDocumentElement(),0,osw);
+ osw.flush();
+ osw.close();
+ }
+
+ // Write nodes; we only need element, text and comment nodes
+ private void write(Node node, int nLevel, OutputStreamWriter osw) throws IOException {
+ short nType = node.getNodeType();
+ switch (nType) {
+ case Node.ELEMENT_NODE:
+ if (node.hasChildNodes()) {
+ // Block pretty print from this node?
+ NodeList list = node.getChildNodes();
+ int nLen = list.getLength();
+ boolean bBlockPrettyPrint = false;
+ if (nLevel>=0) {
+ for (int i = 0; i < nLen; i++) {
+ bBlockPrettyPrint |= list.item(i).getNodeType()==Node.TEXT_NODE;
+ }
+ }
+ // Print start tag
+ if (nLevel>=0) { writeSpaces(nLevel,osw); }
+ osw.write("<"+node.getNodeName());
+ writeAttributes(node,osw);
+ osw.write(">");
+ if (nLevel>=0 && !bBlockPrettyPrint) { osw.write("\n"); }
+ // Print children
+ for (int i = 0; i < nLen; i++) {
+ int nNextLevel;
+ if (bBlockPrettyPrint || nLevel<0) { nNextLevel=-1; }
+ else { nNextLevel=nLevel+1; }
+ write(list.item(i),nNextLevel,osw);
+ }
+ // Print end tag
+ if (nLevel>=0 && !bBlockPrettyPrint) { writeSpaces(nLevel,osw); }
+ osw.write(""+node.getNodeName()+">");
+ if (nLevel>=0) { osw.write("\n"); }
+ }
+ else { // empty element
+ if (nLevel>=0) { writeSpaces(nLevel,osw); }
+ osw.write("<"+node.getNodeName());
+ writeAttributes(node,osw);
+ osw.write(" />");
+ if (nLevel>=0) { osw.write("\n"); }
+ }
+ break;
+ case Node.TEXT_NODE:
+ write(node.getNodeValue(),osw);
+ break;
+ case Node.COMMENT_NODE:
+ if (nLevel>=0) { writeSpaces(nLevel,osw); }
+ osw.write("");
+ if (nLevel>=0) { osw.write("\n"); }
+ }
+ }
+
+ private void writeAttributes(Node node, OutputStreamWriter osw) throws IOException {
+ NamedNodeMap attr = node.getAttributes();
+ int nLen = attr.getLength();
+ for (int i=0; iDocument
for
+ * StarOffice documents.
+ */
+public class OfficeDocument
+ implements writer2latex.xmerge.Document, OfficeConstants {
+
+ /** Factory for DocumentBuilder
objects. */
+ private static DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+
+ /** DOM Document
of content.xml. */
+ private Document contentDoc = null;
+
+ /** DOM Document
of meta.xml. */
+ private Document metaDoc = null;
+
+ /** DOM Document
of settings.xml. */
+ private Document settingsDoc = null;
+
+ /** DOM Document
of content.xml. */
+ private Document styleDoc = null;
+
+ /** DOM Docuemtn
of META-INF/manifest.xml. */
+ private Document manifestDoc = null;
+
+ private String documentName = null;
+ private String fileName = null;
+
+ /** Resources object. */
+ //private Resources res = null;
+
+ /**
+ * OfficeZip
object to store zip contents from
+ * read InputStream
. Note that this member
+ * will still be null if it was initialized using a template
+ * file instead of reading from a StarOffice zipped
+ * XML file.
+ */
+ private OfficeZip zip = null;
+
+ /** Collection to keep track of the embedded objects in the document. */
+ private Map embeddedObjects = null;
+
+ /**
+ * Default constructor.
+ *
+ * @param name Document
name.
+ */
+ public OfficeDocument(String name)
+ {
+ this(name, true, false);
+ }
+
+
+ /**
+ * Constructor with arguments to set namespaceAware
+ * and validating
flags.
+ *
+ * @param name Document
name (may or may not
+ * contain extension).
+ * @param namespaceAware Value for namespaceAware
flag.
+ * @param validating Value for validating
flag.
+ */
+ public OfficeDocument(String name, boolean namespaceAware, boolean validating) {
+
+ //res = Resources.getInstance();
+ factory.setValidating(validating);
+ factory.setNamespaceAware(namespaceAware);
+ this.documentName = trimDocumentName(name);
+ this.fileName = documentName + getFileExtension();
+ }
+
+
+ /**
+ * Removes the file extension from the Document
+ * name.
+ *
+ * @param name Full Document
name with extension.
+ *
+ * @return Name of Document
without the extension.
+ */
+ private String trimDocumentName(String name) {
+ String temp = name.toLowerCase();
+ String ext = getFileExtension();
+
+ if (temp.endsWith(ext)) {
+ // strip the extension
+ int nlen = name.length();
+ int endIndex = nlen - ext.length();
+ name = name.substring(0,endIndex);
+ }
+
+ return name;
+ }
+
+ // FIX2 (HJ): Determine wether this is package or flat format
+ /** Package or flat format?
+ * @return true if the document is in package format, false if it's flat xml
+ */
+ public boolean isPackageFormat() { return zip!=null; }
+
+ /**
+ * Return a DOM Document
object of the content.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the read
method or the
+ * initContentDOM
method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM Document
object.
+ */
+ public Document getContentDOM() {
+
+ return contentDoc;
+ }
+
+ /**
+ * Return a DOM Document
object of the meta.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the read
method or the
+ * initContentDOM
method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM Document
object.
+ */
+ public Document getMetaDOM() {
+
+ return metaDoc;
+ }
+
+
+ /**
+ * Return a DOM Document
object of the settings.xml
+ * file. Note that a content DOM is not created when the constructor
+ * is called. So, either the read
method or the
+ * initContentDOM
method will need to be called ahead
+ * on this object before calling this method.
+ *
+ * @return DOM Document
object.
+ */
+ public Document getSettingsDOM() {
+
+ return settingsDoc;
+ }
+
+
+ /**
+ * Sets the content tree of the document.
+ *
+ * @param newDom Node
containing the new content tree.
+ */
+ public void setContentDOM( Node newDom) {
+ contentDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the meta tree of the document.
+ *
+ * @param newDom Node
containing the new meta tree.
+ */
+ public void setMetaDOM (Node newDom) {
+ metaDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the settings tree of the document.
+ *
+ * @param newDom Node
containing the new settings tree.
+ */
+ public void setSettingsDOM (Node newDom) {
+ settingsDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Sets the style tree of the document.
+ *
+ * @param newDom Node
containing the new style tree.
+ */
+ public void setStyleDOM (Node newDom) {
+ styleDoc = (Document)newDom;
+ }
+
+
+ /**
+ * Return a DOM Document
object of the style.xml file.
+ * Note that this may return null if there is no style DOM.
+ * Note that a style DOM is not created when the constructor
+ * is called. Depending on the InputStream
, a
+ * read
method may or may not build a style DOM. When
+ * creating a new style DOM, call the initStyleDOM
method
+ * first.
+ *
+ * @return DOM Document
object.
+ */
+ public Document getStyleDOM() {
+
+ return styleDoc;
+ }
+
+
+ /**
+ * Return the name of the Document
.
+ *
+ * @return The name of Document
.
+ */
+ public String getName() {
+
+ return documentName;
+ }
+
+
+ /**
+ * Return the file name of the Document
, possibly
+ * with the standard extension.
+ *
+ * @return The file name of Document
.
+ */
+ public String getFileName() {
+
+ return fileName;
+ }
+
+
+ /**
+ * Returns the file extension for this type of
+ * Document
.
+ *
+ * @return The file extension of Document
.
+ */
+ // TODO: is this used?
+ protected String getFileExtension() { return ""; }
+
+
+ /**
+ * Returns all the embedded objects (graphics, formulae, etc.) present in
+ * this document.
+ *
+ * @return An Iterator
of EmbeddedObject
objects.
+ */
+ public Iterator getEmbeddedObjects() {
+
+ if (embeddedObjects == null && manifestDoc != null) {
+ embeddedObjects = new HashMap();
+
+ // Need to read the manifest file and construct a list of objects
+ NodeList nl = manifestDoc.getElementsByTagName(TAG_MANIFEST_FILE);
+
+ // Dont create the HashMap if there are no embedded objects
+ int len = nl.getLength();
+ for (int i = 0; i < len; i++) {
+ Node n = nl.item(i);
+
+ NamedNodeMap attrs = n.getAttributes();
+
+ String type = attrs.getNamedItem(ATTRIBUTE_MANIFEST_FILE_TYPE).getNodeValue();
+ String path = attrs.getNamedItem(ATTRIBUTE_MANIFEST_FILE_PATH).getNodeValue();
+
+
+ /*
+ * According to OpenOffice.org XML File Format document (ver. 1)
+ * there are only two types of embedded object:
+ *
+ * Objects with an XML representation.
+ * Objects without an XML representation.
+ *
+ * The former are represented by one or more XML files.
+ * The latter are in binary form.
+ */
+ // FIX2 (HJ): Allow either OOo 1.x or OpenDocument embedded objects
+ if (type.startsWith("application/vnd.sun.xml") || type.startsWith("application/vnd.oasis.opendocument"))
+ {
+ if (path.equals("/")) {
+ // Exclude the main document entries
+ continue;
+ }
+ // Take off the trailing '/'
+ String name = path.substring(0, path.length() - 1);
+ embeddedObjects.put(name, new EmbeddedXMLObject(name, type, zip));
+ }
+ else if (type.equals("text/xml")) {
+ // XML entries are either embedded StarOffice doc entries or main
+ // document entries
+ continue;
+ }
+ else { // FIX (HJ): allows empty MIME type
+ embeddedObjects.put(path, new EmbeddedBinaryObject(path, type, zip));
+ }
+ }
+ }
+
+ return embeddedObjects.values().iterator();
+ }
+
+ /**
+ * Returns the embedded object corresponding to the name provided.
+ * The name should be stripped of any preceding path characters, such as
+ * '/', '.' or '#'.
+ *
+ * @param name The name of the embedded object to retrieve.
+ *
+ * @return An EmbeddedObject
instance representing the named
+ * object.
+ */
+ public EmbeddedObject getEmbeddedObject(String name) {
+ if (name == null) {
+ return null;
+ }
+
+ if (embeddedObjects == null) {
+ // FIX2 (HJ): Return null if there's no manifest
+ if (manifestDoc != null) {
+ getEmbeddedObjects();
+ }
+ else {
+ return null;
+ }
+ }
+
+ if (embeddedObjects.containsKey(name)) {
+ return (EmbeddedObject)embeddedObjects.get(name);
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Adds a new embedded object to the document.
+ *
+ * @param embObj An instance of EmbeddedObject
.
+ */
+ public void addEmbeddedObject(EmbeddedObject embObj) {
+ if (embObj == null) {
+ return;
+ }
+
+ if (embeddedObjects == null) {
+ embeddedObjects = new HashMap();
+ }
+
+ embeddedObjects.put(embObj.getName(), embObj);
+ }
+
+
+ /**
+ * Read the Office Document
from the given
+ * InputStream
.
+ * FIX3 (HJ): Perform simple type detection to determine package or flat format
+ *
+ * @param is Office document InputStream
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is) throws IOException {
+ byte[] doc = Misc.inputStreamToByteArray(is);
+ boolean bZip = MIMETypes.ZIP.equals(MIMETypes.getMagicMIMEType(doc));
+ // if it's zip, assume package - otherwise assume flat
+ read(new ByteArrayInputStream(doc),bZip);
+ }
+
+ private void readZip(InputStream is) throws IOException {
+
+ // Debug.log(Debug.INFO, "reading Office file");
+
+ DocumentBuilder builder = null;
+
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ throw new OfficeDocumentException(ex);
+ }
+
+ // read in Office zip file format
+
+ zip = new OfficeZip();
+ zip.read(is);
+
+ // grab the content.xml and
+ // parse it into contentDoc.
+
+ byte contentBytes[] = zip.getContentXMLBytes();
+
+ if (contentBytes == null) {
+
+ throw new OfficeDocumentException("Entry content.xml not found in file");
+ }
+
+ try {
+
+ contentDoc = parse(builder, contentBytes);
+
+ } catch (SAXException ex) {
+
+ throw new OfficeDocumentException(ex);
+ }
+
+ // if style.xml exists, grab the style.xml
+ // parse it into styleDoc.
+
+ byte styleBytes[] = zip.getStyleXMLBytes();
+
+ if (styleBytes != null) {
+
+ try {
+
+ styleDoc = parse(builder, styleBytes);
+
+ } catch (SAXException ex) {
+
+ throw new OfficeDocumentException(ex);
+ }
+ }
+
+ byte metaBytes[] = zip.getMetaXMLBytes();
+
+ if (metaBytes != null) {
+
+ try {
+
+ metaDoc = parse(builder, metaBytes);
+
+ } catch (SAXException ex) {
+
+ throw new OfficeDocumentException(ex);
+ }
+ }
+
+ byte settingsBytes[] = zip.getSettingsXMLBytes();
+
+ if (settingsBytes != null) {
+
+ try {
+
+ settingsDoc = parse(builder, settingsBytes);
+
+ } catch (SAXException ex) {
+
+ throw new OfficeDocumentException(ex);
+ }
+ }
+
+
+ // Read in the META-INF/manifest.xml file
+ byte manifestBytes[] = zip.getManifestXMLBytes();
+
+ if (manifestBytes != null) {
+
+ try {
+ manifestDoc = parse(builder, manifestBytes);
+ } catch (SAXException ex) {
+ throw new OfficeDocumentException(ex);
+ }
+ }
+
+ }
+
+
+ /**
+ * Read the Office Document
from the given
+ * InputStream
.
+ *
+ * @param is Office document InputStream
.
+ * @param isZip boolean
Identifies whether
+ * a file is zipped or not
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void read(InputStream is, boolean isZip) throws IOException {
+
+ // Debug.log(Debug.INFO, "reading Office file");
+
+ DocumentBuilder builder = null;
+
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException ex) {
+ throw new OfficeDocumentException(ex);
+ }
+
+ if (isZip)
+ {
+ readZip(is);
+ }
+ else{
+ try{
+ //contentDoc= builder.parse((InputStream)is);
+
+ Reader r = secondHack(is);
+ InputSource ins = new InputSource(r);
+ org.w3c.dom.Document newDoc = builder.parse(ins);
+ //org.w3c.dom.Document newDoc = builder.parse((InputStream)is);
+ Element rootElement=newDoc.getDocumentElement();
+
+ NodeList nodeList;
+ Node tmpNode;
+ Node rootNode = (Node)rootElement;
+ if (newDoc !=null){
+ /*content*/
+ contentDoc = createDOM(TAG_OFFICE_DOCUMENT_CONTENT);
+ rootElement=contentDoc.getDocumentElement();
+ rootNode = (Node)rootElement;
+
+ // FIX (HJ): Include office:font-decls in content DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_FONT_DECLS);
+ if (nodeList.getLength()>0){
+ tmpNode = contentDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ // FIX2 (HJ): Include office:font-face-decls (OpenDocument) in content DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_FONT_FACE_DECLS);
+ if (nodeList.getLength()>0){
+ tmpNode = contentDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = contentDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ if (nodeList.getLength()>0){
+ tmpNode = contentDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ /*Styles*/
+ styleDoc = createDOM(TAG_OFFICE_DOCUMENT_STYLES);
+ rootElement=styleDoc.getDocumentElement();
+ rootNode = (Node)rootElement;
+
+ // FIX (HJ): Include office:font-decls in styles DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_FONT_DECLS);
+ if (nodeList.getLength()>0){
+ tmpNode = styleDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ // FIX2 (HJ): Include office:font-face-decls in styles DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_FONT_FACE_DECLS);
+ if (nodeList.getLength()>0){
+ tmpNode = styleDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = styleDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ // FIX (HJ): Include office:automatic-styles in styles DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = styleDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ // FIX (HJ): Include office:master-styles in styles DOM
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_MASTER_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = styleDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ /*Settings*/
+ settingsDoc = createDOM(TAG_OFFICE_DOCUMENT_SETTINGS);
+ rootElement=settingsDoc.getDocumentElement();
+ rootNode = (Node)rootElement;
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_SETTINGS);
+ if (nodeList.getLength()>0){
+ tmpNode = settingsDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ /*Meta*/
+ metaDoc = createDOM(TAG_OFFICE_DOCUMENT_META);
+ rootElement=metaDoc.getDocumentElement();
+ rootNode = (Node)rootElement;
+ nodeList= newDoc.getElementsByTagName(TAG_OFFICE_META);
+ if (nodeList.getLength()>0){
+ tmpNode = metaDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ }
+ }
+ catch (SAXException ex) {
+ throw new OfficeDocumentException(ex);
+ }
+ }
+
+ }
+
+
+
+ /**
+ * Parse given byte
array into a DOM
+ * Document
object using the
+ * DocumentBuilder
object.
+ *
+ * @param builder DocumentBuilder
object for parsing.
+ * @param bytes byte
array for parsing.
+ *
+ * @return Resulting DOM Document
object.
+ *
+ * @throws SAXException If any parsing error occurs.
+ */
+ static Document parse(DocumentBuilder builder, byte bytes[])
+ throws SAXException, IOException {
+
+ Document doc = null;
+
+ ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+
+ // TODO: replace hack with a more appropriate fix.
+
+ Reader r = hack(is);
+ InputSource ins = new InputSource(r);
+ doc = builder.parse(ins);
+
+ return doc;
+ }
+
+
+ /**
+ * Method to return the MIME type of the document.
+ *
+ * @return String The document's MIME type.
+ */
+ // not really used...
+ protected String getDocumentMimeType() { return ""; }
+
+
+ /**
+ * Write out Office ZIP file format.
+ *
+ * @param os XML OutputStream
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os) throws IOException {
+ if (zip == null) {
+ zip = new OfficeZip();
+ }
+
+ initManifestDOM();
+
+ Element domEntry;
+ Element manifestRoot = manifestDoc.getDocumentElement();
+
+ // The EmbeddedObjects come first.
+ Iterator embObjs = getEmbeddedObjects();
+ while (embObjs.hasNext()) {
+ EmbeddedObject obj = (EmbeddedObject)embObjs.next();
+ obj.writeManifestData(manifestDoc);
+
+ obj.write(zip);
+ }
+
+ // Add in the entry for the Pictures directory. Always present.
+ domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE);
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "Pictures/");
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "");
+ manifestRoot.appendChild(domEntry);
+
+ // Write content to the Zip file and then write any of the optional
+ // data, if it exists.
+ zip.setContentXMLBytes(docToBytes(contentDoc));
+
+ domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE);
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "content.xml");
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+
+ manifestRoot.appendChild(domEntry);
+
+ if (styleDoc != null) {
+ zip.setStyleXMLBytes(docToBytes(styleDoc));
+
+ domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE);
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "styles.xml");
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ manifestRoot.appendChild(domEntry);
+ }
+
+ if (metaDoc != null) {
+ zip.setMetaXMLBytes(docToBytes(metaDoc));
+
+ domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE);
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "meta.xml");
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ manifestRoot.appendChild(domEntry);
+ }
+
+ if (settingsDoc != null) {
+ zip.setSettingsXMLBytes(docToBytes(settingsDoc));
+
+ domEntry = manifestDoc.createElement(TAG_MANIFEST_FILE);
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_PATH, "settings.xml");
+ domEntry.setAttribute(ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
+ manifestRoot.appendChild(domEntry);
+ }
+
+ zip.setManifestXMLBytes(docToBytes(manifestDoc));
+
+ zip.write(os);
+ }
+
+
+ /**
+ * Write out Office ZIP file format.
+ *
+ * @param os XML OutputStream
.
+ * @param isZip boolean
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public void write(OutputStream os, boolean isZip) throws IOException {
+
+ // Create an OfficeZip object if one does not exist.
+ if (isZip){
+ write(os);
+ }
+ else{
+ try{
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder= builderFactory.newDocumentBuilder();
+ DOMImplementation domImpl = builder.getDOMImplementation();
+ domImpl.createDocumentType("office:document","-//OpenOffice.org//DTD OfficeDocument 1.0//EN",null);
+ org.w3c.dom.Document newDoc = domImpl.createDocument("http://openoffice.org/2000/office","office:document",null);
+
+
+ Element rootElement=newDoc.getDocumentElement();
+ rootElement.setAttribute("xmlns:office","http://openoffice.org/2000/office");
+ rootElement.setAttribute("xmlns:style","http://openoffice.org/2000/style" );
+ rootElement.setAttribute("xmlns:text","http://openoffice.org/2000/text");
+ rootElement.setAttribute("xmlns:table","http://openoffice.org/2000/table");
+
+ rootElement.setAttribute("xmlns:draw","http://openoffice.org/2000/drawing");
+ rootElement.setAttribute("xmlns:fo","http://www.w3.org/1999/XSL/Format" );
+ rootElement.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink" );
+ rootElement.setAttribute("xmlns:dc","http://purl.org/dc/elements/1.1/" );
+ rootElement.setAttribute("xmlns:meta","http://openoffice.org/2000/meta" );
+ rootElement.setAttribute("xmlns:number","http://openoffice.org/2000/datastyle" );
+ rootElement.setAttribute("xmlns:svg","http://www.w3.org/2000/svg" );
+ rootElement.setAttribute("xmlns:chart","http://openoffice.org/2000/chart" );
+ rootElement.setAttribute("xmlns:dr3d","http://openoffice.org/2000/dr3d" );
+ rootElement.setAttribute("xmlns:math","http://www.w3.org/1998/Math/MathML" );
+ rootElement.setAttribute("xmlns:form","http://openoffice.org/2000/form" );
+ rootElement.setAttribute("xmlns:script","http://openoffice.org/2000/script" );
+ rootElement.setAttribute("xmlns:config","http://openoffice.org/2001/config" );
+ // #i41033# OASIS format needs the "office:class" set.
+ if(getDocumentMimeType() == SXC_MIME_TYPE)
+ rootElement.setAttribute("office:class","spreadsheet" );
+ else if(getDocumentMimeType() == SXW_MIME_TYPE)
+ rootElement.setAttribute("office:class","text" );
+ rootElement.setAttribute("office:version","1.0");
+
+
+ NodeList nodeList;
+ Node tmpNode;
+ Node rootNode = (Node)rootElement;
+ if (metaDoc !=null){
+ nodeList= metaDoc.getElementsByTagName(TAG_OFFICE_META);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ }if (styleDoc !=null){
+ nodeList= styleDoc.getElementsByTagName(TAG_OFFICE_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ }if (settingsDoc !=null){
+ nodeList= settingsDoc.getElementsByTagName(TAG_OFFICE_SETTINGS);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ }
+ if (contentDoc !=null){
+ nodeList= contentDoc.getElementsByTagName(TAG_OFFICE_AUTOMATIC_STYLES);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+
+ nodeList= contentDoc.getElementsByTagName(TAG_OFFICE_BODY);
+ if (nodeList.getLength()>0){
+ tmpNode = newDoc.importNode(nodeList.item(0),true);
+ rootNode.appendChild(tmpNode);
+ }
+ }
+
+ byte contentBytes[] = docToBytes(newDoc);
+ os.write(contentBytes);
+ }
+ catch(Exception exc){
+ System.err.println("\nException in OfficeDocument.write():" +exc);
+ }
+ //byte contentBytes[] = docToBytes(contentDoc);
+ }
+ }
+
+
+ /**
+ * Write out a org.w3c.dom.Document
object into a
+ * byte
array.
TODO: remove dependency on com.sun.xml.tree.XmlDocument + * package!
+ * + * @param Document DOMDocument
object.
+ *
+ * @return byte
array of DOM Document
+ * object.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ static byte[] docToBytes(Document doc)
+ throws IOException {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ java.lang.reflect.Constructor con;
+ java.lang.reflect.Method meth;
+
+ String domImpl = doc.getClass().getName();
+
+ /*
+ * We may have multiple XML parsers in the Classpath.
+ * Depending on which one is first, the actual type of
+ * doc may vary. Need a way to find out which API is being
+ * used and use an appropriate serialization method.
+ */
+ try {
+ // First of all try for JAXP 1.0
+ if (domImpl.equals("com.sun.xml.tree.XmlDocument")) {
+
+ // Debug.log(Debug.INFO, "Using JAXP");
+
+ Class jaxpDoc = Class.forName("com.sun.xml.tree.XmlDocument");
+
+ // The method is in the XMLDocument class itself, not a helper
+ meth = jaxpDoc.getMethod("write",
+ new Class[] { Class.forName("java.io.OutputStream") } );
+
+ meth.invoke(doc, new Object [] { baos } );
+ }
+ else if (domImpl.equals("org.apache.crimson.tree.XmlDocument"))
+ {
+ // Debug.log(Debug.INFO, "Using Crimson");
+
+ Class crimsonDoc = Class.forName("org.apache.crimson.tree.XmlDocument");
+ // The method is in the XMLDocument class itself, not a helper
+ meth = crimsonDoc.getMethod("write",
+ new Class[] { Class.forName("java.io.OutputStream") } );
+
+ meth.invoke(doc, new Object [] { baos } );
+ }
+ else if (domImpl.equals("org.apache.xerces.dom.DocumentImpl")
+ || domImpl.equals("org.apache.xerces.dom.DeferredDocumentImpl")) {
+
+ // Debug.log(Debug.INFO, "Using Xerces");
+
+ // Try for Xerces
+ Class xercesSer =
+ Class.forName("org.apache.xml.serialize.XMLSerializer");
+
+ // Get the OutputStream constructor
+ // May want to use the OutputFormat parameter at some stage too
+ con = xercesSer.getConstructor(new Class []
+ { Class.forName("java.io.OutputStream"),
+ Class.forName("org.apache.xml.serialize.OutputFormat") } );
+
+
+ // Get the serialize method
+ meth = xercesSer.getMethod("serialize",
+ new Class [] { Class.forName("org.w3c.dom.Document") } );
+
+
+ // Get an instance
+ Object serializer = con.newInstance(new Object [] { baos, null } );
+
+
+ // Now call serialize to write the document
+ meth.invoke(serializer, new Object [] { doc } );
+ }
+ else {
+ // We don't have another parser
+ throw new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl);
+ }
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new IOException(cnfe.toString());
+ }
+ catch (Exception e) {
+ // We may get some other errors, but the bottom line is that
+ // the steps being executed no longer work
+ throw new IOException(e.toString());
+ }
+
+ byte bytes[] = baos.toByteArray();
+
+ return bytes;
+ }
+
+
+ /**
+ * Initializes a new DOM Document
with the content
+ * containing minimum OpenOffice XML tags.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public final void initContentDOM() throws IOException {
+
+ contentDoc = createDOM(TAG_OFFICE_DOCUMENT_CONTENT);
+
+ // this is a work-around for a bug in Office6.0 - not really
+ // needed but StarCalc 6.0 will crash without this tag.
+ Element root = contentDoc.getDocumentElement();
+
+ Element child = contentDoc.createElement(TAG_OFFICE_FONT_DECLS);
+ root.appendChild(child);
+
+ child = contentDoc.createElement(TAG_OFFICE_AUTOMATIC_STYLES);
+ root.appendChild(child);
+
+ child = contentDoc.createElement(TAG_OFFICE_BODY);
+ root.appendChild(child);
+ }
+
+ /**
+ * Initializes a new DOM Document
with the content
+ * containing minimum OpenOffice XML tags.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public final void initSettingsDOM() throws IOException {
+
+ settingsDoc = createSettingsDOM(TAG_OFFICE_DOCUMENT_SETTINGS);
+
+ // this is a work-around for a bug in Office6.0 - not really
+ // needed but StarCalc 6.0 will crash without this tag.
+ Element root = settingsDoc.getDocumentElement();
+
+ Element child = settingsDoc.createElement(TAG_OFFICE_SETTINGS);
+ root.appendChild(child);
+ }
+
+ /**
+ * Initializes a new DOM Document with styles
+ * containing minimum OpenOffice XML tags.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ public final void initStyleDOM() throws IOException {
+
+ styleDoc = createDOM(TAG_OFFICE_DOCUMENT_STYLES);
+ }
+
+ /**
+ * Creates a new DOM Document
containing minimum
+ * OpenOffice XML tags.
This method uses the subclass
+ * getOfficeClassAttribute
method to get the
+ * attribute for office:class.
Document
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private final Document createSettingsDOM(String rootName) throws IOException {
+
+ Document doc = null;
+
+ try {
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ doc = builder.newDocument();
+
+ } catch (ParserConfigurationException ex) {
+
+ throw new OfficeDocumentException(ex);
+
+ }
+
+ Element root = (Element) doc.createElement(rootName);
+ doc.appendChild(root);
+
+ root.setAttribute("xmlns:office", "http://openoffice.org/2000/office");
+ root.setAttribute("xmlns:xlink", "http://openoffice.org/1999/xlink");
+ root.setAttribute("xmlns:config", "http://openoffice.org/2001/config");
+ root.setAttribute("office:version", "1.0");
+
+ return doc;
+ }
+
+
+ /**
+ * Creates a new DOM Document
containing minimum
+ * OpenOffice XML tags.
This method uses the subclass
+ * getOfficeClassAttribute
method to get the
+ * attribute for office:class.
Document
.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private final Document createDOM(String rootName) throws IOException {
+
+ Document doc = null;
+
+ try {
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ doc = builder.newDocument();
+
+ } catch (ParserConfigurationException ex) {
+
+ throw new OfficeDocumentException(ex);
+
+ }
+
+ Element root = (Element) doc.createElement(rootName);
+ doc.appendChild(root);
+
+ root.setAttribute("xmlns:office", "http://openoffice.org/2000/office");
+ root.setAttribute("xmlns:style", "http://openoffice.org/2000/style");
+ root.setAttribute("xmlns:text", "http://openoffice.org/2000/text");
+ root.setAttribute("xmlns:table", "http://openoffice.org/2000/table");
+ root.setAttribute("xmlns:draw", "http://openoffice.org/2000/drawing");
+ root.setAttribute("xmlns:fo", "http://www.w3.org/1999/XSL/Format");
+ root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
+ root.setAttribute("xmlns:number", "http://openoffice.org/2000/datastyle");
+ root.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");
+ root.setAttribute("xmlns:chart", "http://openoffice.org/2000/chart");
+ root.setAttribute("xmlns:dr3d", "http://openoffice.org/2000/dr3d");
+ root.setAttribute("xmlns:math", "http://www.w3.org/1998/Math/MathML");
+ root.setAttribute("xmlns:form", "http://openoffice.org/2000/form");
+ root.setAttribute("xmlns:script", "http://openoffice.org/2000/script");
+ root.setAttribute("office:class", getOfficeClassAttribute());
+ root.setAttribute("office:version", "1.0");
+
+ return doc;
+ }
+
+
+ /**
+ * Return the office:class attribute value.
+ *
+ * @return The attribute value.
+ */
+ // not really used...
+ protected String getOfficeClassAttribute() { return ""; }
+
+
+ /**
+ * Hacked code to filter tag before + * sending stream to parser.
+ * + *This hacked code needs to be changed later on.
+ * + *Issue: using current jaxp1.0 parser, there is no way + * to turn off processing of dtds. Current set of dtds + * have bugs, processing them will throw exceptions.
+ * + *This is a simple hack that assumes the whole + * tag are all in the same line. This is sufficient for + * current StarOffice 6.0 generated XML files. Since this + * hack really needs to go away, I don't want to spend + * too much time in making it a perfect hack.
+ * FIX (HJ): Removed requirement for DOCTYPE to be in one line + * FIX (HJ): No longer removes newlines + * + * @param isInputStream
to be filtered.
+ *
+ * @return Reader value without the tag.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private static Reader hack(InputStream is) throws IOException {
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ StringBuffer buffer = new StringBuffer();
+
+ String str = null;
+
+ while ((str = br.readLine()) != null) {
+
+ int sIndex = str.indexOf(" -1) {
+
+ buffer.append(str.substring(0, sIndex));
+
+ int eIndex = str.indexOf('>', sIndex + 8 );
+
+ if (eIndex > -1) {
+
+ buffer.append(str.substring(eIndex + 1, str.length()));
+ // FIX (HJ): Preserve the newline
+ buffer.append("\n");
+
+ } else {
+
+ // FIX (HJ): More than one line. Search for '>' in following lines
+ boolean bOK = false;
+ while ((str = br.readLine())!=null) {
+ eIndex = str.indexOf('>');
+ if (eIndex>-1) {
+ buffer.append(str.substring(eIndex+1));
+ // FIX (HJ): Preserve the newline
+ buffer.append("\n");
+ bOK = true;
+ break;
+ }
+ }
+
+ if (!bOK) { throw new IOException("Invalid XML"); }
+ }
+
+ } else {
+
+ buffer.append(str);
+ // FIX (HJ): Preserve the newline
+ buffer.append("\n");
+ }
+ }
+
+ StringReader r = new StringReader(buffer.toString());
+ return r;
+ }
+
+ /**
+ * Transform the InputStream to a Reader Stream.
+ * + *This hacked code needs to be changed later on.
+ * + *Issue: the new oasis input file stream means + * that the old input stream fails. see #i33702#
+ * + * @param isInputStream
to be filtered.
+ *
+ * @return Reader value of the InputStream().
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ private static Reader secondHack(InputStream is) throws IOException {
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ char[] charArray = new char[4096];
+ StringBuffer sBuf = new StringBuffer();
+ int n = 0;
+ while ((n=br.read(charArray, 0, charArray.length)) > 0)
+ sBuf.append(charArray, 0, n);
+
+ // ensure there is no trailing garbage after the end of the stream.
+ int sIndex = sBuf.lastIndexOf("");
+ sBuf.delete(sIndex, sBuf.length());
+ sBuf.append("");
+ StringReader r = new StringReader(sBuf.toString());
+ return r;
+ }
+
+
+ /**
+ * Method to create the initial entries in the manifest.xml file stored
+ * in an SX? file.
+ */
+ private void initManifestDOM() throws IOException {
+
+ try {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ DOMImplementation domImpl = builder.getDOMImplementation();
+
+ DocumentType docType = domImpl.createDocumentType(TAG_MANIFEST_ROOT,
+ "-//OpenOffice.org//DTD Manifest 1.0//EN",
+ "Manifest.dtd");
+ manifestDoc = domImpl.createDocument("manifest", TAG_MANIFEST_ROOT, docType);
+ } catch (ParserConfigurationException ex) {
+ throw new OfficeDocumentException(ex);
+ }
+
+ // Add the SAXParseException
.
+ *
+ * @author Herbie Ong
+ */
+
+public final class OfficeDocumentException extends IOException {
+
+ StringBuffer message = null;
+
+
+ /**
+ * Constructor, capturing additional information from the
+ * SAXException
.
+ *
+ * @param e The SAXException
.
+ */
+ public OfficeDocumentException(SAXException e) {
+ super(e.toString());
+ message = new StringBuffer();
+ if (e instanceof SAXParseException) {
+ String msgParseError =
+ "PARSE_ERROR";
+ String msgLine =
+ "LINE";
+ String msgColumn =
+ "COLUMN";
+ String msgPublicId =
+ "PUBLIC_ID";
+ String msgSystemId =
+ "SYSTEM_ID";
+ SAXParseException spe = (SAXParseException) e;
+ message.append(msgParseError);
+ message.append(": ");
+ message.append(msgLine);
+ message.append(": ");
+ message.append(spe.getLineNumber());
+ message.append(", ");
+ message.append(msgColumn);
+ message.append(": ");
+ message.append(spe.getColumnNumber());
+ message.append(", ");
+ message.append(msgSystemId);
+ message.append(": ");
+ message.append(spe.getSystemId());
+ message.append(", ");
+ message.append(msgPublicId);
+ message.append(": ");
+ message.append(spe.getPublicId());
+ message.append("\n");
+ }
+
+ // if there exists an embedded exception
+ Exception ex = e.getException();
+ if (ex != null) {
+ message.append(ex.getMessage());
+ }
+ }
+
+
+ /**
+ * Constructor, creates exception with provided message.
+ *
+ * @param s Message value for the exception.
+ */
+ public OfficeDocumentException(String s) {
+ super(s);
+ }
+
+
+ /**
+ * Constructor, creates exception with the message
+ * corresponding to the message value of the provided
+ * exception.
+ *
+ * @param e The Exception.
+ */
+ public OfficeDocumentException(Exception e) {
+ super(e.getMessage());
+ }
+
+
+ /**
+ * Returns the message value for the Exception
.
+ *
+ * @return The message value for the Exception
.
+ */
+ public String getMessage() {
+ return message.toString() + super.getMessage();
+ }
+}
+
diff --git a/source/java/writer2latex/xmerge/OfficeZip.java b/source/java/writer2latex/xmerge/OfficeZip.java
new file mode 100644
index 0000000..6de0010
--- /dev/null
+++ b/source/java/writer2latex/xmerge/OfficeZip.java
@@ -0,0 +1,473 @@
+/************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ *
+ * - GNU Lesser General Public License Version 2.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// This version is adapted for Writer2LaTeX
+// Version 1.0 (2008-11-22)
+
+package writer2latex.xmerge;
+
+import java.util.List;
+import java.util.ListIterator;
+import java.util.LinkedList;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.CRC32;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+
+//import org.openoffice.xmerge.util.Debug;
+
+/**
+ * Class used by {@link
+ * org.openoffice.xmerge.converter.OfficeDocument
+ * OfficeDocument} to handle reading and writing
+ * from a ZIP file, as well as storing ZIP entries.
+ *
+ * @author Herbie Ong
+ */
+class OfficeZip {
+
+ /** File name of the XML file in a zipped document. */
+ private final static String CONTENTXML = "content.xml";
+
+ private final static String STYLEXML = "styles.xml";
+ private final static String METAXML = "meta.xml";
+ private final static String SETTINGSXML = "settings.xml";
+ private final static String MANIFESTXML = "META-INF/manifest.xml";
+
+ private final static int BUFFERSIZE = 1024;
+
+ private List entryList = null;
+
+ private int contentIndex = -1;
+ private int styleIndex = -1;
+ private int metaIndex = -1;
+ private int settingsIndex = -1;
+ private int manifestIndex = -1;
+
+ /** Default constructor. */
+ OfficeZip() {
+
+ entryList = new LinkedList();
+ }
+
+
+ /**
+ * Read each zip entry in the InputStream
object
+ * and store in entryList both the ZipEntry
object
+ * as well as the bits of each entry. Call this method before
+ * calling the getContentXMLBytes
method or the
+ * getStyleXMLBytes
method.
Keep track of the CONTENTXML and STYLEXML using + * contentIndex and styleIndex, respectively.
+ * + * @param isInputStream
object to read.
+ *
+ * @throws IOException If any I/O error occurs.
+ */
+ void read(InputStream is) throws IOException {
+
+ ZipInputStream zis = new ZipInputStream(is);
+ ZipEntry ze = null;
+ int i = -1;
+
+ while ((ze = zis.getNextEntry()) != null) {
+
+ String name = ze.getName();
+ //System.out.println("Found "+name);
+
+ // Debug.log(Debug.TRACE, "reading entry: " + name);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ int len = 0;
+ byte buffer[] = new byte[BUFFERSIZE];
+
+ while ((len = zis.read(buffer)) > 0) {
+ baos.write(buffer, 0, len);
+ }
+
+ byte bytes[] = baos.toByteArray();
+ Entry entry = new Entry(ze,bytes);
+
+ entryList.add(entry);
+
+ i++;
+
+ if (name.equalsIgnoreCase(CONTENTXML)) {
+ contentIndex = i;
+ }
+ else if (name.equalsIgnoreCase(STYLEXML)) {
+ styleIndex = i;
+ }
+ else if (name.equalsIgnoreCase(METAXML)) {
+ metaIndex = i;
+ }
+ else if (name.equalsIgnoreCase(SETTINGSXML)) {
+ settingsIndex = i;
+ }
+ else if (name.equalsIgnoreCase(MANIFESTXML)) {
+ manifestIndex = i;
+ }
+
+ }
+
+ zis.close();
+ }
+
+
+ /**
+ * This method returns the CONTENTXML file in a
+ * byte
array. It returns null if there is no
+ * CONTENTXML in this zip file.
+ *
+ * @return CONTENTXML in a byte
array.
+ */
+ byte[] getContentXMLBytes() {
+
+ return getEntryBytes(contentIndex);
+ }
+
+
+ /**
+ * This method returns the STYLEXML file in a
+ * byte
array. It returns null if there is
+ * no STYLEXML in this zip file.
+ *
+ * @return STYLEXML in a byte
array.
+ */
+ byte[] getStyleXMLBytes() {
+
+ return getEntryBytes(styleIndex);
+ }
+
+ /**
+ * This method returns the METAXML file in a
+ * byte
array. It returns null if there is
+ * no METAXML in this zip file.
+ *
+ * @return METAXML in a byte
array.
+ */
+ byte[] getMetaXMLBytes() {
+ return getEntryBytes(metaIndex);
+ }
+
+ /**
+ * This method returns the SETTINGSXML file in a
+ * byte
array. It returns null if there is
+ * no SETTINGSXML in this zip file.
+ *
+ * @return SETTINGSXML in a byte
array.
+ */
+ byte[] getSettingsXMLBytes() {
+ return getEntryBytes(settingsIndex);
+ }
+
+ /**
+ * This method returns the MANIFESTXML file in a byte
array.
+ * It returns null if there is no MANIFESTXML in this zip file.
+ *
+ * @return MANIFESTXML in a byte
array.
+ */
+ byte[] getManifestXMLBytes() {
+ return getEntryBytes(manifestIndex);
+ }
+
+ /**
+ * This method returns the bytes corresponding to the entry named in the
+ * parameter.
+ *
+ * @param name The name of the entry in the Zip file to retrieve.
+ *
+ * @return The data for the named entry in a byte
array or
+ * null
if no entry is found.
+ */
+ byte[] getNamedBytes(String name) {
+
+ // The list is not sorted, and sorting it for a binary search would
+ // invalidate the indices stored for the main files.
+
+ // Could improve performance by caching the name and index when
+ // iterating through the ZipFile in read().
+ for (int i = 0; i < entryList.size(); i++) {
+ Entry e = (Entry)entryList.get(i);
+
+ if (e.zipEntry.getName().equals(name)) {
+ return getEntryBytes(i);
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * This method sets the bytes for the named entry. It searches for a
+ * matching entry in the LinkedList. If no entry is found, a new one is
+ * created.
+ *
+ * Writing of data is defferred to setEntryBytes().
+ *
+ * @param name The name of the entry to search for.
+ * @param bytes The new data to write.
+ */
+ void setNamedBytes(String name, byte[] bytes) {
+ for (int i = 0; i < entryList.size(); i++) {
+ Entry e = (Entry)entryList.get(i);
+
+ if (e.zipEntry.getName().equals(name)) {
+ setEntryBytes(i, bytes, name);
+ return;
+ }
+ }
+
+ // If we're here, no entry was found. Call setEntryBytes with an index
+ // of -1 to insert a new entry.
+ setEntryBytes(-1, bytes, name);
+ }
+
+ /**
+ * Used by the getContentXMLBytes
method and the
+ * getStyleXMLBytes
method to return the
+ * byte
array from the corresponding
+ * entry
in the entryList
.
+ *
+ * @param index Index of Entry
object in
+ * entryList
.
+ *
+ * @return byte
array associated in that
+ * Entry
object or null, if there is
+ * not such Entry
.
+ */
+ private byte[] getEntryBytes(int index) {
+
+ byte[] bytes = null;
+
+ if (index > -1) {
+ Entry entry = (Entry) entryList.get(index);
+ bytes = entry.bytes;
+ }
+ return bytes;
+ }
+
+
+ /**
+ * Set or replace the byte
array for the
+ * CONTENTXML file.
+ *
+ * @param bytes byte
array for the
+ * CONTENTXML file.
+ */
+ void setContentXMLBytes(byte bytes[]) {
+
+ contentIndex = setEntryBytes(contentIndex, bytes, CONTENTXML);
+ }
+
+
+ /**
+ * Set or replace the byte
array for the
+ * STYLEXML file.
+ *
+ * @param bytes byte
array for the
+ * STYLEXML file.
+ */
+ void setStyleXMLBytes(byte bytes[]) {
+
+ styleIndex = setEntryBytes(styleIndex, bytes, STYLEXML);
+ }
+
+
+ /**
+ * Set or replace the byte
array for the
+ * METAXML file.
+ *
+ * @param bytes byte
array for the
+ * METAXML file.
+ */
+ void setMetaXMLBytes(byte bytes[]) {
+
+ metaIndex = setEntryBytes(metaIndex, bytes, METAXML);
+ }
+
+
+ /**
+ * Set or replace the byte
array for the
+ * SETTINGSXML file.
+ *
+ * @param bytes byte
array for the
+ * SETTINGSXML file.
+ */
+ void setSettingsXMLBytes(byte bytes[]) {
+
+ settingsIndex = setEntryBytes(settingsIndex, bytes, SETTINGSXML);
+ }
+
+
+ /**
+ * Set or replace the byte
array for the MANIFESTXML file.
+ *
+ * @param bytes byte
array for the MANIFESTXML file.
+ */
+ void setManifestXMLBytes(byte bytes[]) {
+ manifestIndex = setEntryBytes(manifestIndex, bytes, MANIFESTXML);
+ }
+
+ /**
+ * Used by the setContentXMLBytes
method and
+ * the setStyleXMLBytes
to either replace an
+ * existing Entry
, or create a new entry in
+ * entryList
.
If there is an Entry
object within
+ * entryList that corresponds to the index, replace the
+ * ZipEntry
info.
Entry
to modify.
+ * @param bytes Entry
value.
+ * @param name Name of Entry
.
+ *
+ * @return Index of value added or modified in entryList
+ */
+ private int setEntryBytes(int index, byte bytes[], String name) {
+
+ if (index > -1) {
+
+ // replace existing entry in entryList
+
+ Entry entry = (Entry) entryList.get(index);
+ name = entry.zipEntry.getName();
+ int method = entry.zipEntry.getMethod();
+
+ ZipEntry ze = createZipEntry(name, bytes, method);
+
+ entry.zipEntry = ze;
+ entry.bytes= bytes;
+
+ } else {
+
+ // add a new entry into entryList
+ ZipEntry ze = createZipEntry(name, bytes, ZipEntry.DEFLATED);
+ Entry entry = new Entry(ze, bytes);
+ entryList.add(entry);
+ index = entryList.size() - 1;
+ }
+
+ return index;
+ }
+
+
+ /**
+ * Write out the ZIP entries into the OutputStream
+ * object.
+ *
+ * @param os OutputStream
object to write ZIP.
+ *
+ * @throws IOException If any ZIP I/O error occurs.
+ */
+ void write(OutputStream os) throws IOException {
+
+ // Debug.log(Debug.TRACE, "Writing out the following entries into zip.");
+
+ ZipOutputStream zos = new ZipOutputStream(os);
+
+ ListIterator iterator = entryList.listIterator();
+
+ while (iterator.hasNext()) {
+
+ Entry entry = (Entry) iterator.next();
+ ZipEntry ze = entry.zipEntry;
+
+ //String name = ze.getName();
+
+ // Debug.log(Debug.TRACE, "... " + name);
+
+ zos.putNextEntry(ze);
+ zos.write(entry.bytes);
+ }
+
+ zos.close();
+ }
+
+
+ /**
+ * Creates a ZipEntry
object based on the given params.
+ *
+ * @param name Name for the ZipEntry
.
+ * @param bytes byte
array for ZipEntry
.
+ * @param method ZIP method to be used for ZipEntry
.
+ *
+ * @return A ZipEntry
object.
+ */
+ private ZipEntry createZipEntry(String name, byte bytes[], int method) {
+
+ ZipEntry ze = new ZipEntry(name);
+
+ ze.setMethod(method);
+ ze.setSize(bytes.length);
+
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(bytes);
+ ze.setCrc(crc.getValue());
+
+ ze.setTime(System.currentTimeMillis());
+
+ return ze;
+ }
+
+ /**
+ * This inner class is used as a data structure for holding
+ * a ZipEntry
info and its corresponding bytes.
+ * These are stored in entryList.
+ */
+ private class Entry {
+
+ ZipEntry zipEntry = null;
+ byte bytes[] = null;
+
+ Entry(ZipEntry zipEntry, byte bytes[]) {
+ this.zipEntry = zipEntry;
+ this.bytes = bytes;
+ }
+ }
+}
+
diff --git a/source/java/writer2latex/xmerge/Package.html b/source/java/writer2latex/xmerge/Package.html
new file mode 100644
index 0000000..835cc3c
--- /dev/null
+++ b/source/java/writer2latex/xmerge/Package.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Classes originating from OOo's xmerge.
+Previously, Writer2LaTeX was based on xmerge, but this is not the case +anymore. The classes in this packages are reminiscent of that.
+This package is supposed to go away in a future version and be replaced by +something else (probably ODFDOM)
+ + diff --git a/source/oxt/writer2latex/META-INF/manifest.xml b/source/oxt/writer2latex/META-INF/manifest.xml new file mode 100644 index 0000000..a0e086c --- /dev/null +++ b/source/oxt/writer2latex/META-INF/manifest.xml @@ -0,0 +1,33 @@ + + +