Initial import

git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@5 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
henrikjust 2009-02-20 09:37:06 +00:00
parent 75e32b1e8f
commit b0b66fcae9
252 changed files with 49000 additions and 0 deletions

460
source/COPYING.TXT Normal file
View file

@ -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

460
source/distro/COPYING.TXT Normal file
View file

@ -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

121
source/distro/History.txt Normal file
View file

@ -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

18
source/distro/Readme.txt Normal file
View file

@ -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

325
source/distro/changelog.txt Normal file
View file

@ -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 <tbody> for tables without <thead>
[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 &nbsp;
(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)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -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{<prescripts>}{<under>}{<over>}{<formula>}{<scripts>}
\newcommand\multiscripts[5]{%
\mathchoice%
{\idxdheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxtheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxsheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxssheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}
}%
\newcommand\mathoverstrike[1]{%
\mathchoice%
{\idxdheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxtheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxsheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxssheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
}
\endinput

View file

@ -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/12/27 v1.01 - 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{\mathversion{normal}$#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{<prescripts>}{<under>}{<over>}{<formula>}{<scripts>}
\newcommand\multiscripts[5]{%
\mathchoice%
{\idxdheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxtheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxsheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}%
{\idxssheight{#4}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#1\underset{#2}
{\overset{#3}{#4}}\rule[-\idxmathdepth]{0mm}{\idxmathtotal}#5}
}%
\newcommand\mathoverstrike[1]{%
\mathchoice%
{\idxdheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxtheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxsheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
{\idxssheight{#1}\rlap{\rule[\idxraiseme]{\idxmathwidth}{0.4pt}}{#1}}%
}
\endinput

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- gdocs.xml
This is a sample configuration file for Writer2LaTeX.
The options are set to produce the cleanest possible
LaTeX file from an Google Docs document.
The configuration is provided by Elefterios Stamatogiannakis
-->
<config>
<option name="documentclass" value="article" />
<option name="backend" value="generic" />
<option name="inputencoding" value="ascii" />
<option name="multilingual" value="false" />
<option name="use_ooomath" value="false" />
<option name="use_color" value="false" />
<option name="use_colortbl" value="false" />
<option name="use_geometry" value="false" />
<option name="use_fancyhdr" value="false" />
<option name="use_hyperref" value="false" />
<option name="use_caption" value="true" />
<option name="use_endnotes" value="false" />
<option name="use_bibtex" value="true" />
<option name="bibtex_style" value="plain" />
<option name="formatting" value="ignore_most" />
<option name="page_formatting" value="ignore_all" />
<option name="ignore_empty_paragraphs" value="true" />
<option name="ignore_hard_page_breaks" value="true" />
<option name="ignore_hard_line_breaks" value="true" />
<option name="ignore_double_spaces" value="true" />
<option name="use_supertabular" value="false" />
<option name="simple_table_limit" value="10000" />
<option name="wrap_lines_after" value="0" />
<option name="debug" value="false" />
<heading-map max-level="5">
<heading-level-map writer-level="1" name="section" level="1" />
<heading-level-map writer-level="2" name="subsection" level="2" />
<heading-level-map writer-level="3" name="subsubsection" level="3" />
<heading-level-map writer-level="4" name="paragraph" level="4" />
<heading-level-map writer-level="5" name="subparagraph" level="5" />
</heading-map>
<custom-preamble />
<!-- Style maps: These rules defines how styles in OOo are mapped to LaTeX code.
A number of predefined Writer styles are converted -->
<!-- "Title" is mapped to \maketitle. If the user chooses to export meta data,
the author and date will be inserted automatically -->
<style-map name="Title" class="paragraph" before="\title{" after="}&#10;\maketitle" line-break="false" />
<!-- "Quotations" is mapped to a quotation environment -->
<style-map name="Quotations" family="paragraph-block" next="Quotations" before="\begin{quotation}" after="\end{quotation}" />
<style-map name="Quotations" family="paragraph" before="" after="" />
<!-- Preformatted Text is mapped to a verbatim environment
Note the attribute verbatim, which instructs OOo to output the content
verbatim (characters not available in the inputencoding will be replaced
by question marks; other content will be lost). -->
<style-map name="Preformatted Text" family="paragraph-block" next="Preformatted Text" before="\begin{verbatim}" after="\end{verbatim}" />
<style-map name="Preformatted Text" family="paragraph" before="" after="" verbatim="true" />
<!-- "Horizontal line" is mapped to a \hrule -->
<style-map name="Horizontal Line" family="paragraph" before="" after="&#10;\begin{center}\hrule\end{center}" />
<!-- "Emphasis" text style is mapped to \emph -->
<style-map name="Emphasis" family="text" before="\emph{" after="}" />
<!-- Italics text style is mapped to \emph -->
<style-map class="text-attribute" name="italic" before="\emph{" after="}" />
<!-- Underlined text style is mapped to latex verbatim output -->
<style-map class="text-attribute" name="underline" before="" after="" verbatim="true"/>
<!-- Superscript text style is mapped to \textsuperscript -->
<style-map class="text-attribute" name="superscript" before="\textsuperscript{" after="}" />
<!-- Subscript text style is mapped to clean latex -->
<style-map class="text-attribute" name="subscript" before="$_{\textrm{" after="}}$" />
<!-- "Strong Emphasis" text style is mapped to \textbf -->
<style-map name="Strong Emphasis" family="text" before="\textbf{" after="}"/>
<!-- "Teletype" text style is mapped to \texttt -->
<style-map name="Teletype" family="text" before="\texttt{" after="}" />
<!-- "List Heading" and "List Contents" are mapped to a description environment -->
<style-map name="List Heading" family="paragraph-block" next="List Heading;List Contents" before="\begin{description}" after="\end{description}"/>
<style-map name="List Heading" family="paragraph" before="\item[" after="]" line-break="false" />
<style-map name="List Contents" family="paragraph" before="" after="" />
<!-- Various characters are mapped to more human friendly latex entities-->
<string-replace input="&#x0022;" latex-code="&quot;" />
<string-replace input="&#x003C;" latex-code="&lt;" />
<string-replace input="&#x003E;" latex-code="&gt;" />
<string-replace input="&#x2018;" latex-code="`" />
<string-replace input="&#x2019;" latex-code="'" />
<string-replace input="&#x201A;" latex-code="'" />
<string-replace input="&#x201C;" latex-code="``" />
<string-replace input="&#x201D;" latex-code="''" />
<string-replace input="&#x201E;" latex-code="&quot;" />
<string-replace input="&#xF0B2;" latex-code="&quot;" />
<string-replace input="&#xF022;" latex-code="''" />
<string-replace input="&#xF027;" latex-code="'" />
<string-replace input="&#xF05C;" latex-code="``" />
<string-replace input="&#xF060;" latex-code="'" />
<string-replace input="'" latex-code="'" />
<!-- Some mappings to help with citations. -->
<string-replace input="<<<" latex-code="\cite{" />
<string-replace input=">>>" latex-code="}" />
</config>

Binary file not shown.

22
source/distro/w2l Normal file
View file

@ -0,0 +1,22 @@
# *Very* simple script to run Writer2LaTeX (unix version)
# Created by Henrik Just, october 2003
# Modified december 2003 as suggested by Juan Julian Merelo Guervos
# Modified may 2004 as suggested by J. Wolfgang Kaltz
# Last modified december 2008
# If writer2latex.jar is not in the same directory as the script, please
# edit the following line to contain the full path to Writer2LaTeX:
W2LPATH=`dirname $0`
# If the required JVM is not in your path, or the path is not set by JAVA_HOME,
# please edit the following line to contain the full path and file name
MYJAVAEXE="java"
if [ "$JAVA_HOME" = "" ]
then
JAVAEXE="$MYJAVAEXE"
else
JAVAEXE="$JAVA_HOME/bin/java"
fi
$JAVAEXE -jar "$W2LPATH/writer2latex.jar" "$@"

19
source/distro/w2l.bat Normal file
View file

@ -0,0 +1,19 @@
@echo off
rem *Very* simple batch file to run Writer2LaTeX
rem Created by Henrik Just, october 2003
rem Modfied december 2003 as suggested by Juan Julian Merelo Guervos
rem Last modified july 2007
rem Please edit the following line to contain the full path to Writer2LaTeX:
set W2LPATH="c:\writer2latex09"
rem If the Java executable is not in your path, please edit the following
rem line to contain the full path and file name
set JAVAEXE="java"
%JAVAEXE% -jar %W2LPATH%\writer2latex.jar %1 %2 %3 %4 %5 %6 %7 %8 %9
set W2LPATH=
set JAVAEXE=

View file

@ -0,0 +1,612 @@
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mml="http://www.w3.org/1998/Math/MathML"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:fns="http://www.w3.org/2002/Math/preference"
xmlns:doc="http://www.dcarlisle.demon.co.uk/xsldoc"
xmlns:ie5="http://www.w3.org/TR/WD-xsl"
exclude-result-prefixes="h ie5 fns msxsl fns doc"
extension-element-prefixes="msxsl fns doc"
>
<!--
$Id: pmathml.xsl,v 1.8 2003/06/23 14:46:44 davidc Exp $
Copyright David Carlisle 2001, 2002.
Use and distribution of this code are permitted under the terms of the <a
href="http://www.w3.org/Consortium/Legal/copyright-software-19980720"
>W3C Software Notice and License</a>.
-->
<!-- MathPlayer mpdialog code for contributed by
Jack Dignan and Robert Miner, both of Design Science.
-->
<xsl:output method="xml" omit-xml-declaration="yes" />
<ie5:if doc:id="iehack" test=".">
<ie5:eval no-entities="t">'&lt;!--'</ie5:eval>
</ie5:if>
<fns:x name="mathplayer" o="MathPlayer.Factory.1">
<object id="mmlFactory"
classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">
</object>
<?import namespace="mml" implementation="#mmlFactory"?>
</fns:x>
<fns:x name="techexplorer" o="techexplorer.AxTchExpCtrl.1">
<object id="mmlFactory" classid="clsid:0E76D59A-C088-11D4-9920-002035EFB1A4">
</object>
<?import namespace="mml" implementation="#mmlFactory"?>
</fns:x>
<!-- SCRIPT not script due to weird mozilla bug
http://bugzilla.mozilla.org/show_bug.cgi?id=158457
-->
<fns:x name="css" o="Microsoft.FreeThreadedXMLDOM">
<SCRIPT for="window" event="onload">
var xsl = new ActiveXObject("Microsoft.FreeThreadedXMLDOM");
xsl.async = false;
xsl.validateOnParse = false;
xsl.load("pmathmlcss.xsl");
var xslTemplate = new ActiveXObject("MSXML2.XSLTemplate.3.0");
xslTemplate.stylesheet=xsl.documentElement;
var xslProc = xslTemplate.createProcessor();
xslProc.input = document.XMLDocument;
xslProc.transform();
var str = xslProc.output;
<!-- work around bug in IE6 under Win XP, RM 6/5/2002 -->
var repl = "replace";
if (window.navigator.appVersion.match(/Windows NT 5.1/)) { repl = ""; }
var newDoc = document.open("text/html", repl);
newDoc.write(str);
</SCRIPT>
</fns:x>
<h:p>
in mpdialog mode, we just write out some JavaScript to display
dialog to the reader asking whether they want to install MathPlayer
Depending on the response we get, we then instantiate an XSL processor
and reprocess the doc, passing $secondpass according to the
reader response.
</h:p>
<h:p>Using d-o-e is fairly horrible, but this code is only for IE
anyway, and we need to force HTML semantics in this case.</h:p>
<xsl:variable name="mpdialog">
var cookieName = "MathPlayerInstall=";
function MPInstall(){
var showDialog=true;
var c = document.cookie;
var i = c.indexOf(cookieName);
if (i >= 0) {
if ( c.substr(i + cookieName.length, 1) >= 2) { showDialog=false; }
}
if (showDialog) {
MPDialog();
c = document.cookie;
i = c.indexOf(cookieName);
}
if (i >= 0) return c.substr(i + cookieName.length, 1);
else return null;
}
function MPDialog() {
var vArgs="";
var sFeatures="dialogWidth:410px;dialogHeight:190px;help:off;status:no";
var text = "";
text += "javascript:document.write('"
text += '&lt;script>'
text += 'function fnClose(v) { '
text += 'var exp = new Date();'
text += 'var thirtyDays = exp.getTime() + (30 * 24 * 60 * 60 * 1000);'
text += 'exp.setTime(thirtyDays);'
text += 'var cookieProps = ";expires=" + exp.toGMTString();'
text += 'if (document.forms[0].dontask.checked) v+=2;'
text += 'document.cookie="' + cookieName + '"+v+cookieProps;'
text += 'window.close();'
text += '}'
text += '&lt;/' + 'script>'
text += '&lt;head>&lt;title>Install MathPlayer?&lt;/title>&lt;/head>'
text += '&lt;body bgcolor="#D4D0C8">&lt;form>'
text += '&lt;table cellpadding=10 style="font-family:Arial;font-size:10pt" border=0 width=100%>'
text += '&lt;tr>&lt;td align=left>This page requires Design Science\\\'s MathPlayer&amp;trade;.&lt;br>'
text += 'Do you want to download and install MathPlayer?&lt;/td>&lt;/tr>';
text += '&lt;tr>&lt;td align=center>&lt;input type="checkbox" name="dontask">'
text += 'Don\\\'t ask me again&lt;/td>&lt;/tr>'
text += '&lt;tr>&lt;td align=center>&lt;input id=yes type="button" value=" Yes "'
text += ' onClick="fnClose(1)">&amp;nbsp;&amp;nbsp;&amp;nbsp;'
text += '&lt;input type="button" value=" No " onClick="fnClose(0)">&lt;/td>&lt;/tr>'
text += '&lt;/table>&lt;/form>';
text += '&lt;/body>'
text += "')"
window.showModalDialog( text , vArgs, sFeatures );
}
function WaitDialog() {
var vArgs="";
var sFeatures="dialogWidth:510px;dialogHeight:150px;help:off;status:no";
var text = "";
text += "javascript:document.write('"
text += '&lt;script>'
text += 'window.onload=fnLoad;'
text += 'function fnLoad() {document.forms[0].yes.focus();}'
text += 'function fnClose(v) { '
text += 'window.returnValue=v;'
text += 'window.close();'
text += '}'
text += '&lt;/' + 'script>'
text += '&lt;head>&lt;title>Wait for Installation?&lt;/title>&lt;/head>'
text += '&lt;body bgcolor="#D4D0C8" onload="fnLoad()">&lt;form>&lt;'
text += 'table cellpadding=10 style="font-family:Arial;font-size:10pt" border=0 width=100%>'
text += '&lt;tr>&lt;td align=left>Click OK once MathPlayer is installed '
text += 'to refresh the page.&lt;br>'
text += 'Click Cancel to view the page immediately without MathPlayer.&lt;/td>&lt;/tr>';
text += '&lt;tr>&lt;td align=center>&lt;input id=yes type="button" '
text += 'value=" OK " onClick="fnClose(1)">&amp;nbsp;&amp;nbsp;&amp;nbsp;'
text += '&lt;input type="button" value="Cancel" onClick="fnClose(0)">&lt;/td>&lt;/tr>'
text += '&lt;/table>&lt;/form>';
text += '&lt;/body>'
text += "')"
return window.showModalDialog( text , vArgs, sFeatures );
}
var result = MPInstall();
var action = "fallthrough";
if (result == 1 || result == 3) {
window.open("http://www.dessci.com/webmath/mathplayer");
var wait = WaitDialog();
if ( wait == 1) {
action = "install";
document.location.reload();
}
}
if (action == "fallthrough") {
var xsl = new ActiveXObject("Microsoft.FreeThreadedXMLDOM");
xsl.async = false;
xsl.validateOnParse = false;
xsl.load("pmathmlcss.xsl");
var xslTemplate = new ActiveXObject("MSXML2.XSLTemplate.3.0");
xslTemplate.stylesheet=xsl.documentElement;
var xslProc = xslTemplate.createProcessor();
xslProc.input = document.XMLDocument;
xslProc.transform();
var str = xslProc.output;
<!-- work around bug in IE6 under Win XP, RM 6/5/2002 -->
var repl = "replace";
if (window.navigator.appVersion.match(/Windows NT 5.1/)) { repl = ""; }
var newDoc = document.open("text/html", repl);
newDoc.write(str);
document.close();
}
</xsl:variable>
<fns:x name="mathplayer-dl" >mathplayer-dl</fns:x>
<fns:x name="techexplorer-plugin" >techexplorer-plugin</fns:x>
<xsl:variable name="root" select="/"/>
<xsl:param name="activex">
<xsl:choose>
<xsl:when test="/*/@fns:renderer='techexplorer-plugin'">techexplorer-plugin</xsl:when>
<xsl:when test="system-property('xsl:vendor')!='Microsoft'"/>
<xsl:otherwise>
<xsl:variable name="docpref" select="document('')/*/fns:x[@name=$root/*/@fns:renderer][1]"/>
<xsl:choose>
<xsl:when test="$docpref='mathplayer-dl'">mathplayer-dl</xsl:when>
<xsl:when test="$docpref and fns:isinstalled(string($docpref/@o))='true'">
<xsl:copy-of select="$docpref/node()"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="(document('')/*/fns:x[fns:isinstalled(string(@o))='true'])[1]/node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:param>
<h:div doc:ref="iehack">
<h:h3>IE5 hacks</h:h3>
<h:p>This code will be ignored by an XSLT engine as a top level
element in a foreign namespace. It will be executed by an IE5XSL
engine and insert &lt;!-- into the output stream, ie the start of a
comment. This will comment out all the XSLT code which will be copied
to the output. A similar clause below will close this comment, it is
then followed by the IE5XSL templates to be executed.</h:p>
<h:p>This trick is due to Jonathan Marsh of Microsoft, and used in
<h:a href="http://www.w3.org/TR/2001/WD-query-datamodel-20010607/xmlspec-ie-dm.xsl">the stylesheet for
the XPath 2 data model draft</h:a>.</h:p>
</h:div>
<h:h2>XSLT stylesheet</h:h2>
<h:h3>MSXSL script block</h:h3>
<h:p>The following script block implements an extension function that
tests whether a specified ActiveX component is known to the client.
This is used below to test for the existence of MathML rendering
components.</h:p>
<msxsl:script language="JScript" implements-prefix="fns">
function isinstalled(ax)
{
try {
var ActiveX = new ActiveXObject(ax);
return "true";
} catch (e) {
return "false";
}
}
</msxsl:script>
<h:p>The main bulk of this stylesheet is an identity transformation so...</h:p>
<xsl:template match="*|comment()">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<h:p>XHTML elements are copied sans prefix (XHTML is default namespace
here, so these elements will still be in XHTML namespace</h:p>
<xsl:template match="h:*">
<xsl:element name="{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<h:p>IE's treatment of XHTML as HTML needs a little help here...</h:p>
<xsl:template match="h:br|h:hr">
<xsl:choose>
<xsl:when test="system-property('xsl:vendor')='Microsoft'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;',local-name(.))"/>
<xsl:apply-templates mode="verb" select="@*"/>
<xsl:text disable-output-escaping="yes">&gt;</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<h:p>This just ensures the mathml prefix declaration isn't copied from
the source at this stage, so that the system will use the mml prefix
coming from this stylesheet</h:p>
<xsl:template match="h:html|html">
<html>
<xsl:copy-of select="@*[not(namespace-uri(.)='http://www.w3.org/2002/Math/preference')]"/>
<xsl:apply-templates/>
</html>
</xsl:template>
<h:p>We modify the head element to add code to specify a Microsoft
"Behaviour" if the behaviour component is known to the system.</h:p>
<h:span doc:ref="mp">Test for MathPlayer (Design Science)</h:span>
<h:span doc:ref="te">Test for Techexplorer (IBM)</h:span>
<h:span doc:ref="ms"><h:div>Test for Microsoft. In this case we just
output a small HTML file that executes a script that will re-process
the source docuument with a different stylesheet. Doing things this
way avoids the need to xsl:import the second stylesheet, which would
very much increase the processing overhead of running this
stylesheet.</h:div></h:span>
<h:span doc:ref="other">Further tests (eg for netscape/mozilla) could
be added here if necessary</h:span>
<xsl:template match="h:head|head">
<head>
<!-- new if for IE frames bug -->
<xsl:if test="system-property('xsl:vendor')='Microsoft'">
<xsl:if test="name(msxsl:node-set($activex)/*)=''">
<object id="mmlFactory"
classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">
</object>
<xsl:processing-instruction name="import">
namespace="mml" implementation="#mmlFactory"
</xsl:processing-instruction>
</xsl:if>
</xsl:if>
<xsl:choose>
<xsl:when doc:id="mp" test="$activex='mathplayer-dl'">
<xsl:if test="fns:isinstalled('MathPlayer.Factory.1')='false'">
<SCRIPT for="window" event="onload">
<xsl:value-of select="$mpdialog" disable-output-escaping="yes"/>
</SCRIPT>
</xsl:if>
<xsl:copy-of select="document('')/*/fns:x[@name='mathplayer']"/>
</xsl:when>
<xsl:when doc:id="mp" test="not($activex='techexplorer-plugin') and system-property('xsl:vendor')='Microsoft'">
<xsl:copy-of select="$activex"/>
</xsl:when>
<xsl:otherwise doc:id="other">
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</head>
</xsl:template>
<xsl:template match="mml:math" priority="22">
<xsl:choose>
<xsl:when test="$activex='techexplorer-plugin'">
<embed type="text/mathml" height="75" width="300">
<xsl:attribute name="mmldata">
<xsl:apply-templates mode="verb" select="."/>
</xsl:attribute>
</embed>
</xsl:when>
<xsl:otherwise>
<xsl:element name="mml:{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- squash annotation elements -->
<h:p>Somewhat bizarrely in an otherwise namespace aware system,
Microsoft behaviours are defined to trigger off the
<h:em>prefix</h:em> not the <h:em>Namespace</h:em>. In the code above
we associated a MathML rendering behaviour (if one was found) with the
prefix <h:code>mml:</h:code> so here we ensure that this is the prefix
that actually gets used in the output.</h:p>
<xsl:template match="mml:*">
<xsl:element name="mml:{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<h:p>Copy semantics element through in IE (so mathplayer gets to see
mathplayer annotations, otherwise use first child or a presentation annotation.</h:p>
<xsl:template match="mml:semantics">
<xsl:choose>
<xsl:when test="system-property('xsl:vendor')='Microsoft'">
<xsl:element name="mml:{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:when>
<xsl:when test="mml:annotation-xml[@encoding='MathML-Presentation']">
<xsl:apply-templates select="mml:annotation-xml[@encoding='MathML-Presentation']/node()"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="*[1]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- a version of my old verb.xsl -->
<!-- non empty elements and other nodes. -->
<xsl:template mode="verb" match="*[*]|*[text()]|*[comment()]|*[processing-instruction()]">
<xsl:value-of select="concat('&lt;',local-name(.))"/>
<xsl:apply-templates mode="verb" select="@*"/>
<xsl:text>&gt;</xsl:text>
<xsl:apply-templates mode="verb"/>
<xsl:value-of select="concat('&lt;/',local-name(.),'&gt;')"/>
</xsl:template>
<!-- empty elements -->
<xsl:template mode="verb" match="*">
<xsl:value-of select="concat('&lt;',local-name(.))"/>
<xsl:apply-templates mode="verb" select="@*"/>
<xsl:text>/&gt;</xsl:text>
</xsl:template>
<!-- attributes
Output always surrounds attribute value by "
so we need to make sure no literal " appear in the value -->
<xsl:template mode="verb" match="@*">
<xsl:value-of select="concat(' ',local-name(.),'=')"/>
<xsl:text>"</xsl:text>
<xsl:call-template name="string-replace">
<xsl:with-param name="from" select="'&quot;'"/>
<xsl:with-param name="to" select="'&amp;quot;'"/>
<xsl:with-param name="string" select="."/>
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:template>
<!-- pis -->
<xsl:template mode="verb" match="processing-instruction()"/>
<!-- only works if parser passes on comment nodes -->
<xsl:template mode="verb" match="comment()"/>
<!-- text elements
need to replace & and < by entity references-->
<xsl:template mode="verb" match="text()">
<a name="{generate-id(.)}"/>
<xsl:call-template name="string-replace">
<xsl:with-param name="to" select="'&amp;gt;'"/>
<xsl:with-param name="from" select="'&gt;'"/>
<xsl:with-param name="string">
<xsl:call-template name="string-replace">
<xsl:with-param name="to" select="'&amp;lt;'"/>
<xsl:with-param name="from" select="'&lt;'"/>
<xsl:with-param name="string">
<xsl:call-template name="string-replace">
<xsl:with-param name="to" select="'&amp;amp;'"/>
<xsl:with-param name="from" select="'&amp;'"/>
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- end verb mode -->
<!-- replace all occurences of the character(s) `from'
by the string `to' in the string `string'.-->
<xsl:template name="string-replace" >
<xsl:param name="string"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($string,$from)">
<xsl:value-of select="substring-before($string,$from)"/>
<xsl:value-of select="$to"/>
<xsl:call-template name="string-replace">
<xsl:with-param name="string" select="substring-after($string,$from)"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- end of verb.xsl -->
<h:h2>IE5XSL stylesheet</h:h2>
<h:p>In a rare fit of sympathy for users of
<h:em>the-language-known-as-XSL-in-IE5</h:em> this file incorporates a
version of the above code designed to work in the Microsoft dialect.
This is needed otherwise users of a MathML rendering behaviour would
have to make a choice whether they wanted to use this stylesheet
(keeping their source documents conforming XHTML+MathML) or to use
the explicit Microsoft Object code, which is less portable, but would
work in at least IE5.5.</h:p>
<h:p>This entire section of code, down to the end of the stylesheet is
contained within this ie5:if. Thus XSLT sees it as a top level element
from a foreign namespace and silently ignores it. IE5XSL sees it as
"if true" and so executes the code.</h:p>
<h:p doc:ref="closecomment">First close the comment started at the beginning. This ensures
that the bulk of the XSLT code, while being copied to the result tree
by the IE5XSL engine, will not be rendered in the browser.</h:p>
<h:span doc:ref="eval">Lacking attribute value templates in
xsl:element, and the local-name() function, we resort to constructing
the start and end tags in strings in javascript, then using
no-entities attribute which is the IE5XSL equivalent of disable-output-encoding</h:span>
<ie5:if test=".">
<ie5:eval doc:id="closecomment" no-entities="t">'--&gt;'</ie5:eval>
<ie5:apply-templates select=".">
<ie5:script>
function mpisinstalled()
{
try {
var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
return "true";
} catch (e) {
return "false";
}
}
</ie5:script>
<ie5:template match="/">
<ie5:apply-templates/>
</ie5:template>
<ie5:template match="head|h:head"/>
<ie5:template match="text()">
<ie5:value-of select="."/>
</ie5:template>
<ie5:template match="*|@*">
<ie5:copy>
<ie5:apply-templates select="*|text()|@*"/>
</ie5:copy>
</ie5:template>
<ie5:template match="mml:*">
<ie5:eval no-entities="t" doc:id="eval">'&lt;mml:' + this.nodeName.substring(this.nodeName.indexOf(":")+1)</ie5:eval>
<ie5:for-each select="@*">
<ie5:eval no-entities="t">' ' + this.nodeName</ie5:eval>="<ie5:value-of select="."/>"
</ie5:for-each>
<ie5:eval no-entities="t">'&gt;'</ie5:eval>
<ie5:apply-templates select="*|text()"/>
<ie5:eval no-entities="t">'&lt;/mml:' + this.nodeName.substring(this.nodeName.indexOf(":")+1) + '&gt;'</ie5:eval>
</ie5:template>
<ie5:template match="mml:math">
<ie5:if expr="mpisinstalled()=='false'">
<embed type="text/mathml" height="75" width="300">
<ie5:attribute name="mmldata">
<ie5:eval doc:id="eval" no-entities="t">'&lt;math&gt;'</ie5:eval>
<ie5:apply-templates/>
<ie5:eval doc:id="eval" no-entities="t">'&lt;/math&gt;'</ie5:eval>
</ie5:attribute>
</embed>
</ie5:if>
<ie5:if expr="mpisinstalled()=='true'">
<ie5:eval doc:id="eval" no-entities="t">'&lt;mml:' + this.nodeName.substring(this.nodeName.indexOf(":")+1)</ie5:eval>
<ie5:for-each select="@*">
<ie5:eval no-entities="t">' ' + this.nodeName</ie5:eval>="<ie5:value-of select="."/>"
</ie5:for-each>
<ie5:eval no-entities="t">'&gt;'</ie5:eval>
<ie5:apply-templates select="*|text()"/>
<ie5:eval no-entities="t">'&lt;/mml:' + this.nodeName.substring(this.nodeName.indexOf(":")+1) + '&gt;'</ie5:eval>
</ie5:if>
</ie5:template>
<ie5:template match="html|h:html">
<html xmlns:mml="http://www.w3.org/1998/Math/MathML">
<head>
<ie5:if expr="mpisinstalled()=='true'">
<object id="mmlFactory"
classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">
</object>
<ie5:pi name="IMPORT">
namespace="mml" implementation="#mmlFactory"
</ie5:pi>
</ie5:if>
<ie5:apply-templates select="h:head/*|head/*"/>
</head>
<body>
<ie5:apply-templates select="body|h:body"/>
</body>
</html>
</ie5:template>
</ie5:apply-templates>
</ie5:if>
</xsl:stylesheet>

View file

@ -0,0 +1,872 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!--
Presentation MathML Stylesheet
-->
<!--
$Id: pmathmlcss.xsl,v 1.1 2002/03/20 12:20:57 mf Exp $
Copyright David Carlisle 2001, 2002.
Use and distribution of this code are permitted under the terms of the <a
href="http://www.w3.org/Consortium/Legal/copyright-software-19980720"
>W3C Software Notice and License</a>.
-->
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:m="http://www.w3.org/1998/Math/MathML"
xmlns:doc="http://www.dcarlisle.demon.co.uk/xsldoc"
xmlns:x="data:,x"
exclude-result-prefixes="x h doc"
>
<h:h2>Dictionary</h:h2>
<h:p> The following elements in the x: namespace form an
implementation of an "Operator Dictionary" for this MathML
Implementation. In the case of stretch operators, the element
specifies the symbol parts via the latin-1 equivalent character based
on the encoding in the symbol font. It is a clear "failure to comply
to the spec" that using latin 1 characters (or numeric character
references) in the latin 1 range access glyphs in teh symbol font via
font position, however most of these character parts are not in
Unicode (until 3.2), so there is no standard way to access these characters.</h:p>
<x:x x="{" m="0em" stretch="true" top="ì" middle="í" extend="ï" bottom="î">{</x:x>
<x:x x="}" m="0em" stretch="true" top="ü" middle="ý" extend="ú" bottom="þ">{</x:x>
<x:x x="(" m="0em" stretch="true" top="æ" middle="ç" extend="ç" bottom="è">(</x:x>
<x:x x=")" m="0em" stretch="true" top="ö" middle="÷" extend="÷" bottom="ø">)</x:x>
<x:x x="[" m="0em" stretch="true" top="é" middle="ê" extend="ê" bottom="ë">[</x:x>
<x:x x="]" m="0em" stretch="true" top="ù" middle="ú" extend="ú" bottom="û">]</x:x>
<x:x x="&#x301A;" m="0em" stretch="true" top="éé" middle="êê" extend="êê" bottom="ëë">[[</x:x>
<x:x x="&#x301B;" m="0em" stretch="true" top="ùù" middle="úú" extend="úú" bottom="ûû">]]</x:x>
<x:x x="|" m="0em" stretch="true" top="ç" middle="ç" extend="ç" bottom="ç">|</x:x>
<x:x x="||" m="0em" stretch="true" top="çç" middle="çç" extend="çç" bottom="çç">||</x:x>
<x:x x="&#x2061;" m="0em">&#xFEFF;</x:x><!-- applyfunction -->
<x:x x="&#x2062;" m="0em">&#xFEFF;</x:x><!-- invisibletimes -->
<x:x x="-">&#x2212;</x:x>
<x:x x="&#x2243;"><span style="position:
relative; top: +.1em;">&#x2212;</span>&#xFEFF;<span style="position:
relative; left: -.55em; top: -.2em; margin: 0em;">~</span></x:x>
<x:x x="&#xFE38;" m="0em">_v_</x:x>
<h:p>Remove these for now, as XML parser in IE6 is broken and doesn't
accept plane 1 characters.</h:p>
<!--
<x:x x="&#x1D538;" v="doublestruck">A</x:x>
<x:x x="&#x1D539;" v="doublestruck">B</x:x>
<x:x x="&#x2102;" v="doublestruck">C</x:x>
<x:x x="&#x1D53B;" v="doublestruck">D</x:x>
<x:x x="&#x1D552;" v="doublestruck">a</x:x>
<x:x x="&#x1D553;" v="doublestruck">b</x:x>
<x:x x="&#x1D554;" v="doublestruck">c</x:x>
<x:x x="&#x1D555;" v="doublestruck">d</x:x>
<x:x x="&#x1D504;" v="fraktur">A</x:x>
<x:x x="&#x1D505;" v="fraktur">B</x:x>
<x:x x="&#x212D;" v="fraktur">C</x:x>
<x:x x="&#x1D507;" v="fraktur">D</x:x>
<x:x x="&#x1D51E;" v="fraktur">a</x:x>
<x:x x="&#x1D51F;" v="fraktur">b</x:x>
<x:x x="&#x1D520;" v="fraktur">c</x:x>
<x:x x="&#x1D521;" v="fraktur">d</x:x>
-->
<h:p>Grab all of the above into a variable.</h:p>
<xsl:variable name="opdict" select="document('')/*/x:x"/>
<h:h2>HTML elements</h:h2>
<h:p>
XHTML elements get passed straight through, sans namespace prefix.
</h:p>
<xsl:template match="h:*">
<xsl:element name="{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<h:p>
Template for the head element copies the original content, aand in
addition adds a script element and CSS style element that implement
the core of the MathML renderer.
</h:p>
<h:p doc:ref="malign">
The malign function first finds the left most item in the aligngroup, and
then modifies the left margin of each item to make them
align. (Currently only left alignment is supported.)
</h:p>
<h:p doc:ref="mrowStretch">
The mrowStretch function implements stretchy brackets. It is called
repeatedly, once for each mo child,after a span corresponding to an
mrow. The arguments are the id of teh span and the characters to use
for the parts of the stretch operator.
constructed fence. The
</h:p>
<h:p doc:ref="css">
Inline CSS style block handles all font and size specification for the
various MathML operators.
</h:p>
<xsl:template match="h:head">
<xsl:element name="{local-name(.)}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
<script>
<xsl:text doc:id="malign">
function malign (l)
{
var m = 0;
for ( i = 0; i &lt; l.length ; i++)
{
m = Math.max(m,l[i].offsetLeft);
}
for ( i = 0; i &lt; l.length ; i++)
{
l[i].style.marginLeft=m - l[i].offsetLeft;
}
}
</xsl:text>
<xsl:text doc:id="mrowStretch">
function mrowStretch (opid,opt,ope,opm,opb){
opH = opid.offsetHeight;
var opH;
var i;
var es;
if (mrowH &gt; opH * 2) {
m= "&lt;font size='+1' face='symbol'>" + opm + "&lt;/font>&lt;br/>" ;
if ((mrowH &lt; opH * 3) &amp;&amp;(opm == ope) ) m="";
es="";
for ( i = 3; i &lt;= mrowH / (2*opH) ; i += 1) es += "&lt;font size='+1' face='symbol'>" + ope + "&lt;/font>&lt;br/>" ;
opid.innerHTML="&lt;table class='lr'>&lt;tr>&lt;td>&lt;font size='+1' face='symbol'>" +
opt + "&lt;/font>&lt;br/>" +
es +
m +
es +
"&lt;font size='+1' face='symbol'>" + opb + "&lt;/font>&lt;/td>&lt;/tr>&lt;/table>";
}
}
</xsl:text>
<xsl:text doc:id="msubsup">
function msubsup (bs,bbs,x,b,p){
<!--
p.style.setExpression("top",bs +" .offsetTop - " + (p.offsetHeight/2 +(bbs.offsetHeight - Math.max(bbs.offsetHeight, b.offsetHeight + p.offsetHeight)*.5)));
-->
p.style.setExpression("top",bs +" .offsetTop -" + (p.offsetHeight/2));
b.style.setExpression("top",bs + ".offsetTop + " + (bbs.offsetHeight - b.offsetHeight*.5));
x.style.setExpression("marginLeft",Math.max(p.offsetWidth,b.offsetWidth));
document.recalc(true);
}
</xsl:text>
<!--
function msubsupzz (bs,x,b,p){
p.style.setExpression("top",bs +" .offsetTop - " + bs +
"p.offsetHeight/2 +(" + bs + ".offsetHeight - Math.max(" + bs + ".offsetHeight, (" + bs + "b.offsetHeight + " + bs + "p.offsetHeight)*.5))");
b.style.setExpression("top",bs + ".offsetTop + " + bs + ".offsetHeight - " + bs + "b.offsetHeight/2");
x.style.setExpression("marginLeft","Math.max(" + bs +"p.offsetWidth,"
+ bs +"b.offsetWidth)");
}
-->
<xsl:text doc:id="msup">
function msup (bs,x,p){
p.style.setExpression("top",bs +" .offsetTop -" + (p.offsetHeight/2));
x.style.setExpression("marginLeft", bs +"p.offsetWidth");
x.style.setExpression("height", bs + ".offsetHeight + " + p.offsetHeight);
document.recalc(true);
}
</xsl:text>
<xsl:text doc:id="msub">
function msub (bs,x,p){
p.style.setExpression("top",bs +" .offsetTop +" + (p.offsetHeight/2));
x.style.setExpression("marginLeft", bs +"p.offsetWidth");
x.style.setExpression("height", bs + ".offsetHeight + " + p.offsetHeight);
document.recalc(true);
}
</xsl:text>
<xsl:text doc:id="toggle">
function toggle (x) {
for ( i = 0 ; i &lt; x.childNodes.length ; i++) {
if (x.childNodes.item(i).style.display=='inline') {
x.childNodes.item(i).style.display='none';
if ( i+1 == x.childNodes.length) {
x.childNodes.item(0).style.display='inline';
} else {
x.childNodes.item(i+1).style.display='inline';
};
break;
}
}
}
</xsl:text>
</script>
<style>
<xsl:text doc:id="css">
.msubsup {
<!--background-color: red;-->
font-size: 80%;
position: absolute;
}
.munderover {
display: inline;
vertical-align: middle;
}
.lr {
display: inline;
vertical-align: middle;
}
.mi {
font-style: serif;
}
.mspace{
display: inline;
}
.mtext {
font-style: serif;
}
.ms {
font-style: monospace;
}
.mi1 {
font-style: italic;
}
.doublestruck {
font-family: castellar, algerian,niagara engraved;
}
.mo {
padding-right: .3em;
padding-left: .3em;
}
.mn {
}
.msqrt {
border-style: solid;
border-color: black;
border-width: .1em 0pt 0pt .1em;
padding-left: .2em;
margin-left: 0em;
margin-top: .2em;
display: inline;
}
.actuarial {
border-style: solid;
border-color: black;
border-width: .1em .1em 0pt 0pt ;
padding-right: .2em;
margin-right: 0em;
margin-top: .2em;
display: inline;
}
.ssa {
position:relative; top:+0.5ex;
width: 0pt;
color: red;
}
.mover {
margin: 0pt;
padding: 0pt;
display: inline;
vertical-align: middle;
text-align: center;
}
.mtable {
display: inline;
vertical-align: middle;
}
.mfrac {
text-align: center;
display:inline;
vertical-align: middle;
}
.mfraca {
vertical-align: bottom;
}
.mfracaa {
border-width: 0em 0em .2ex 0em ; border-style: solid;
border-color: black;
}
.mfracb {
vertical-align: top;
}
.merror{
background-color: white ;
border-style: solid;
border-color: #FF0000;
color: #FF0000;
}
.mphantom{
visibility: hidden;
}
</xsl:text>
</style>
</xsl:element>
</xsl:template>
<h:p>
Unimplemented MathML elements get copied literally, in red, mainly as
a debugging aid.
</h:p>
<xsl:template match="m:*">
<span style="color: red;">&lt;<xsl:value-of select="local-name(.)"/>&gt;</span>
<xsl:apply-templates/>
<span style="color: red;">&lt;/<xsl:value-of select="local-name(.)"/>&gt;</span>
</xsl:template>
<h:p>
mi: set default font based on string length, otherwise behaviour based
on entries in the operator dictionary if one exists, or content is
copied through to the output unchanged.
</h:p>
<xsl:template match="m:mi">
<span class="mi">
<xsl:if test="1=string-length(normalize-space(.))">
<xsl:attribute name="class">mi1</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@mathvariant"/>
<xsl:variable name="x" select="normalize-space(.)"/>
<xsl:choose>
<xsl:when test="$opdict[@x=$x and @v]">
<xsl:attribute name="class"><xsl:value-of select="$opdict[@x=$x]/@v"/></xsl:attribute>
<xsl:value-of select="$opdict[@x=$x and @v]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$x"/>
</xsl:otherwise>
</xsl:choose>
</span>
</xsl:template>
<h:p>
Handling of mathvariant attribute.
The choice of font families here (currently) avoids math-specific
fonts but does use several fionts coming with windows 9.x and/or
office 2000.
</h:p>
<xsl:template match="@mathvariant[.='bold']">
<xsl:attribute name="style">font-weight: bold; font-style: upright</xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='bold-italic']">
<xsl:attribute name="style">font-style: upright; font-weight: bold; font-style: italic;</xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='italic']">
<xsl:attribute name="style">font-style: italic; </xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='monospace']">
<xsl:attribute name="style">font-family: monospace; </xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='sans-serif']">
<xsl:attribute name="style">font-family: sans-serif; </xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='bold-sans-serif']">
<xsl:attribute name="style">font-family: sans-serif; font-weight: bold; </xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='fraktur']">
<xsl:attribute name="style">font-family: old english text mt</xsl:attribute>
<xsl:attribute name="class"></xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='double-struck']">
<xsl:attribute name="class">doublestruck</xsl:attribute>
</xsl:template>
<xsl:template match="@mathvariant[.='script']">
<xsl:attribute name="style">font-family: brush script mt italic</xsl:attribute>
<xsl:attribute name="class"></xsl:attribute>
</xsl:template>
<h:p>mo: Generate a unique ID so that a script at the end of any
surrounding mrow may replace the conent by a suitably stretched
operator if need be.</h:p>
<xsl:template match="m:mo">
<span id="{generate-id()}" class="mo">
<xsl:apply-templates/>
</span>
</xsl:template>
<h:p>mn: a simple span</h:p>
<xsl:template match="m:mn">
<span class="mn">
<xsl:apply-templates/>
</span>
</xsl:template>
<h:p>munder: currently only supports underline, with a bottom border</h:p>
<xsl:template match="m:munder">
<span class="munder">
<xsl:if test="normalize-space(*[2])='&#x332;'">
<xsl:attribute
name="style">border-width: 0pt 0pt .1em 0pt; border-style: solid;"</xsl:attribute>
</xsl:if>
<span><xsl:apply-templates select="*[1]"/></span>
</span>
</xsl:template>
<h:p>mover: currently only supports overline, with a top border</h:p>
<xsl:template match="m:mover">
<span class="munder">
<xsl:if test="normalize-space(*[2])='&#xAF;'">
<xsl:attribute
name="style">border-width: .1em 0pt 0pt 0pt; border-style: solid;"</xsl:attribute>
</xsl:if>
<span><xsl:apply-templates select="*[1]"/></span>
</span>
</xsl:template>
<h:p>munderover: </h:p>
<xsl:template match="m:munderover">
<table class="munderover">
<tr><td><xsl:apply-templates select="*[3]"/></td></tr>
<tr><td><xsl:apply-templates select="*[1]"/></td></tr>
<tr><td><xsl:apply-templates select="*[2]"/></td></tr>
</table>
</xsl:template>
<h:p>mtext: a simple span</h:p>
<xsl:template match="m:mtext">
<span class="mtext">
<xsl:value-of select="normalize-space(.)"/>
</span>
</xsl:template>
<h:p>mstyle: not many attributes currently supported</h:p>
<xsl:template match="m:mstyle">
<span>
<xsl:attribute name="style">
<xsl:if test="@color">color: <xsl:value-of select="@color"/>; </xsl:if>
<xsl:if test="@background">background-color: <xsl:value-of select="@background"/>; </xsl:if>
</xsl:attribute>
<xsl:apply-templates/>
</span>
</xsl:template>
<h:p>mglyph: Uses disable output escaping to construct a numeric
character reference. Uses IE's non conforming behaviour of using this
number to access the font encoding rather than unicode.</h:p>
<xsl:template match="m:mglyph">
<font face="{@fontfamily}"><xsl:value-of
disable-output-escaping="yes" select="'&amp;#'"/>
<xsl:value-of select="@index"/>;<xsl:text/>
</font>
</xsl:template>
<h:p>ms: a simple span with left and right character added to the content.</h:p>
<xsl:template match="m:ms">
<span class="ms">
<xsl:value-of select="@lquote"/><xsl:if test="not(@lquote)">"</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
<xsl:value-of select="@rquote"/><xsl:if test="not(@rquote)">"</xsl:if>
</span>
</xsl:template>
<xsl:template match="m:math">
<xsl:call-template name="mrow"/>
</xsl:template>
<xsl:template match="m:mfenced">
<xsl:variable name="l">
<xsl:choose>
<xsl:when test="@open"><xsl:value-of select="@open"/></xsl:when>
<xsl:otherwise>(</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="r">
<xsl:choose>
<xsl:when test="@close"><xsl:value-of select="@close"/></xsl:when>
<xsl:otherwise>)</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="s">
<xsl:choose>
<xsl:when test="@sep">
<xsl:call-template name="text">
<xsl:with-param name="x" select="@sep"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>,</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<span id="{generate-id()}L"><xsl:value-of select="$l"/></span>
<span id="{generate-id()}M">
<xsl:for-each select="*">
<xsl:apply-templates select="."/>
<xsl:if test="position() != last()"><span id="{generate-id()}X{position()}"><xsl:value-of select="$s"/></span></xsl:if>
</xsl:for-each>
</span>
<span id="{generate-id()}R"><xsl:value-of select="$r"/></span>
<script>
<xsl:if test="$s=$opdict[@stretch='true']/@x">
<xsl:for-each select="*[position()&lt;last()]">
<xsl:variable name="opdictentry" select="$opdict[@x=$s]"/>
mrowStretch(<xsl:value-of select="concat(generate-id(),'X',position())"/>,"<xsl:value-of
select="$opdictentry/@top"/>","<xsl:value-of
select="$opdictentry/@extend"/>","<xsl:value-of
select="$opdictentry/@middle"/>","<xsl:value-of
select="$opdictentry/@bottom"/>");</xsl:for-each>
</xsl:if>
<xsl:variable name="opdictentry" select="$opdict[@x=$l]"/>
var mrowH = <xsl:value-of select="generate-id()"/>M.offsetHeight;
mrowStretch(<xsl:value-of select="generate-id()"/>L,"<xsl:value-of
select="$opdictentry/@top"/>","<xsl:value-of
select="$opdictentry/@extend"/>","<xsl:value-of
select="$opdictentry/@middle"/>","<xsl:value-of
select="$opdictentry/@bottom"/>");<xsl:text/>
<xsl:variable name="opdictentry2" select="$opdict[@x=$r]"/>
mrowStretch(<xsl:value-of select="generate-id()"/>R,"<xsl:value-of
select="$opdictentry2/@top"/>","<xsl:value-of
select="$opdictentry2/@extend"/>","<xsl:value-of
select="$opdictentry2/@middle"/>","<xsl:value-of
select="$opdictentry2/@bottom"/>");<xsl:text/>
</script>
</xsl:template>
<xsl:template match="m:mmultiscripts">
<table style="display:inline; vertical-align: middle;">
<tr>
<xsl:for-each select="*[preceding-sibling::m:mprescripts and position() mod 2 = 0]">
<td><xsl:apply-templates select="."/></td>
</xsl:for-each>
<td rowspan="2"><xsl:apply-templates select="*[1]"/></td>
<xsl:for-each select="*[not(preceding-sibling::m:mprescripts) and position() !=1 and position() mod 2 = 1]">
<td><xsl:apply-templates select="."/></td>
</xsl:for-each>
</tr>
<tr>
<xsl:for-each select="*[preceding-sibling::m:mprescripts and position() mod 2 = 1]">
<td><xsl:apply-templates select="."/></td>
</xsl:for-each>
<xsl:for-each select="*[not(preceding-sibling::m:mprescripts) and
not(self::m:mprescripts) and position() mod 2 = 0]">
<td><xsl:apply-templates select="."/></td>
</xsl:for-each>
</tr>
</table>
</xsl:template>
<xsl:template match="m:none">&#xFEFF;</xsl:template>
<xsl:template match="m:merror">
<span class="merror"><xsl:call-template name="mrow"/></span>
</xsl:template>
<xsl:template match="m:mphantom">
<span class="mphantom"><xsl:apply-templates/></span>
</xsl:template>
<xsl:template match="m:maction[@type='tooltip']">
<span title="{*[2]}"><xsl:apply-templates select="*[1]"/></span>
</xsl:template>
<xsl:template match="m:maction[@type='toggle']">
<span id="{generate-id()}" onclick="toggle({generate-id()})">
<span style="display:inline;"><xsl:apply-templates select="*[1]"/></span>
<xsl:for-each select="*[position() &gt; 1]">
<span style="display:none;"><xsl:apply-templates select="."/></span>
</xsl:for-each>
</span>
</xsl:template>
<xsl:template match="m:maction[@type='statusline']">
<span id="{generate-id()}"
onmouseover="window.status='{*[2]}';"
onmouseout="window.status='';"
>
<xsl:apply-templates select="*[1]"/></span>
</xsl:template>
<xsl:template match="m:maction[@type='highlight']">
<span id="{generate-id()}"
onmouseover="{generate-id()}.style.backgroundColor='yellow';"
onmouseout="{generate-id()}.style.backgroundColor='white';"><xsl:apply-templates/></span>
</xsl:template>
<xsl:template match="m:mrow" name="mrow">
<span id="{generate-id()}" class="mrow">
<xsl:apply-templates select="*"/>
</span>
<xsl:if test="m:mo[@stretch='true' or normalize-space(.)=$opdict[@stretch='true']/@x]">
<script>
var mrowH = <xsl:value-of select="generate-id()"/>.offsetHeight;
<xsl:for-each select="m:mo[@stretch='true' or
normalize-space(.)=$opdict[@stretch='true']/@x]">
<xsl:variable name="o" select="normalize-space(.)"/>
<xsl:variable name="opdictentry" select="$opdict[@x=$o]"/>
mrowStretch(<xsl:value-of select="generate-id()"/>,"<xsl:value-of
select="$opdictentry/@top"/>","<xsl:value-of
select="$opdictentry/@extend"/>","<xsl:value-of
select="$opdictentry/@middle"/>","<xsl:value-of
select="$opdictentry/@bottom"/>");</xsl:for-each>
</script>
</xsl:if>
</xsl:template>
<xsl:template match="m:msubsup">
<span id="{generate-id()}" >
<xsl:apply-templates select="*[1]"/></span
><span id="{generate-id()}b" class="msubsup"><xsl:apply-templates
select="*[2]"/></span
><span id="{generate-id()}p" class="msubsup"><xsl:apply-templates
select="*[3]"/></span
><span id="{generate-id()}x">&#xFEFF;</span>
<script>
msubsup("<xsl:value-of select="concat(generate-id(),'&quot;,',generate-id(),',',generate-id(),'x,',generate-id(),'b,',generate-id())"/>p);
</script>
</xsl:template>
<xsl:template match="h:table//m:msubsup|m:mtable//m:msubsup|m:msubsup"
priority="2">
<span>
<xsl:apply-templates select="*[1]"/>
</span
><sub><xsl:apply-templates
select="*[2]"/></sub>
<sup><xsl:apply-templates
select="*[3]"/></sup>
</xsl:template>
<xsl:template match="m:msup
">
<span id="{generate-id()}">
<xsl:apply-templates select="*[1]"/>
</span
><span id="{generate-id()}p" class="msubsup"><xsl:apply-templates
select="*[2]"/></span
><span id="{generate-id()}x">&#xFEFF;</span>
<script>
msup("<xsl:value-of select="concat(generate-id(),'&quot;,',generate-id(),'x,',generate-id())"/>p);
</script>
</xsl:template>
<xsl:template match="h:table//m:msup|m:mtable//m:msup|m:msup"
priority="2">
<span>
<xsl:apply-templates select="*[1]"/>
</span
><sup><xsl:apply-templates
select="*[2]"/></sup>
</xsl:template>
<xsl:template match="m:msub
">
<span id="{generate-id()}">
<xsl:apply-templates select="*[1]"/>
</span
><span id="{generate-id()}p" class="msubsup"><xsl:apply-templates
select="*[2]"/></span
><span id="{generate-id()}x">&#xFEFF;</span>
<script>
msub("<xsl:value-of select="concat(generate-id(),'&quot;,',generate-id(),'x,',generate-id())"/>p);
</script>
</xsl:template>
<xsl:template match="h:table//m:msub|m:mtable//m:msub|m:msub"
priority="2">
<span>
<xsl:apply-templates select="*[1]"/>
</span
><sub><xsl:apply-templates
select="*[2]"/></sub>
</xsl:template>
<xsl:template match="m:*/text()" name="text">
<xsl:param name="x" select="normalize-space(.)"/>
<xsl:variable name="mo" select="document('')/*/x:x[@x=$x]"/>
<xsl:choose>
<xsl:when test="$mo"><xsl:copy-of select="$mo/node()"/></xsl:when>
<xsl:otherwise><xsl:copy-of select="$x"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="m:msqrt">
<span class="msqrtx">\&#xFEFF;</span><span class="msqrt">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="m:menclose[@notation='radical']">
<span class="msqrtx">\&#xFEFF;</span><span class="msqrt">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="m:menclose[@notation='actuarial']">
<span class="actuarial">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="m:menclose">
<span class="msqrt">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="m:mroot">
<span class="msqrtx"><sup><xsl:apply-templates select="*[2]"/></sup>\&#xFEFF;</span><span class="msqrt">
<xsl:apply-templates select="*[1]"/>
</span>
</xsl:template>
<xsl:template match="m:mfrac">
<xsl:param name="full" select="not(ancestor::m:mfrac)"/>
<table class="mfrac">
<xsl:if test="$full">
<xsl:attribute name="style">font-size: 75% ;</xsl:attribute>
</xsl:if>
<xsl:if test="not($full)">
<xsl:attribute name="style">font-size: 100% ;</xsl:attribute>
</xsl:if>
<tr id="a{generate-id()}" class="mfraca"><td class="mfracaa">
<xsl:apply-templates select="*[1]"/>
</td></tr>
<tr id="b{generate-id()}" class="mfracb"><td>
<xsl:apply-templates select="*[2]"/>
</td></tr>
</table><xsl:if test="$full"><script>
if ( a<xsl:value-of select="generate-id()"
/>.offsetHeight > b<xsl:value-of select="generate-id()"
/>.offsetHeight ) b<xsl:value-of select="generate-id()
"/>.style.setExpression("height",a<xsl:value-of select="generate-id()"/>.offsetHeight );
else a<xsl:value-of
select="generate-id()"/>.style.setExpression("height",b<xsl:value-of
select="generate-id()"/>.offsetHeight );
</script></xsl:if>
</xsl:template>
<xsl:template match="m:padded">
<span>
<xsl:attribute name="display">
</xsl:attribute>
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="m:mspace">
<span style="padding-left: {@width};"></span>
</xsl:template>
<xsl:template match="m:mtable">
<table class="mtable">
<xsl:apply-templates/>
</table>
<script>
<xsl:variable name="t" select="."/>
<xsl:for-each select="m:mtr[1]/m:mtd">
<xsl:variable name="c" select="position()"/>
<xsl:for-each select="descendant::m:maligngroup">
<xsl:variable name="g" select="position()"/>
malign([<xsl:for-each
select="$t/m:mtr/m:mtd[$c]/descendant::m:maligngroup[$g]">
<xsl:value-of select="generate-id()"/>
<xsl:if test="position()&lt;last()">,</xsl:if>
</xsl:for-each>]);</xsl:for-each>
</xsl:for-each>
</script>
</xsl:template>
<xsl:template match="m:mtr">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="m:mtd">
<td>
<xsl:apply-templates/>
</td>
</xsl:template>
<xsl:template match="m:maligngroup">
<xsl:variable name="g">
<xsl:choose>
<xsl:when test="@groupalign">
</xsl:when>
<xsl:when test="ancestor::td/@groupalign">
</xsl:when>
<xsl:when test="ancestor::tr/@groupalign">
</xsl:when>
<xsl:when test="ancestor::table/@groupalign">
</xsl:when>
<xsl:otherwise>left</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<span id="{generate-id()}">&#xFEFF;</span>
</xsl:template>
</xsl:stylesheet>

30
source/idl/readme-idl.txt Normal file
View file

@ -0,0 +1,30 @@
This directory contains idl specifications for the custom uno interfaces
defined by the Writer2LaTeX and Writer2xhtml extensions
To avoid dependencies on the OOo SDK in the build process, compiled versions
are included here.
If you need to rebuild it, the complete SDK is required. These are the steps:
To create the registry database for Writer2LaTeX:
idlc -I<path to SDK>\idl XW2LStarMathConverter.idl
regmerge writer2latex.rdb /UCR XW2LStarMathConverter.urd
To create the java interface
javamaker -BUCR -Torg.openoffice.da.writer2latex.XW2LStarMathConverter -nD <path to the OOo installation>\program\types.rdb writer2latex.rdb
and likewise for Writer2xhtml:
idlc -I<path to SDK>\idl XBatchConverter.idl
regmerge writer2xhtml.rdb /UCR XBatchConverter.urd
To create the java interfaces
javamaker -BUCR -Torg.openoffice.da.writer2xhtml.XBatchConverter -nD <path to the OOo installation>\program\types.rdb writer2xhtml.rdb
javamaker -BUCR -Torg.openoffice.da.writer2xhtml.XBatchHandler -nD <path to the OOo installation>\program\types.rdb writer2xhtml.rdb
If you need to use the interfaces from C++ you will also need to run cppumaker

View file

@ -0,0 +1,22 @@
#ifndef __org_openoffice_da_writer2latex_XW2LStarMathConverter_idl__
#define __org_openoffice_da_writer2latex_XW2LStarMathConverter_idl__
#include <com/sun/star/uno/XInterface.idl>
module org { module openoffice { module da { module writer2latex {
interface XW2LStarMathConverter : com::sun::star::uno::XInterface
{
// method org::openoffice::da::writer2latex::XW2LStarMathConverter::convertFormula
string convertFormula ( [in] string sStarMathFormula );
// method org::openoffice::da::writer2latex::XW2LStarMathConverter::getPreamble
string getPreamble ( );
};
}; }; }; };
#endif

Binary file not shown.

View file

@ -0,0 +1,52 @@
#ifndef __org_openoffice_da_writer2xhtml_XBatchConverter_idl__
#define __org_openoffice_da_writer2xhtml_XBatchConverter_idl__
#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/beans/PropertyValue.idl>
module org { module openoffice { module da { module writer2xhtml {
// This interface is an IDL version of the java interface (writer2latex.api.BatchHandler)
interface XBatchHandler : com::sun::star::uno::XInterface
{
// method org::openoffice::da::writer2xhtml::XBatchHandler::startConversion
void startConversion ();
// method org::openoffice::da::writer2xhtml::XBatchHandler::endConversion
void endConversion ();
// method org::openoffice::da::writer2xhtml::XBatchHandler::startDirectory
void startDirectory ( [in] string sName );
// method org::openoffice::da::writer2xhtml::XBatchHandler::endDirectory
void endDirectory ( [in] string sName, [in] boolean bSuccess );
// method org::openoffice::da::writer2xhtml::XBatchHandler::startFile
void startFile ( [in] string sName );
// method org::openoffice::da::writer2xhtml::XBatchHandler::endFile
void endFile ( [in] string sName, [in] boolean bSuccess );
// method org::openoffice::da::writer2xhtml::XBatchHandler::cancel
boolean cancel ();
};
// This interface is an IDL version of the java interface (writer2latex.api.BatchConverter)
interface XBatchConverter : com::sun::star::uno::XInterface
{
// method org::openoffice::da::writer2xhtml::XBatchConverter::convert
void convert ( [in] string sSourceURL,
[in] string sTargetURL,
[in] sequence< com::sun::star::beans::PropertyValue > lArguments,
[in] XBatchHandler handler );
} ;
}; }; }; };
#endif

Binary file not shown.

View file

@ -0,0 +1,188 @@
/************************************************************************
*
* ByteArrayXStream.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-22)
*
*/
package org.openoffice.da.comp.w2lcommon.filter;
// This class is based on these java uno adapter classes:
// com.sun.star.lib.uno.adapter.ByteArrayToXInputStreamAdapter;
// com.sun.star.lib.uno.adapter.XOutputStreamToByteArrayAdapter;
// See http://go-oo.org/lxr/source/udk/javaunohelper/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java
// and http://go-oo.org/lxr/source/udk/javaunohelper/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java
// for original source
import com.sun.star.io.XInputStream;
import com.sun.star.io.XOutputStream;
import com.sun.star.io.XSeekable;
import com.sun.star.io.XStream;
/** <p>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.)</p>
*/
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; }
}

View file

@ -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,"&","&amp;");
}
if (origString.indexOf("\"")!=-1){
origString=replace(origString,"\"","&quot;");
}
if (origString.indexOf("<")!=-1){
origString=replace(origString,"<","&lt;");
}
if (origString.indexOf(">")!=-1){
origString=replace(origString,">","&gt;");
}
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;i<len;i++)
{
str=str.concat(xattribs.getNameByIndex(i));
str=str.concat("=\"");
str=str.concat(needsMask(xattribs.getValueByIndex(i)));
str=str.concat("\" ");
}
}
str=str.concat(">");
try{
xOutStream.writeBytes(str.getBytes("UTF-8"));
}
catch (Exception e){
System.err.println("\n"+e);
}
}
public void endElement(String str){
str="</".concat(str);
str=str.concat(">");
try{
xOutStream.writeBytes(str.getBytes("UTF-8"));
}
catch (Exception e){
System.err.println("\n"+e);
}
}
public void characters(String str){
str=needsMask(str);
try{
xOutStream.writeBytes(str.getBytes("UTF-8"));
}
catch (Exception e){
System.err.println("\n"+e);
}
}
public void ignorableWhitespace(String str){
}
public void processingInstruction(String aTarget, String aData){
}
public void setDocumentLocator(com.sun.star.xml.sax.XLocator xLocator){
}
// This is the actual conversion method, using Writer2LaTeX to convert
// the flat xml recieved from the XInputStream, and writing the result
// to the XOutputStream. The XMLExporter does not support export to
// compound documents with multiple output files; so the main file
// is written to the XOutStream and other files are written using ucb.
public void convert (com.sun.star.io.XInputStream xml,com.sun.star.io.XOutputStream exportStream)
throws com.sun.star.uno.RuntimeException, IOException {
// Initialise the file access
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 base name from the url provided by OOo
String sName= getFileName(sURL);
// Adapter for input stream (OpenDocument flat xml)
XInputStreamToInputStreamAdapter xis =new XInputStreamToInputStreamAdapter(xml);
// Adapter for output stream (Main output file)
XOutputStreamToOutputStreamAdapter newxos =new XOutputStreamToOutputStreamAdapter(exportStream);
// Create converter
Converter converter = ConverterFactory.createConverter(sdMime);
if (converter==null) {
throw new com.sun.star.uno.RuntimeException("Failed to create converter to "+sdMime);
}
// Apply the FilterData to the converter
if (filterData!=null) {
FilterDataParser fdp = new FilterDataParser(xComponentContext);
fdp.applyFilterData(filterData,converter);
}
// Do conversion
converter.setGraphicConverter(new GraphicConverterImpl(xComponentContext));
ConverterResult dataOut = null;
try {
dataOut = converter.convert(xis,sName);
}
catch (IOException e) {
// Fail silently
}
// Write out files
Iterator docEnum = dataOut.iterator();
// Remove the file name part of the url
String sNewURL = null;
if (sURL.lastIndexOf("/")>-1) {
// Take the url up to and including the last slash
sNewURL = sURL.substring(0,sURL.lastIndexOf("/")+1);
}
else {
// The url does not include a path; this should not really happen,
// but in this case we will write to the current default directory
sNewURL = "";
}
while (docEnum.hasNext() && sURL.startsWith("file:")) {
OutputFile docOut = (OutputFile)docEnum.next();
if (dataOut.getMasterDocument()==docOut) {
// The master document is written to the XOutStream supplied
// by the XMLFilterAdaptor
docOut.write(newxos);
newxos.flush();
newxos.close();
}
else {
// Additional documents are written directly using ucb
// Get the file name and the (optional) directory name
String sFullFileName = docOut.getFileName();
String sDirName = "";
String sFileName = sFullFileName;
int nSlash = sFileName.indexOf("/");
if (nSlash>-1) {
sDirName = sFileName.substring(0,nSlash);
sFileName = sFileName.substring(nSlash+1);
}
try{
// Create subdirectory if required
if (sDirName.length()>0 && !sfa2.exists(sNewURL+sDirName)) {
sfa2.createFolder(sNewURL+sDirName);
}
// writeFile demands an InputStream, so we need a pipe
Object xPipeObj=xMSF.createInstance("com.sun.star.io.Pipe");
XInputStream xInStream
= (XInputStream) UnoRuntime.queryInterface(XInputStream.class, xPipeObj );
XOutputStream xOutStream
= (XOutputStream) UnoRuntime.queryInterface(XOutputStream.class, xPipeObj );
OutputStream outStream = new XOutputStreamToOutputStreamAdapter(xOutStream);
// Feed the pipe with content...
docOut.write(outStream);
outStream.flush();
outStream.close();
xOutStream.closeOutput();
// ...and then write the content to the url
sfa2.writeFile(sNewURL+sFullFileName,xInStream);
}
catch (Throwable e){
MessageBox msgBox = new MessageBox(xComponentContext);
msgBox.showMessage(__displayName+": Error writing files",
e.toString()+" at "+e.getStackTrace()[0].toString());
}
}
}
}
// Implement methods from interface XTypeProvider
// Implementation of XTypeProvider
public com.sun.star.uno.Type[] getTypes() {
Type[] typeReturn = {};
try {
typeReturn = new Type[] {
new Type( XTypeProvider.class ),
new Type( XExportFilter.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;
//return( W2LExportFilter.class.getName() );
}
public String[] getSupportedServiceNames() {
String[] stringSupportedServiceNames = { __serviceName };
return( stringSupportedServiceNames );
}
}

View file

@ -0,0 +1,271 @@
/************************************************************************
*
* FilterDataParser.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;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import com.sun.star.beans.PropertyValue;
import com.sun.star.io.NotConnectedException;
import com.sun.star.io.XInputStream;
import com.sun.star.io.XOutputStream;
import com.sun.star.ucb.CommandAbortedException;
import com.sun.star.ucb.XSimpleFileAccess2;
import com.sun.star.uno.AnyConverter;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.XStringSubstitution;
import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter;
import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter;
import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
import writer2latex.api.Converter;
/** This class parses the FilterData property passed to the filter and
* applies it to a <code>Converter</code>
* 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 <code>writer2latex.api.Converter</code> 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;
}
}
}

View file

@ -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;
}
}

View file

@ -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; i<n; i++) {
if (match(blob,psStart,i)) {
nStart=i;
break;
}
}
int nEnd = n;
for (int i=nStart; i<n; i++) {
if (match(blob,psEnd,i)) {
nEnd=i+psEnd.length;
break;
}
}
byte[] newBlob = new byte[nEnd-nStart];
System.arraycopy(blob,nStart,newBlob,0,nEnd-nStart);
return newBlob;
}
private boolean match(byte[] blob, byte[] sig, int nStart) {
int n = sig.length;
if (nStart+n>=blob.length) { return false; }
for (int i=0; i<n; i++) {
if (blob[nStart+i]!=sig[i]) { return false; }
}
return true;
}
}

View file

@ -0,0 +1,267 @@
/************************************************************************
*
* GraphicConverterImpl2.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-07)
*
*/
package org.openoffice.da.comp.w2lcommon.filter;
import java.util.Hashtable;
import com.sun.star.awt.Point;
import com.sun.star.awt.Size;
import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.XPropertySet;
import com.sun.star.drawing.XDrawPage;
import com.sun.star.drawing.XDrawPages;
import com.sun.star.drawing.XDrawPagesSupplier;
import com.sun.star.drawing.XShape;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.util.XRefreshable;
import com.sun.star.lib.uno.adapter.ByteArrayToXInputStreamAdapter;
import com.sun.star.lib.uno.adapter.XOutputStreamToByteArrayAdapter;
import writer2latex.api.GraphicConverter;
import writer2latex.api.MIMETypes;
/** A GraphicConverter implementation which uses a hidden Draw document to
* store the graphic, providing more control over the image than the
* simple GraphicProvider implementation.
*/
public class GraphicConverterImpl2 implements GraphicConverter {
private XComponentContext xComponentContext;
private Hashtable importFilter;
private Hashtable exportFilter;
public GraphicConverterImpl2(XComponentContext xComponentContext) {
this.xComponentContext = xComponentContext;
importFilter = new Hashtable();
importFilter.put(MIMETypes.BMP, "BMP - MS Windows");
//importFilter.put(MIMETypes.EMF, "EMF - MS Windows Metafile");
importFilter.put(MIMETypes.EPS, "EPS - Encapsulated PostScript");
importFilter.put(MIMETypes.GIF, "GIF - Graphics Interchange Format");
importFilter.put(MIMETypes.JPEG, "JPG - JPEG");
importFilter.put(MIMETypes.PNG, "PNG - Portable Network Graphic");
importFilter.put(MIMETypes.SVM, "SVM - StarView Metafile");
importFilter.put(MIMETypes.TIFF, "TIF - Tag Image File");
importFilter.put(MIMETypes.WMF, "WMF - MS Windows Metafile");
exportFilter = new Hashtable();
exportFilter.put(MIMETypes.BMP,"draw_bmp_Export");
//exportFilter.put(MIMETypes.EMF,"draw_emf_Export");
exportFilter.put(MIMETypes.EPS,"draw_eps_Export");
exportFilter.put(MIMETypes.GIF,"draw_gif_Export");
exportFilter.put(MIMETypes.JPEG,"draw_jpg_Export");
exportFilter.put(MIMETypes.PNG,"draw_png_Export");
//exportFilter.put(MIMETypes.SVG,"draw_svg_Export");
exportFilter.put(MIMETypes.SVM,"draw_svm_Export");
exportFilter.put(MIMETypes.TIFF,"draw_tif_Export");
exportFilter.put(MIMETypes.WMF,"draw_wmf_Export");
exportFilter.put(MIMETypes.PDF,"draw_pdf_Export");
}
public boolean supportsConversion(String sSourceMime, String sTargetMime, boolean bCrop, boolean bResize) {
// We don't support cropping and resizing
if (bCrop || bResize) { return false; }
// We currently only support conversion of svm into pdf
// Trying wmf causes an IllegalArgumentException "URL seems to be an unsupported one"
// Seems to be an OOo bug; workaround: Use temporary files..??
boolean bSupportsSource = MIMETypes.SVM.equals(sSourceMime);
/*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);*/
return bSupportsSource && MIMETypes.PDF.equals(sTargetMime);
}
public byte[] convert(byte[] source, String sSourceMime, String sTargetMime) {
// Open a hidden sdraw document
XMultiComponentFactory xMCF = xComponentContext.getServiceManager();
org.openoffice.da.comp.w2lcommon.helper.MessageBox msgBox = new org.openoffice.da.comp.w2lcommon.helper.MessageBox(xComponentContext);
try {
// Load the graphic into a new draw document as xDocument
// using a named filter
Object desktop = xMCF.createInstanceWithContext(
"com.sun.star.frame.Desktop", xComponentContext);
XComponentLoader xComponentLoader = (XComponentLoader)
UnoRuntime.queryInterface(XComponentLoader.class, desktop);
//msgBox.showMessage("Graphics","Trying to load using filter name "+importFilter.get(sSourceMime));
PropertyValue[] fileProps = new PropertyValue[3];
fileProps[0] = new PropertyValue();
fileProps[0].Name = "FilterName";
fileProps[0].Value = (String) importFilter.get(sSourceMime);
fileProps[1] = new PropertyValue();
fileProps[1].Name = "InputStream";
fileProps[1].Value = new ByteArrayToXInputStreamAdapter(source);
fileProps[2] = new PropertyValue();
fileProps[2].Name = "Hidden";
fileProps[2].Value = new Boolean(true);
XComponent xDocument = xComponentLoader.loadComponentFromURL(
"private:stream", "_blank", 0, fileProps);
// Get the first draw page as xDrawPage
XDrawPagesSupplier xDrawPagesSupplier = (XDrawPagesSupplier)
UnoRuntime.queryInterface(XDrawPagesSupplier.class, xDocument);
XDrawPages xDrawPages = xDrawPagesSupplier.getDrawPages();
Object drawPage = xDrawPages.getByIndex(0);
XDrawPage xDrawPage = (XDrawPage) UnoRuntime.queryInterface(
XDrawPage.class, drawPage);
// Get the shape as xShape
Object shape = xDrawPage.getByIndex(0);
XShape xShape = (XShape) UnoRuntime.queryInterface(XShape.class, shape);
// Move the shape to upper left corner of the page
Point position = new Point();
position.X = 0;
position.Y = 0;
xShape.setPosition(position);
// Adjust the page size and margin to the size of the graphic
XPropertySet xPageProps = (XPropertySet) UnoRuntime.queryInterface(
XPropertySet.class, xDrawPage);
Size size = xShape.getSize();
xPageProps.setPropertyValue("Width", new Integer(size.Width));
xPageProps.setPropertyValue("Height", new Integer(size.Height));
xPageProps.setPropertyValue("BorderTop", new Integer(0));
xPageProps.setPropertyValue("BorderBottom", new Integer(0));
xPageProps.setPropertyValue("BorderLeft", new Integer(0));
xPageProps.setPropertyValue("BorderRight", new Integer(0));
// Export the draw document (xDocument)
refreshDocument(xDocument);
XOutputStreamToByteArrayAdapter outputStream = new XOutputStreamToByteArrayAdapter();
PropertyValue[] exportProps = new PropertyValue[3];
exportProps[0] = new PropertyValue();
exportProps[0].Name = "FilterName";
exportProps[0].Value = (String) exportFilter.get(sTargetMime);
exportProps[1] = new PropertyValue();
exportProps[1].Name = "OutputStream";
exportProps[1].Value = outputStream;
exportProps[2] = new PropertyValue();
exportProps[2].Name = "Overwrite";
exportProps[2].Value = new Boolean(true);
XStorable xStore = (XStorable) UnoRuntime.queryInterface (
XStorable.class, xDocument);
xStore.storeToURL ("private:stream", exportProps);
outputStream.closeOutput();
byte[] result = outputStream.getBuffer();
xDocument.dispose();
return result;
}
catch (com.sun.star.beans.PropertyVetoException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.beans.UnknownPropertyException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.io.IOException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.lang.IllegalArgumentException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.lang.IndexOutOfBoundsException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.lang.WrappedTargetException e) {
msgBox.showMessage("Exception",e.toString());
}
catch (com.sun.star.uno.Exception e) {
msgBox.showMessage("Exception",e.toString());
}
// Conversion failed, for whatever reason
return null;
}
protected void refreshDocument(XComponent document) {
XRefreshable refreshable = (XRefreshable) UnoRuntime.queryInterface(XRefreshable.class, document);
if (refreshable != null) {
refreshable.refresh();
}
}
/* Dim SelSize As New com.sun.star.awt.Size
SelSize = oGraphic.Size
oDrawGraphic.GraphicURL = oGraphic.GraphicURL
oDrawGraphic.Size = SelSize
oDrawPage.add(oDrawGraphic)
oDrawGraphic.GraphicCrop = oGraphic.GraphicCrop
oDrawPage.Width = oGraphic.Size.Width
oDrawPage.Height = oGraphic.Size.Height
Dim aFilterData (1) As new com.sun.star.beans.PropertyValue
aFilterData(0).Name = "PixelWidth" '
aFilterData(0).Value = oDrawPage.Width/100 * iPixels / 25.40
aFilterData(1).Name = "PixelHeight"
aFilterData(1).Value = oDrawPage.Height/100 * iPixels / 25.40
Export( oDrawPage, sURLImageResized , aFilterData() )
On error resume Next
oDrawDoc.Close(True)
On error goto 0
SUB Export( xObject, sFileUrl As String, aFilterData )
Dim xExporter As Object
xExporter = createUnoService( "com.sun.star.drawing.GraphicExportFilter" )
xExporter.SetSourceDocument( xObject )
Dim aArgs (2) As new com.sun.star.beans.PropertyValue
'sFileURL = ConvertToURL(sFileURL)
aArgs(0).Name = "FilterName"
aArgs(0).Value = "jpg"
aArgs(1).Name = "URL"
aArgs(1).Value = sFileURL
'print sFileURL
aArgs(2).Name = "FilterData"
aArgs(2).Value = aFilterData
xExporter.filter( aArgs() )
END SUB*/
}

View file

@ -0,0 +1,547 @@
/************************************************************************
*
* OptionsDialogBase.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-14)
*
*/
package org.openoffice.da.comp.w2lcommon.filter;
import java.util.HashSet;
import com.sun.star.awt.XDialogEventHandler;
import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.XPropertyAccess;
import com.sun.star.beans.XPropertySet;
import com.sun.star.container.XNameAccess;
import com.sun.star.document.XDocumentInfoSupplier;
import com.sun.star.frame.XDesktop;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.IllegalArgumentException;
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.ui.dialogs.XExecutableDialog;
import com.sun.star.uno.Type;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.XChangesBatch;
import com.sun.star.util.XMacroExpander;
import org.openoffice.da.comp.w2lcommon.helper.DialogBase;
import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
/** This class provides an abstract uno component which implements a filter ui
*/
public abstract class OptionsDialogBase extends DialogBase implements
XPropertyAccess { // Filter ui requires XExecutableDialog + XPropertyAccess
//////////////////////////////////////////////////////////////////////////
// The subclass must override the following; and override the
// implementation of XDialogEventHandler if needed
/** Load settings from the registry to the dialog
* The subclass must implement this
*/
protected abstract void loadSettings(XPropertySet xRegistryProps);
/** Save settings from the dialog to the registry and create FilterData
* The subclass must implement this
*/
protected abstract void saveSettings(XPropertySet xRegistryProps, PropertyHelper filterData);
/** Return the name of the library containing the dialog
*/
public abstract String getDialogLibraryName();
/** Return the name of the dialog within the library
*/
public abstract String getDialogName();
/** Return the path to the options in the registry */
public abstract String getRegistryPath();
/** Create a new OptionsDialogBase */
public OptionsDialogBase(XComponentContext xContext) {
super(xContext);
this.xMSF = null; // must be set properly by subclass
mediaProps = null;
sConfigNames = null;
lockedOptions = new HashSet();
}
//////////////////////////////////////////////////////////////////////////
// Implement some methods required by DialogBase
/** Initialize the dialog (eg. with settings from the registry)
*/
public void initialize() {
try {
// Prepare registry view
Object view = getRegistryView(false);
XPropertySet xProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,view);
// Load settings using method from subclass
loadSettings(xProps);
// Dispose the registry view
disposeRegistryView(view);
}
catch (com.sun.star.uno.Exception e) {
// Failed to get registry view
}
}
/** Finalize the dialog after execution (eg. save settings to the registry)
*/
public void finalize() {
try {
// Prepare registry view
Object rwview = getRegistryView(true);
XPropertySet xProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,rwview);
// Save settings and create FilterData using method from subclass
PropertyHelper filterData = new PropertyHelper();
saveSettings(xProps, filterData);
// Commit registry changes
XChangesBatch xUpdateContext = (XChangesBatch)
UnoRuntime.queryInterface(XChangesBatch.class,rwview);
try {
xUpdateContext.commitChanges();
}
catch (Exception e) {
// ignore
}
// Dispose the registry view
disposeRegistryView(rwview);
// Update the media properties with the FilterData
PropertyHelper helper = new PropertyHelper(mediaProps);
helper.put("FilterData",filterData.toArray());
mediaProps = helper.toArray();
}
catch (com.sun.star.uno.Exception e) {
// Failed to get registry view
}
}
//////////////////////////////////////////////////////////////////////////
// Some private global variables
// The service factory
protected XMultiServiceFactory xMSF;
// The media properties (set/get via XPropertyAccess implementation)
private PropertyValue[] mediaProps;
// Configuration names (stored during execution of dialog)
private String[] sConfigNames;
// Set of locked controls
private HashSet lockedOptions;
//////////////////////////////////////////////////////////////////////////
// Some private utility methods
// Perform macro extansion
private String expandMacros(String s) {
if (s.startsWith("vnd.sun.star.expand:")) {
// The string contains a macro, usually as a result of using %origin% in the registry
s = s.substring(20);
Object expander = xContext.getValueByName("/singletons/com.sun.star.util.theMacroExpander");
XMacroExpander xExpander = (XMacroExpander) UnoRuntime.queryInterface (XMacroExpander.class, expander);
try {
return xExpander.expandMacros(s);
}
catch (IllegalArgumentException e) {
// Unknown macro name found, proceed and hope for the best
return s;
}
}
else {
return s;
}
}
// Get the template name from the document with ui focus
private String getTemplateName() {
try {
// Get current component
Object desktop = xContext.getServiceManager()
.createInstanceWithContext("com.sun.star.frame.Desktop",xContext);
XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class,desktop);
XComponent xComponent = xDesktop.getCurrentComponent();
// Get the document info property set
XDocumentInfoSupplier xDocInfoSuppl = (XDocumentInfoSupplier)
UnoRuntime.queryInterface(XDocumentInfoSupplier.class, xComponent);
Object docInfo = xDocInfoSuppl.getDocumentInfo();
XPropertySet xDocInfo = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class, docInfo);
return getPropertyValueAsString(xDocInfo,"Template");
}
catch (Exception e) {
return "";
}
}
// Get a view of the options root in the registry
private Object getRegistryView(boolean bUpdate)
throws com.sun.star.uno.Exception {
Object provider = xMSF.createInstance(
"com.sun.star.configuration.ConfigurationProvider");
XMultiServiceFactory xProvider = (XMultiServiceFactory)
UnoRuntime.queryInterface(XMultiServiceFactory.class,provider);
PropertyValue[] args = new PropertyValue[1];
args[0] = new PropertyValue();
args[0].Name = "nodepath";
args[0].Value = getRegistryPath();
String sServiceName = bUpdate ?
"com.sun.star.configuration.ConfigurationUpdateAccess" :
"com.sun.star.configuration.ConfigurationAccess";
Object view = xProvider.createInstanceWithArguments(sServiceName,args);
return view;
}
// Dispose a previously obtained registry view
private void disposeRegistryView(Object view) {
XComponent xComponent = (XComponent)
UnoRuntime.queryInterface(XComponent.class,view);
xComponent.dispose();
}
//////////////////////////////////////////////////////////////////////////
// Implement uno interfaces
// Override getTypes() from the interface XTypeProvider
public Type[] getTypes() {
Type[] typeReturn = {};
try {
typeReturn = new Type[] {
new Type( XServiceName.class ),
new Type( XServiceInfo.class ),
new Type( XTypeProvider.class ),
new Type( XExecutableDialog.class ),
new Type( XPropertyAccess.class ),
new Type( XDialogEventHandler.class ) };
} catch(Exception exception) {
}
return typeReturn;
}
// Implement the interface XPropertyAccess
public PropertyValue[] getPropertyValues() {
return mediaProps;
}
public void setPropertyValues(PropertyValue[] props) {
mediaProps = props;
}
//////////////////////////////////////////////////////////////////////////
// Various utility methods to be used by the sublasses
// Helpers to load and save settings
protected void updateLockedOptions() {
lockedOptions.clear();
short nItem = getListBoxSelectedItem("Config");
int nStdConfigs = getListBoxStringItemList("Config").length - sConfigNames.length;
if (nItem>=nStdConfigs) {
// Get current configuration name
String sName = sConfigNames[nItem-nStdConfigs];
try {
// Prepare registry view
Object view = getRegistryView(false);
XPropertySet xProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,view);
// Get the available configurations
Object configurations = getPropertyValue(xProps,"Configurations");
XNameAccess xConfigurations = (XNameAccess)
UnoRuntime.queryInterface(XNameAccess.class,configurations);
// Get the LockedOptions node from the desired configuration
String sLockedOptions = "";
Object config = xConfigurations.getByName(sName);
XPropertySet xCfgProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,config);
sLockedOptions = getPropertyValueAsString(xCfgProps,"LockedOptions");
// Dispose the registry view
disposeRegistryView(view);
// Feed lockedOptions with the comma separated list of options
int nStart = 0;
for (int i=0; i<sLockedOptions.length(); i++) {
if (sLockedOptions.charAt(i)==',') {
lockedOptions.add(sLockedOptions.substring(nStart,i).trim());
nStart = i+1;
}
}
if (nStart<sLockedOptions.length()) {
lockedOptions.add(sLockedOptions.substring(nStart).trim());
}
}
catch (Exception e) {
// no options will be locked...
}
}
}
protected boolean isLocked(String sOptionName) {
return lockedOptions.contains(sOptionName);
}
// Configuration
protected void loadConfig(XPropertySet xProps) {
// The list box is extended with configurations from the registry
String[] sStdConfigs = getListBoxStringItemList("Config");
int nStdConfigs = sStdConfigs.length;
Object configurations = getPropertyValue(xProps,"Configurations");
XNameAccess xConfigurations = (XNameAccess)
UnoRuntime.queryInterface(XNameAccess.class,configurations);
sConfigNames = xConfigurations.getElementNames();
int nRegConfigs = sConfigNames.length;
String[] sAllConfigs = new String[nStdConfigs+nRegConfigs];
for (short i=0; i<nStdConfigs; i++) {
sAllConfigs[i] = sStdConfigs[i];
}
for (short i=0; i<nRegConfigs; i++) {
try {
Object config = xConfigurations.getByName(sConfigNames[i]);
XPropertySet xCfgProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,config);
sAllConfigs[nStdConfigs+i] = getPropertyValueAsString(xCfgProps,"DisplayName");
}
catch (Exception e) {
sAllConfigs[nStdConfigs+i] = "";
}
}
setListBoxStringItemList("Config",sAllConfigs);
if (nStdConfigs+nRegConfigs<=12) {
setListBoxLineCount("Config",(short) (nStdConfigs+nRegConfigs));
}
else {
setListBoxLineCount("Config",(short) 12);
}
// Select item based on template name
String sTheTemplateName = getTemplateName();
Object templates = getPropertyValue(xProps,"Templates");
XNameAccess xTemplates = (XNameAccess)
UnoRuntime.queryInterface(XNameAccess.class,templates);
String[] sTemplateNames = xTemplates.getElementNames();
for (int i=0; i<sTemplateNames.length; i++) {
try {
Object template = xTemplates.getByName(sTemplateNames[i]);
XPropertySet xTplProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,template);
String sTemplateName = getPropertyValueAsString(xTplProps,"TemplateName");
if (sTemplateName.equals(sTheTemplateName)) {
String sConfigName = getPropertyValueAsString(xTplProps,"ConfigName");
for (short j=0; j<nRegConfigs; j++) {
if (sConfigNames[j].equals(sConfigName)) {
setListBoxSelectedItem("Config",(short) (nStdConfigs+j));
return;
}
}
}
}
catch (Exception e) {
// ignore
}
}
// Select item based on value stored in registry
short nConfig = getPropertyValueAsShort(xProps,"Config");
if (nConfig<nStdConfigs) {
setListBoxSelectedItem("Config",nConfig);
}
else { // Registry configurations are stored by name
String sConfigName = getPropertyValueAsString(xProps,"ConfigName");
for (short i=0; i<nRegConfigs; i++) {
if (sConfigNames[i].equals(sConfigName)) {
setListBoxSelectedItem("Config",(short) (nStdConfigs+i));
}
}
}
}
protected short saveConfig(XPropertySet xProps, PropertyHelper filterData) {
// The Config list box is common for all dialogs
Object configurations = getPropertyValue(xProps,"Configurations");
XNameAccess xNameAccess = (XNameAccess)
UnoRuntime.queryInterface(XNameAccess.class,configurations);
boolean bFound = false;
short nConfig = getListBoxSelectedItem("Config");
int nStdConfigs = getListBoxStringItemList("Config").length - sConfigNames.length;
if (nConfig>=nStdConfigs) { // only handle registry configurations
int i = nConfig-nStdConfigs;
try {
Object config = xNameAccess.getByName(sConfigNames[i]);
XPropertySet xCfgProps = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class,config);
filterData.put("ConfigURL",expandMacros(getPropertyValueAsString(xCfgProps,"ConfigURL")));
filterData.put("TemplateURL",expandMacros(getPropertyValueAsString(xCfgProps,"TargetTemplateURL")));
setPropertyValue(xProps,"ConfigName",sConfigNames[i]);
bFound = true;
}
catch (Exception e) {
}
}
setPropertyValue(xProps,"Config",nConfig);
if (!bFound) { setPropertyValue(xProps,"ConfigName",""); }
return nConfig;
}
// Check box option (boolean)
protected boolean loadCheckBoxOption(XPropertySet xProps, String sName) {
boolean bValue = getPropertyValueAsBoolean(xProps,sName);
setCheckBoxStateAsBoolean(sName, bValue);
return bValue;
}
protected boolean saveCheckBoxOption(XPropertySet xProps, String sName) {
boolean bValue = getCheckBoxStateAsBoolean(sName);
setPropertyValue(xProps, sName, bValue);
return bValue;
}
protected boolean saveCheckBoxOption(XPropertySet xProps, PropertyHelper filterData,
String sName, String sOptionName) {
boolean bValue = saveCheckBoxOption(xProps, sName);
if (!isLocked(sOptionName)) {
filterData.put(sOptionName, Boolean.toString(bValue));
}
return bValue;
}
// List box option
protected short loadListBoxOption(XPropertySet xProps, String sName) {
short nValue = getPropertyValueAsShort(xProps, sName);
setListBoxSelectedItem(sName ,nValue);
return nValue;
}
protected short saveListBoxOption(XPropertySet xProps, String sName) {
short nValue = getListBoxSelectedItem(sName);
setPropertyValue(xProps, sName, nValue);
return nValue;
}
protected short saveListBoxOption(XPropertySet xProps, PropertyHelper filterData,
String sName, String sOptionName, String[] sValues) {
short nValue = saveListBoxOption(xProps, sName);
if (!isLocked(sOptionName) && (nValue>=0) && (nValue<sValues.length)) {
filterData.put(sOptionName, sValues[nValue]);
}
return nValue;
}
// Combo box option
protected String loadComboBoxOption(XPropertySet xProps, String sName) {
String sValue = getPropertyValueAsString(xProps, sName);
setComboBoxText(sName ,sValue);
return sValue;
}
protected String saveComboBoxOption(XPropertySet xProps, String sName) {
String sValue = getComboBoxText(sName);
setPropertyValue(xProps, sName, sValue);
return sValue;
}
protected String saveComboBoxOption(XPropertySet xProps, PropertyHelper filterData,
String sName, String sOptionName) {
String sValue = saveComboBoxOption(xProps, sName);
if (!isLocked(sOptionName)) {
filterData.put(sOptionName, sValue);
}
return sValue;
}
// Text Field option
protected String loadTextFieldOption(XPropertySet xProps, String sName) {
String sValue = getPropertyValueAsString(xProps, sName);
setTextFieldText(sName ,sValue);
return sValue;
}
protected String saveTextFieldOption(XPropertySet xProps, String sName) {
String sValue = getTextFieldText(sName);
setPropertyValue(xProps, sName, sValue);
return sValue;
}
protected String saveTextFieldOption(XPropertySet xProps, PropertyHelper filterData,
String sName, String sOptionName) {
String sValue = saveTextFieldOption(xProps, sName);
if (!isLocked(sOptionName)) {
filterData.put(sOptionName, sValue);
}
return sValue;
}
// Numeric option
protected int loadNumericOption(XPropertySet xProps, String sName) {
int nValue = getPropertyValueAsInteger(xProps, sName);
setNumericFieldValue(sName, nValue);
return nValue;
}
protected int saveNumericOption(XPropertySet xProps, String sName) {
int nValue = getNumericFieldValue(sName);
setPropertyValue(xProps, sName, nValue);
return nValue;
}
protected int saveNumericOptionAsPercentage(XPropertySet xProps,
PropertyHelper filterData, String sName, String sOptionName) {
int nValue = saveNumericOption(xProps, sName);
if (!isLocked(sOptionName)) {
filterData.put(sOptionName,Integer.toString(nValue)+"%");
}
return nValue;
}
}

View file

@ -0,0 +1,503 @@
/************************************************************************
*
* DialogBase.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.w2lcommon.helper;
import com.sun.star.awt.XControl;
import com.sun.star.awt.XControlContainer;
import com.sun.star.awt.XControlModel;
import com.sun.star.awt.XDialog;
import com.sun.star.awt.XDialogEventHandler;
import com.sun.star.awt.XDialogProvider2;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.lang.XServiceName;
import com.sun.star.lang.XTypeProvider;
import com.sun.star.ui.dialogs.ExecutableDialogResults;
import com.sun.star.ui.dialogs.XExecutableDialog;
import com.sun.star.uno.Type;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
/** This class provides an abstract uno component which implements a dialog
* from an xml description (using the DialogProvider2 service)
*/
public abstract class DialogBase implements
XTypeProvider, XServiceInfo, XServiceName, // Uno component
XExecutableDialog, // Execute the dialog
XDialogEventHandler { // Event handling for dialog
//////////////////////////////////////////////////////////////////////////
// The subclass must override the following; and override the
// implementation of XDialogEventHandler if needed
/** The component will be registered under this name.
* The subclass must override this with a suitable name
*/
public static String __serviceName = "";
/** The component should also have an implementation name.
* The subclass must override this with a suitable name
*/
public static String __implementationName = "";
/** Return the name of the library containing the dialog
* The subclass must override this to provide the name of the library
*/
public abstract String getDialogLibraryName();
/** Return the name of the dialog within the library
* The subclass must override this to provide the name of the dialog
*/
public abstract String getDialogName();
/** Initialize the dialog (eg. with settings from the registry)
* The subclass must implement this
*/
protected abstract void initialize();
/** Finalize the dialog after execution (eg. save settings to the registry)
* The subclass must implement this
*/
protected abstract void finalize();
//////////////////////////////////////////////////////////////////////////
// Some constants
// State of a checkbox
protected static final short CHECKBOX_NOT_CHECKED = 0;
protected static final short CHECKBOX_CHECKED = 1;
protected static final short CHECKBOX_DONT_KNOW = 2;
//////////////////////////////////////////////////////////////////////////
// Some private global variables
// The component context (from constructor)
protected XComponentContext xContext;
// The dialog (created by XExecutableDialog implementation)
private XDialog xDialog;
private String sTitle;
//////////////////////////////////////////////////////////////////////////
// The constructor
/** Create a new OptionsDialogBase */
public DialogBase(XComponentContext xContext) {
this.xContext = xContext;
xDialog = null;
sTitle = null;
}
//////////////////////////////////////////////////////////////////////////
// Implement uno interfaces
// Implement the interface XTypeProvider
public Type[] getTypes() {
Type[] typeReturn = {};
try {
typeReturn = new Type[] {
new Type( XServiceName.class ),
new Type( XServiceInfo.class ),
new Type( XTypeProvider.class ),
new Type( XExecutableDialog.class ),
new Type( XDialogEventHandler.class ) };
} catch(Exception exception) {
}
return typeReturn;
}
public byte[] getImplementationId() {
byte[] byteReturn = {};
byteReturn = new String( "" + this.hashCode() ).getBytes();
return( byteReturn );
}
// Implement the interface XServiceName
public String getServiceName() {
return __serviceName;
}
// Implement the interface XServiceInfo
public boolean supportsService(String sServiceName) {
return sServiceName.equals(__serviceName);
}
public String getImplementationName() {
return __implementationName;
}
public String[] getSupportedServiceNames() {
String[] sSupportedServiceNames = { __serviceName };
return sSupportedServiceNames;
}
// Implement the interface XExecutableDialog
public void setTitle(String sTitle) {
this.sTitle = sTitle;
}
public short execute() {
try {
// Create the dialog
XMultiComponentFactory xMCF = xContext.getServiceManager();
Object provider = xMCF.createInstanceWithContext(
"com.sun.star.awt.DialogProvider2", xContext);
XDialogProvider2 xDialogProvider = (XDialogProvider2)
UnoRuntime.queryInterface(XDialogProvider2.class, provider);
String sDialogUrl = "vnd.sun.star.script:"+getDialogLibraryName()+"."
+getDialogName()+"?location=application";
xDialog = xDialogProvider.createDialogWithHandler(sDialogUrl, this);
if (sTitle!=null) { xDialog.setTitle(sTitle); }
// Do initialization using method from subclass
initialize();
// Execute the dialog
short nResult = xDialog.execute();
if (nResult == ExecutableDialogResults.OK) {
// Finalize after execution of dialog using method from subclass
finalize();
}
xDialog.endExecute();
return nResult;
}
catch (Exception e) {
MessageBox msgBox = new MessageBox(xContext);
msgBox.showMessage("Error",e.toString()+" "+e.getStackTrace()[0].toString());
// continue as if the dialog was executed OK
return ExecutableDialogResults.OK;
}
}
// Implement the interface XDialogEventHandler
public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
// Do nothing, leaving the responsibility to the subclass
return true;
}
public String[] getSupportedMethodNames() {
// We do not support any method names, subclass should take care of this
return new String[0];
}
//////////////////////////////////////////////////////////////////////////
// Helpers to access controls in the dialog (to be used by the subclass)
// Note: The helpers fail silently if an exception occurs. Could query the
// the ClassId property for the control type and check that the property
// exists to ensure a correct behaviour in all cases, but as long as the
// helpers are used correctly, this doesn't really matter.
// Get the properties of a named control in the dialog
private XPropertySet getControlProperties(String sControlName) {
XControlContainer xContainer = (XControlContainer)
UnoRuntime.queryInterface(XControlContainer.class, xDialog);
XControl xControl = xContainer.getControl(sControlName);
XControlModel xModel = xControl.getModel();
XPropertySet xPropertySet = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class, xModel);
return xPropertySet;
}
protected void setControlEnabled(String sControlName, boolean bEnabled) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("Enabled", new Boolean(bEnabled));
}
catch (Exception e) {
// Will fail if the control does not exist
}
}
protected short getCheckBoxState(String sControlName) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return ((Short) xPropertySet.getPropertyValue("State")).shortValue();
}
catch (Exception e) {
// Will fail if the control does not exist or is not a checkbox
return CHECKBOX_DONT_KNOW;
}
}
protected boolean getCheckBoxStateAsBoolean(String sControlName) {
return getCheckBoxState(sControlName)==CHECKBOX_CHECKED;
}
protected void setCheckBoxState(String sControlName, short nState) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("State",new Short(nState));
}
catch (Exception e) {
// will fail if the control does not exist or is not a checkbox or
// nState has an illegal value
}
}
protected void setCheckBoxStateAsBoolean(String sControlName, boolean bChecked) {
setCheckBoxState(sControlName,bChecked ? CHECKBOX_CHECKED : CHECKBOX_NOT_CHECKED);
}
protected String[] getListBoxStringItemList(String sControlName) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return (String[]) xPropertySet.getPropertyValue("StringItemList");
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box
return new String[0];
}
}
protected void setListBoxStringItemList(String sControlName, String[] items) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("StringItemList",items);
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box
}
}
protected short getListBoxSelectedItem(String sControlName) {
// Returns the first selected element in case of a multiselection
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
short[] selection = (short[]) xPropertySet.getPropertyValue("SelectedItems");
return selection[0];
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box
return -1;
}
}
protected void setListBoxSelectedItem(String sControlName, short nIndex) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
short[] selection = new short[1];
selection[0] = nIndex;
xPropertySet.setPropertyValue("SelectedItems",selection);
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box or
// nIndex is an illegal value
}
}
protected short getListBoxLineCount(String sControlName) {
// Returns the first selected element in case of a multiselection
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return ((Short) xPropertySet.getPropertyValue("LineCount")).shortValue();
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box
return 0;
}
}
protected void setListBoxLineCount(String sControlName, short nLineCount) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("LineCount",new Short(nLineCount));
}
catch (Exception e) {
// Will fail if the control does not exist or is not a list box or
// nLineCount is an illegal value
}
}
protected String getComboBoxText(String sControlName) {
// Returns the text of a combobox
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return (String) xPropertySet.getPropertyValue("Text");
}
catch (Exception e) {
// Will fail if the control does not exist or is not a combo
return "";
}
}
protected void setComboBoxText(String sControlName, String sText) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("Text", sText);
}
catch (Exception e) {
// Will fail if the control does not exist or is not a combo box or
// nText is an illegal value
}
}
protected String getTextFieldText(String sControlName) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return (String) xPropertySet.getPropertyValue("Text");
}
catch (Exception e) {
// Will fail if the control does not exist or is not a text field
return "";
}
}
protected void setTextFieldText(String sControlName, String sText) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("Text",sText);
}
catch (Exception e) {
// Will fail if the control does not exist or is not a text field
}
}
protected String getFormattedFieldText(String sControlName) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return (String) xPropertySet.getPropertyValue("Text");
}
catch (Exception e) {
// Will fail if the control does not exist or is not a formatted field
return "";
}
}
protected void setFormattedFieldText(String sControlName, String sText) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("Text",sText);
}
catch (Exception e) {
// Will fail if the control does not exist or is not a formatted field
}
}
protected int getNumericFieldValue(String sControlName) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
return ((Double) xPropertySet.getPropertyValue("Value")).intValue();
}
catch (Exception e) {
// Will fail if the control does not exist or is not a numeric field
return 0;
}
}
protected void setNumericFieldValue(String sControlName, int nValue) {
XPropertySet xPropertySet = getControlProperties(sControlName);
try {
xPropertySet.setPropertyValue("Value",new Double(nValue));
}
catch (Exception e) {
// Will fail if the control does not exist or is not a numeric field
}
}
// Helpers for access to an XPropertySet. The helpers will fail silently if
// names or data is provided, but the subclass is expected to use them with
// correct data only...
protected Object getPropertyValue(XPropertySet xProps, String sName) {
try {
return xProps.getPropertyValue(sName);
}
catch (UnknownPropertyException e) {
return null;
}
catch (WrappedTargetException e) {
return null;
}
}
protected void setPropertyValue(XPropertySet xProps, String sName, Object value) {
try {
xProps.setPropertyValue(sName,value);
}
catch (UnknownPropertyException e) {
}
catch (PropertyVetoException e) { // unacceptable value
}
catch (IllegalArgumentException e) {
}
catch (WrappedTargetException e) {
}
}
protected String getPropertyValueAsString(XPropertySet xProps, String sName) {
Object value = getPropertyValue(xProps,sName);
return value instanceof String ? (String) value : "";
}
protected int getPropertyValueAsInteger(XPropertySet xProps, String sName) {
Object value = getPropertyValue(xProps,sName);
return value instanceof Integer ? ((Integer) value).intValue() : 0;
}
protected void setPropertyValue(XPropertySet xProps, String sName, int nValue) {
setPropertyValue(xProps,sName,new Integer(nValue));
}
protected short getPropertyValueAsShort(XPropertySet xProps, String sName) {
Object value = getPropertyValue(xProps,sName);
return value instanceof Short ? ((Short) value).shortValue() : 0;
}
protected void setPropertyValue(XPropertySet xProps, String sName, short nValue) {
setPropertyValue(xProps,sName,new Short(nValue));
}
protected boolean getPropertyValueAsBoolean(XPropertySet xProps, String sName) {
Object value = getPropertyValue(xProps,sName);
return value instanceof Boolean ? ((Boolean) value).booleanValue() : false;
}
protected void setPropertyValue(XPropertySet xProps, String sName, boolean bValue) {
setPropertyValue(xProps,sName,new Boolean(bValue));
}
}

View file

@ -0,0 +1,105 @@
/************************************************************************
*
* MessageBox.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.helper;
import com.sun.star.awt.Rectangle;
import com.sun.star.awt.WindowAttribute;
import com.sun.star.awt.WindowClass;
import com.sun.star.awt.WindowDescriptor;
import com.sun.star.awt.XMessageBox;
import com.sun.star.awt.XToolkit;
import com.sun.star.awt.XWindowPeer;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XFrame;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
/** This class provides simple access to a uno awt message box
*/
public class MessageBox {
private XFrame xFrame;
private XToolkit xToolkit;
/** Create a new MessageBox belonging to the current frame
*/
public MessageBox(XComponentContext xContext) {
this(xContext,null);
}
/** Create a new MessageBox belonging to a specific frame
*/
public MessageBox(XComponentContext xContext, XFrame xFrame) {
try {
Object toolkit = xContext.getServiceManager()
.createInstanceWithContext("com.sun.star.awt.Toolkit",xContext);
xToolkit = (XToolkit) UnoRuntime.queryInterface(XToolkit.class,toolkit);
if (xFrame==null) {
Object desktop = xContext.getServiceManager()
.createInstanceWithContext("com.sun.star.frame.Desktop",xContext);
XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class,desktop);
xFrame = xDesktop.getCurrentFrame();
}
this.xFrame = xFrame;
}
catch (Exception e) {
// Failed to get toolkit or frame
xToolkit = null;
xFrame = null;
}
}
public void showMessage(String sTitle, String sMessage) {
if (xToolkit==null || xFrame==null) { return; }
try {
WindowDescriptor descriptor = new WindowDescriptor();
descriptor.Type = WindowClass.MODALTOP;
descriptor.WindowServiceName = "infobox";
descriptor.ParentIndex = -1;
descriptor.Parent = (XWindowPeer) UnoRuntime.queryInterface(
XWindowPeer.class,xFrame.getContainerWindow());
descriptor.Bounds = new Rectangle(0,0,300,200);
descriptor.WindowAttributes = WindowAttribute.BORDER |
WindowAttribute.MOVEABLE | WindowAttribute.CLOSEABLE;
XWindowPeer xPeer = xToolkit.createWindow(descriptor);
if (xPeer!=null) {
XMessageBox xMessageBox = (XMessageBox)
UnoRuntime.queryInterface(XMessageBox.class,xPeer);
if (xMessageBox!=null) {
xMessageBox.setCaptionText(sTitle);
xMessageBox.setMessageText(sMessage);
xMessageBox.execute();
}
}
}
catch (Exception e) {
// ignore, give up...
}
}
}

View file

@ -0,0 +1,78 @@
/************************************************************************
*
* PropertyHelper.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.helper;
import java.util.Enumeration;
import java.util.Hashtable;
import com.sun.star.beans.PropertyValue;
/** This class provides access by name to a <code>PropertyValue</code> array
*/
public class PropertyHelper {
private Hashtable data;
public PropertyHelper() {
data = new Hashtable();
}
public PropertyHelper(PropertyValue[] props) {
data = new Hashtable();
int nLen = props.length;
for (int i=0; i<nLen; i++) {
data.put(props[i].Name,props[i].Value);
}
}
public void put(String sName, Object value) {
data.put(sName,value);
}
public Object get(String sName) {
return data.get(sName);
}
public Enumeration keys() {
return data.keys();
}
public PropertyValue[] toArray() {
int nSize = data.size();
PropertyValue[] props = new PropertyValue[nSize];
int i=0;
Enumeration keys = keys();
while (keys.hasMoreElements()) {
String sKey = (String) keys.nextElement();
props[i] = new PropertyValue();
props[i].Name = sKey;
props[i++].Value = get(sKey);
}
return props;
}
}

View file

@ -0,0 +1,351 @@
/************************************************************************
*
* LaTeXOptionsDialog.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.writer2latex;
import com.sun.star.awt.XDialog;
import com.sun.star.beans.XPropertySet;
//import com.sun.star.frame.XDesktop;
//import com.sun.star.lang.XComponent;
//import com.sun.star.text.XTextFieldsSupplier;
//import com.sun.star.uno.UnoRuntime;
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
* LaTeX export
*/
public class LaTeXOptionsDialog extends OptionsDialogBase {
// Translate list box items to configuration option values
private static final String[] BACKEND_VALUES =
{ "generic", "pdftex", "dvips", "unspecified" };
private static final String[] INPUTENCODING_VALUES =
{ "ascii", "latin1", "latin2", "iso-8859-7", "cp1250", "cp1251", "koi8-r", "utf8" };
private static final String[] NOTES_VALUES =
{ "ignore", "comment", "marginpar", "pdfannotation" };
private static final String[] FLOATOPTIONS_VALUES =
{ "", "tp", "bp", "htp", "hbp" };
/** The component will be registered under this name.
*/
public static String __serviceName = "org.openoffice.da.writer2latex.LaTeXOptionsDialog";
/** The component should also have an implementation name.
* The subclass should override this with a suitable name
*/
public static String __implementationName = "org.openoffice.da.comp.writer2latex.LaTeXOptionsDialog";
public String getDialogLibraryName() { return "W2LDialogs"; }
/** Create a new LaTeXOptionsDialog */
public LaTeXOptionsDialog(XComponentContext xContext) {
super(xContext);
xMSF = W2LRegistration.xMultiServiceFactory;
}
/** Return the name of the dialog within the library
*/
public String getDialogName() { return "LaTeXOptions"; }
/** Return the name of the registry path
*/
public String getRegistryPath() {
return "/org.openoffice.da.Writer2LaTeX.Options/LaTeXOptions";
}
/** Load settings from the registry to the dialog */
protected void loadSettings(XPropertySet xProps) {
// General
loadConfig(xProps);
loadListBoxOption(xProps,"Backend");
loadListBoxOption(xProps,"Inputencoding");
loadCheckBoxOption(xProps,"Multilingual");
loadCheckBoxOption(xProps,"GreekMath");
loadCheckBoxOption(xProps,"AdditionalSymbols");
// Bibliography
loadCheckBoxOption(xProps,"UseBibtex");
loadComboBoxOption(xProps,"BibtexStyle");
// Files
loadCheckBoxOption(xProps,"WrapLines");
loadNumericOption(xProps,"WrapLinesAfter");
loadCheckBoxOption(xProps,"SplitLinkedSections");
loadCheckBoxOption(xProps,"SplitToplevelSections");
loadCheckBoxOption(xProps,"SaveImagesInSubdir");
// Special content
loadListBoxOption(xProps,"Notes");
loadCheckBoxOption(xProps,"Metadata");
// Figures and tables
loadCheckBoxOption(xProps,"OriginalImageSize");
loadCheckBoxOption(xProps,"OptimizeSimpleTables");
loadNumericOption(xProps,"SimpleTableLimit");
loadCheckBoxOption(xProps,"FloatTables");
loadCheckBoxOption(xProps,"FloatFigures");
loadListBoxOption(xProps,"FloatOptions");
// AutoCorrect
loadCheckBoxOption(xProps,"IgnoreHardPageBreaks");
loadCheckBoxOption(xProps,"IgnoreHardLineBreaks");
loadCheckBoxOption(xProps,"IgnoreEmptyParagraphs");
loadCheckBoxOption(xProps,"IgnoreDoubleSpaces");
updateLockedOptions();
enableControls();
}
/** Save settings from the dialog to the registry and create FilterData */
protected void saveSettings(XPropertySet xProps, PropertyHelper filterData) {
// General
short nConfig = saveConfig(xProps, filterData);
switch (nConfig) {
case 0: filterData.put("ConfigURL","*ultraclean.xml"); break;
case 1: filterData.put("ConfigURL","*clean.xml"); break;
case 2: filterData.put("ConfigURL","*default.xml"); break;
case 3: filterData.put("ConfigURL","*pdfprint.xml"); break;
case 4: filterData.put("ConfigURL","*pdfscreen.xml"); break;
case 5: filterData.put("ConfigURL","$(user)/writer2latex.xml");
filterData.put("AutoCreate","true");
}
saveListBoxOption(xProps, filterData, "Backend", "backend", BACKEND_VALUES );
if (getListBoxSelectedItem("Config")==4) {
// pdfscreen locks the backend to pdftex
filterData.put("backend","pdftex");
}
saveListBoxOption(xProps, filterData, "Inputencoding", "inputencoding", INPUTENCODING_VALUES);
saveCheckBoxOption(xProps, filterData, "Multilingual", "multilingual");
saveCheckBoxOption(xProps, filterData, "GreekMath", "greek_math");
// AdditionalSymbols sets 5 different w2l options...
saveCheckBoxOption(xProps, filterData, "AdditionalSymbols", "use_pifont");
saveCheckBoxOption(xProps, filterData, "AdditionalSymbols", "use_ifsym");
saveCheckBoxOption(xProps, filterData, "AdditionalSymbols", "use_wasysym");
saveCheckBoxOption(xProps, filterData, "AdditionalSymbols", "use_eurosym");
saveCheckBoxOption(xProps, filterData, "AdditionalSymbols", "use_tipa");
// Bibliography
saveCheckBoxOption(xProps, filterData, "UseBibtex", "use_bibtex");
saveComboBoxOption(xProps, filterData, "BibtexStyle", "bibtex_style");
// Files
boolean bWrapLines = saveCheckBoxOption(xProps, "WrapLines");
int nWrapLinesAfter = saveNumericOption(xProps, "WrapLinesAfter");
if (!isLocked("wrap_lines_after")) {
if (bWrapLines) {
filterData.put("wrap_lines_after",Integer.toString(nWrapLinesAfter));
}
else {
filterData.put("wrap_lines_after","0");
}
}
saveCheckBoxOption(xProps, filterData, "SplitLinkedSections", "split_linked_sections");
saveCheckBoxOption(xProps, filterData, "SplitToplevelSections", "split_toplevel_sections");
saveCheckBoxOption(xProps, filterData, "SaveImagesInSubdir", "save_images_in_subdir");
// Special content
saveListBoxOption(xProps, filterData, "Notes", "notes", NOTES_VALUES);
saveCheckBoxOption(xProps, filterData, "Metadata", "metadata");
// Figures and tables
saveCheckBoxOption(xProps, filterData, "OriginalImageSize", "original_image_size");
boolean bOptimizeSimpleTables = saveCheckBoxOption(xProps,"OptimizeSimpleTables");
int nSimpleTableLimit = saveNumericOption(xProps,"SimpleTableLimit");
if (!isLocked("simple_table_limit")) {
if (bOptimizeSimpleTables) {
filterData.put("simple_table_limit",Integer.toString(nSimpleTableLimit));
}
else {
filterData.put("simple_table_limit","0");
}
}
saveCheckBoxOption(xProps, filterData, "FloatTables", "float_tables");
saveCheckBoxOption(xProps, filterData, "FloatFigures", "float_figures");
saveListBoxOption(xProps, filterData, "FloatOptions", "float_options", FLOATOPTIONS_VALUES);
// AutoCorrect
saveCheckBoxOption(xProps, filterData, "IgnoreHardPageBreaks", "ignore_hard_page_breaks");
saveCheckBoxOption(xProps, filterData, "IgnoreHardLineBreaks", "ignore_hard_line_breaks");
saveCheckBoxOption(xProps, filterData, "IgnoreEmptyParagraphs", "ignore_empty_paragraphs");
saveCheckBoxOption(xProps, filterData, "IgnoreDoubleSpaces", "ignore_double_spaces");
}
// Implement XDialogEventHandler
public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
if (sMethod.equals("ConfigChange")) {
updateLockedOptions();
enableControls();
}
else if (sMethod.equals("UseBibtexChange")) {
enableBibtexStyle();
}
else if (sMethod.equals("WrapLinesChange")) {
enableWrapLinesAfter();
}
else if (sMethod.equals("OptimizeSimpleTablesChange")) {
enableSimpleTableLimit();
}
else if (sMethod.equals("FloatTablesChange")) {
enableFloatOptions();
}
else if (sMethod.equals("FloatFiguresChange")) {
enableFloatOptions();
}
return true;
}
public String[] getSupportedMethodNames() {
String[] sNames = { "ConfigChange", "UseBibtexChange", "WrapLinesChange",
"OptimizeSimpleTablesChange", "FloatTablesChange", "FloatFiguresChange" };
return sNames;
}
protected boolean isLocked(String sOptionName) {
if ("backend".equals(sOptionName)) {
// backend must be pdf for pdfscreen
return getListBoxSelectedItem("Config")==4 || super.isLocked(sOptionName);
}
else if ("additional_symbols".equals(sOptionName)) {
// additional_symbols is disabled for custom config (where the 5
// individual options can be set independently)
return getListBoxSelectedItem("Config")==5 || super.isLocked(sOptionName);
}
else if ("use_pifont".equals(sOptionName)) {
return isLocked("additional_symbols");
}
else if ("use_ifsym".equals(sOptionName)) {
return isLocked("additional_symbols");
}
else if ("use_wasysym".equals(sOptionName)) {
return isLocked("additional_symbols");
}
else if ("use_eurosym".equals(sOptionName)) {
return isLocked("additional_symbols");
}
else if ("use_tipa".equals(sOptionName)) {
return isLocked("additional_symbols");
}
else {
return super.isLocked(sOptionName);
}
}
private void enableControls() {
// General
setControlEnabled("BackendLabel",!isLocked("backend"));
setControlEnabled("Backend",!isLocked("backend"));
setControlEnabled("InputencodingLabel",!isLocked("inputencoding"));
setControlEnabled("Inputencoding",!isLocked("inputencoding"));
setControlEnabled("Multilingual",!isLocked("multilingual"));
setControlEnabled("GreekMath",!isLocked("greek_math"));
setControlEnabled("AdditionalSymbols",!isLocked("additional_symbols"));
// Bibliography
setControlEnabled("UseBibtex",!isLocked("use_bibtex"));
boolean bUseBibtex = getCheckBoxStateAsBoolean("UseBibtex");
setControlEnabled("BibtexStyleLabel",!isLocked("bibtex_style") && bUseBibtex);
setControlEnabled("BibtexStyle",!isLocked("bibtex_style") && bUseBibtex);
// Files
setControlEnabled("WrapLines",!isLocked("wrap_lines_after"));
boolean bWrapLines = getCheckBoxStateAsBoolean("WrapLines");
setControlEnabled("WrapLinesAfterLabel",!isLocked("wrap_lines_after") && bWrapLines);
setControlEnabled("WrapLinesAfter",!isLocked("wrap_lines_after") && bWrapLines);
setControlEnabled("SplitLinkedSections",!isLocked("split_linked_sections"));
setControlEnabled("SplitToplevelSections",!isLocked("split_toplevel_sections"));
setControlEnabled("SaveImagesInSubdir",!isLocked("save_images_in_subdir"));
// Special content
setControlEnabled("NotesLabel",!isLocked("notes"));
setControlEnabled("Notes",!isLocked("notes"));
setControlEnabled("Metadata",!isLocked("metadata"));
// Figures and tables
setControlEnabled("OriginalImageSize",!isLocked("original_image_size"));
setControlEnabled("OptimizeSimpleTables",!isLocked("simple_table_limit"));
boolean bOptimizeSimpleTables = getCheckBoxStateAsBoolean("OptimizeSimpleTables");
setControlEnabled("SimpleTableLimitLabel",!isLocked("simple_table_limit") && bOptimizeSimpleTables);
setControlEnabled("SimpleTableLimit",!isLocked("simple_table_limit") && bOptimizeSimpleTables);
setControlEnabled("FloatTables",!isLocked("float_tables"));
setControlEnabled("FloatFigures",!isLocked("float_figures"));
boolean bFloat = getCheckBoxStateAsBoolean("FloatFigures") ||
getCheckBoxStateAsBoolean("FloatTables");
setControlEnabled("FloatOptionsLabel",!isLocked("float_options") && bFloat);
setControlEnabled("FloatOptions",!isLocked("float_options") && bFloat);
// AutoCorrect
setControlEnabled("IgnoreHardPageBreaks",!isLocked("ignore_hard_page_breaks"));
setControlEnabled("IgnoreHardLineBreaks",!isLocked("ignore_hard_line_breaks"));
setControlEnabled("IgnoreEmptyParagraphs",!isLocked("ignore_empty_paragraphs"));
setControlEnabled("IgnoreDoubleSpaces",!isLocked("ignore_double_spaces"));
}
private void enableBibtexStyle() {
if (!isLocked("bibtex_style")) {
boolean bState = getCheckBoxStateAsBoolean("UseBibtex");
setControlEnabled("BibtexStyleLabel",bState);
setControlEnabled("BibtexStyle",bState);
}
}
private void enableWrapLinesAfter() {
if (!isLocked("wrap_lines_after")) {
boolean bState = getCheckBoxStateAsBoolean("WrapLines");
setControlEnabled("WrapLinesAfterLabel",bState);
setControlEnabled("WrapLinesAfter",bState);
}
}
private void enableSimpleTableLimit() {
if (!isLocked("simple_table_limit")) {
boolean bState = getCheckBoxStateAsBoolean("OptimizeSimpleTables");
setControlEnabled("SimpleTableLimitLabel",bState);
setControlEnabled("SimpleTableLimit",bState);
}
}
private void enableFloatOptions() {
if (!isLocked("float_options")) {
boolean bState = getCheckBoxStateAsBoolean("FloatFigures") ||
getCheckBoxStateAsBoolean("FloatTables");
setControlEnabled("FloatOptionsLabel",bState);
setControlEnabled("FloatOptions",bState);
}
}
}

View file

@ -0,0 +1,56 @@
/************************************************************************
*
* W2LExportFilter.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.writer2latex;
import com.sun.star.uno.XComponentContext;
import org.openoffice.da.comp.w2lcommon.filter.ExportFilterBase;
/** This class implements the LaTeX and BibTeX export filter component
*/
public class W2LExportFilter extends ExportFilterBase {
/** Service name for the component */
public static final String __serviceName = "org.openoffice.da.comp.writer2latex.W2LExportFilter";
/** Implementation name for the component */
public static final String __implementationName = "org.openoffice.da.comp.writer2latex.W2LExportFilter";
/** Filter name to include in error messages */
public static final String __displayName = "Writer2LaTeX";
public W2LExportFilter(XComponentContext xComponentContext1) {
super(xComponentContext1);
xMSF = W2LRegistration.xMultiServiceFactory;
}
}

View file

@ -0,0 +1,103 @@
/************************************************************************
*
* W2LRegistration.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.writer2latex;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.registry.XRegistryKey;
import com.sun.star.comp.loader.FactoryHelper;
/** This class provides a static method to instantiate our uno components
* on demand (__getServiceFactory()), and a static method to give
* information about the components (__writeRegistryServiceInfo()).
* Furthermore, it saves the XMultiServiceFactory provided to the
* __getServiceFactory method for future reference by the componentes.
*/
public class W2LRegistration {
public static XMultiServiceFactory xMultiServiceFactory;
/**
* Returns a factory for creating the service.
* This method is called by the <code>JavaLoader</code>
*
* @return returns a <code>XSingleServiceFactory</code> 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 <code>JavaLoader</code>
* <p>
* @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);
}
}

View file

@ -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 );
}
}

View file

@ -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<nSize; i++) {
String sName = lArguments[i].Name;
Object value = lArguments[i].Value;
if ("Recurse".equals(sName)) {
bRecurse = !"false".equals(getValue(value));
}
else if ("IncludePdf".equals(sName)) {
bIncludePdf = !"false".equals(getValue(value));
}
else if ("IncludeOriginal".equals(sName)) {
bIncludeOriginal = "true".equals(getValue(value));
}
else if ("UseTitle".equals(sName)) {
bUseTitle = !"false".equals(getValue(value));
}
else if ("UseDescription".equals(sName)) {
bUseDescription = !"false".equals(getValue(value));
}
else if ("Uplink".equals(sName)) {
sUplink = getValue(value);
}
else if ("DirectoryIcon".equals(sName)) {
sDirectoryIcon = getValue(value);
}
else if ("DocumentIcon".equals(sName)) {
sDocumentIcon = getValue(value);
}
else if ("TemplateURL".equals(sName)) {
sTemplateURL = getValue(value);
}
else if ("WriterFilterName".equals(sName)) {
sWriterFilterName = getValue(value);
}
else if ("WriterFilterData".equals(sName)) {
writerFilterData = lArguments[i].Value;
}
else if ("CalcFilterName".equals(sName)) {
sCalcFilterName = getValue(value);
}
else if ("CalcFilterData".equals(sName)) {
calcFilterData = lArguments[i].Value;
}
}
// Set arguments on batch converter
batchConverter.getConfig().setOption("uplink", sUplink);
batchConverter.getConfig().setOption("directory_icon", sDirectoryIcon);
batchConverter.getConfig().setOption("document_icon", sDocumentIcon);
if (sTemplateURL!=null) {
try {
XInputStream xis = sfa2.openFileRead(sTemplateURL);
XInputStreamToInputStreamAdapter isa = new XInputStreamToInputStreamAdapter(xis);
batchConverter.readTemplate(isa);
}
catch (IOException e) {
// The batchconverter failed to read the template
}
catch (CommandAbortedException e) {
// The sfa could not execute the command
}
catch (com.sun.star.uno.Exception e) {
// Unspecified uno exception
}
}
// Convert the directory
handler.startConversion();
convertDirectory(sSourceURL, sTargetURL, getName(sSourceURL));
handler.endConversion();
}
// Convert a directory - return true if not cancelled
private boolean convertDirectory(String sSourceURL, String sTargetURL, String sHeading) {
handler.startDirectory(sSourceURL);
// Step 1: Get the directory
String[] contents;
try {
contents = sfa2.getFolderContents(sSourceURL, true);
}
catch (CommandAbortedException e) {
handler.endDirectory(sSourceURL,false);
return true;
}
catch (com.sun.star.uno.Exception e) {
handler.endDirectory(sSourceURL,false);
return true;
}
int nLen = contents.length;
IndexPageEntry[] entries = new IndexPageEntry[nLen];
// Step 2: Traverse subdirectories, if allowed
if (bRecurse) {
String sUplink = batchConverter.getConfig().getOption("uplink");
for (int i=0; i<nLen; i++) {
boolean bIsDirectory = false;
try {
bIsDirectory = sfa2.isFolder(contents[i]);
}
catch (CommandAbortedException e) {
// Considered non critical, ignore
}
catch (com.sun.star.uno.Exception e) {
// Considered non critical, ignore
}
if (bIsDirectory) {
batchConverter.getConfig().setOption("uplink","../index.html");
String sNewTargetURL = ensureSlash(sTargetURL) + getName(contents[i]);
String sNewHeading = sHeading + " - " + decodeURL(getName(contents[i]));
boolean bResult = convertDirectory(contents[i],sNewTargetURL,sNewHeading);
batchConverter.getConfig().setOption("uplink", sUplink);
if (!bResult) { return false; }
// Create entry for this subdirectory
IndexPageEntry entry = new IndexPageEntry(ensureSlash(sNewTargetURL)+"index.html",true);
entry.setDisplayName(decodeURL(getName(contents[i])));
entries[i]=entry;
}
}
}
// Step 3: Traverse documents
for (int i=0; i<nLen; i++) {
boolean bIsFile = false;
try {
bIsFile = sfa2.exists(contents[i]) && !sfa2.isFolder(contents[i]);
}
catch (CommandAbortedException e) {
// Considered non critical, ignore
}
catch (com.sun.star.uno.Exception e) {
// Considered non critical, ignore
}
if (bIsFile) {
IndexPageEntry entry = convertFile(contents[i],sTargetURL);
if (entry!=null) { entries[i]=entry; }
if (handler.cancel()) { return false; }
}
}
// Step 4: Create and write out the index file
OutputFile indexFile = batchConverter.createIndexFile(sHeading, entries);
try {
if (!sfa2.exists(sTargetURL)) { sfa2.createFolder(sTargetURL); }
}
catch (CommandAbortedException e) {
handler.endDirectory(sSourceURL,false);
return true;
}
catch (com.sun.star.uno.Exception e) {
handler.endDirectory(sSourceURL,false);
return true;
}
try {
// writeFile demands an InputStream, so we need a pipe
Object xPipeObj=xComponentContext.getServiceManager().createInstanceWithContext(
"com.sun.star.io.Pipe",xComponentContext);
XInputStream xInStream
= (XInputStream) UnoRuntime.queryInterface(XInputStream.class, xPipeObj );
XOutputStream xOutStream
= (XOutputStream) UnoRuntime.queryInterface(XOutputStream.class, xPipeObj );
OutputStream outStream = new XOutputStreamToOutputStreamAdapter(xOutStream);
// Feed the pipe with content...
indexFile.write(outStream);
outStream.flush();
outStream.close();
xOutStream.closeOutput();
// ...and then write the content to the url
sfa2.writeFile(ensureSlash(sTargetURL)+"index.html",xInStream);
}
catch (IOException e) {
handler.endDirectory(sSourceURL,false);
return true;
}
catch (NotConnectedException e) {
handler.endDirectory(sSourceURL,false);
return true;
}
catch (com.sun.star.uno.Exception e) {
handler.endDirectory(sSourceURL,false);
return true;
}
handler.endDirectory(sSourceURL, true);
return !handler.cancel();
}
private IndexPageEntry convertFile(String sSourceFileURL, String sTargetURL) {
handler.startFile(sSourceFileURL);
String sTargetFileURL = ensureSlash(sTargetURL) + getBaseName(sSourceFileURL) + ".html";
IndexPageEntry entry = new IndexPageEntry(getName(sTargetFileURL),false);
entry.setDisplayName(decodeURL(getBaseName(sTargetFileURL)));
// Load component
XComponent xDocument;
try {
Object desktop = xComponentContext.getServiceManager().createInstanceWithContext(
"com.sun.star.frame.Desktop", xComponentContext);
XComponentLoader xComponentLoader = (XComponentLoader)
UnoRuntime.queryInterface(XComponentLoader.class, desktop);
PropertyValue[] fileProps = new PropertyValue[1];
fileProps[0] = new PropertyValue();
fileProps[0].Name = "Hidden";
fileProps[0].Value = new Boolean(true);
xDocument = xComponentLoader.loadComponentFromURL(sSourceFileURL, "_blank", 0, fileProps);
}
catch (com.sun.star.io.IOException e) {
handler.endFile(sSourceFileURL,false);
return null;
}
catch (com.sun.star.uno.Exception e) {
handler.endFile(sSourceFileURL,false);
return null;
}
// Get the title and the description of the document
XDocumentInfoSupplier docInfo = (XDocumentInfoSupplier) UnoRuntime.queryInterface(XDocumentInfoSupplier.class, xDocument);
XPropertySet infoProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, docInfo.getDocumentInfo());
if (infoProps!=null) {
try {
Object loadedTitle = infoProps.getPropertyValue("Title");
if (AnyConverter.isString(loadedTitle)) {
String sLoadedTitle = AnyConverter.toString(loadedTitle);
if (bUseTitle && sLoadedTitle.length()>0) {
entry.setDisplayName(sLoadedTitle);
}
}
Object loadedDescription = infoProps.getPropertyValue("Description");
if (AnyConverter.isString(loadedDescription)) {
String sLoadedDescription = AnyConverter.toString(loadedDescription);
if (bUseDescription && sLoadedDescription.length()>0) {
entry.setDescription(sLoadedDescription);
}
}
}
catch (UnknownPropertyException e) {
}
catch (WrappedTargetException e) {
}
catch (com.sun.star.lang.IllegalArgumentException e) {
}
}
// Determine the type of the component
boolean bText = false;
boolean bSpreadsheet = false;
if (UnoRuntime.queryInterface(XTextDocument.class, xDocument)!=null) { bText=true; }
else if (UnoRuntime.queryInterface(XSpreadsheetDocument.class, xDocument)!=null) { bSpreadsheet=true; }
if (!bText && !bSpreadsheet) {
handler.endFile(sSourceFileURL,false);
xDocument.dispose();
return null;
}
// Convert using requested filter
boolean bHtmlSuccess = true;
PropertyHelper exportProps = new PropertyHelper();
exportProps.put("FilterName", bText ? sWriterFilterName : sCalcFilterName);
exportProps.put("Overwrite", new Boolean(true));
if (bText && writerFilterData!=null) { exportProps.put("FilterData", writerFilterData); }
if (bSpreadsheet && calcFilterData!=null) { exportProps.put("FilterData", calcFilterData); }
try {
XStorable xStore = (XStorable) UnoRuntime.queryInterface (XStorable.class, xDocument);
xStore.storeToURL (sTargetFileURL, exportProps.toArray());
}
catch (com.sun.star.io.IOException e) {
// Failed to convert; continue anyway, but don't link to the file name
entry.setFile(null);
bHtmlSuccess = false;
}
// Convet to pdf if requested
boolean bPdfSuccess = true;
if (bIncludePdf) {
PropertyValue[] pdfProps = new PropertyValue[2];
pdfProps[0] = new PropertyValue();
pdfProps[0].Name = "FilterName";
pdfProps[0].Value = bText ? "writer_pdf_Export" : "calc_pdf_Export";
pdfProps[1] = new PropertyValue();
pdfProps[1].Name = "Overwrite";
pdfProps[1].Value = new Boolean(true);
String sPdfFileURL = ensureSlash(sTargetURL) + getBaseName(sSourceFileURL) + ".pdf";
try {
XStorable xStore = (XStorable) UnoRuntime.queryInterface (XStorable.class, xDocument);
xStore.storeToURL (sPdfFileURL, pdfProps);
entry.setPdfFile(sPdfFileURL);
}
catch (com.sun.star.io.IOException e) {
// Not critical, continue without pdf
bPdfSuccess = false;
}
}
xDocument.dispose();
// Include original document if required
if (bIncludeOriginal) {
// TODO
}
// Report a failure to the user if either of the exports failed
handler.endFile(sSourceFileURL,bHtmlSuccess && bPdfSuccess);
// But return the index entry even if only one succeded
if (bHtmlSuccess || bPdfSuccess) { return entry; }
else { return null; }
}
private String getName(String sURL) {
int n = sURL.lastIndexOf("/");
return n>-1 ? sURL.substring(n+1) : sURL;
}
private String getBaseName(String sURL) {
String sName = getName(sURL);
int n = sName.lastIndexOf(".");
return n>-1 ? sName.substring(0,n) : sName;
}
private String ensureSlash(String sURL) {
return sURL.endsWith("/") ? sURL : sURL+"/";
}
private String decodeURL(String sURL) {
try {
return new URI(sURL).getPath();
}
catch (URISyntaxException e) {
return sURL;
}
}
// Implement methods from interface XTypeProvider
public com.sun.star.uno.Type[] getTypes() {
Type[] typeReturn = {};
try {
typeReturn = new Type[] {
new Type( XBatchConverter.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 );
}
}

View file

@ -0,0 +1,72 @@
/************************************************************************
*
* BatchHandlerAdapter.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-05)
*
*/
package org.openoffice.da.comp.writer2xhtml;
import writer2latex.api.BatchHandler;
import org.openoffice.da.writer2xhtml.XBatchHandler;
/** The uno interface provides an XBatchHandler implementation, the java
* interface requires a BatchHandler implementation. This simple class
* implements the latter using an instance of the former.
*/
public class BatchHandlerAdapter implements BatchHandler {
private XBatchHandler unoHandler;
public BatchHandlerAdapter(XBatchHandler unoHandler) {
this.unoHandler = unoHandler;
}
public void startConversion() {
unoHandler.startConversion();
}
public void endConversion() {
unoHandler.endConversion();
}
public void startDirectory(String sName) {
unoHandler.startDirectory(sName);
}
public void endDirectory(String sName, boolean bSuccess) {
unoHandler.endDirectory(sName, bSuccess);
}
public void startFile(String sName) {
unoHandler.startFile(sName);
}
public void endFile(String sName, boolean bSuccess) {
unoHandler.endFile(sName, bSuccess);
}
public boolean cancel() {
return unoHandler.cancel();
}
}

View file

@ -0,0 +1,56 @@
/************************************************************************
*
* W2XExportFilter.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.writer2xhtml;
import com.sun.star.uno.XComponentContext;
import org.openoffice.da.comp.w2lcommon.filter.ExportFilterBase;
/** This class implements the xhtml export filter component
*/
public class W2XExportFilter extends ExportFilterBase {
/** Service name for the component */
public static final String __serviceName = "org.openoffice.da.comp.writer2xhtml.W2XExportFilter";
/** Implementation name for the component */
public static final String __implementationName = "org.openoffice.da.comp.writer2xhtml.W2XExportFilter";
/** Filter name to include in error messages */
public static final String __displayName = "Writer2xhtml";
public W2XExportFilter(XComponentContext xComponentContext1) {
super(xComponentContext1);
xMSF = W2XRegistration.xMultiServiceFactory;
}
}

View file

@ -0,0 +1,119 @@
/************************************************************************
*
* W2XRegistration.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-04)
*
*/
package org.openoffice.da.comp.writer2xhtml;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.registry.XRegistryKey;
import com.sun.star.comp.loader.FactoryHelper;
/** This class provides a static method to instantiate our uno components
* on demand (__getServiceFactory()), and a static method to give
* information about the components (__writeRegistryServiceInfo()).
* Furthermore, it saves the XMultiServiceFactory provided to the
* __getServiceFactory method for future reference by the componentes.
*/
public class W2XRegistration {
public static XMultiServiceFactory xMultiServiceFactory;
/**
* Returns a factory for creating the service.
* This method is called by the <code>JavaLoader</code>
*
* @return returns a <code>XSingleServiceFactory</code> 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 <code>JavaLoader</code>
* <p>
* @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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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"));
}
}

View file

@ -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);
}
}

View file

@ -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;
/**
* <p>Commandline utility to convert an OpenOffice.org Writer XML file into XHTML/LaTeX/BibTeX</p>
* <p>The utility is invoked with the following command line:</p>
* <pre>java -jar writer2latex.jar [options] source [target]</pre>
* <p>Where the available options are
* <ul>
* <li><code>-latex</code>, <code>-bibtex</code>, <code>-xhtml</code>,
<code>-xhtml+mathml</code>, <code>-xhtml+mathml+xsl</code>
* <li><code>-recurse</code>
* <li><code>-ultraclean</code>, <code>-clean</code>, <code>-pdfscreen</code>,
* <code>-pdfprint</code>, <code>-cleanxhtml</code>
* <li><code>-config[=]filename</code>
* <li><code>-template[=]filename</code>
* <li><code>-option[=]value</code>
* </ul>
* <p>where <code>option</code> can be any simple option known to Writer2LaTeX
* (see documentation for the configuration file).</p>
*/
public final class Application {
/* Based on command-line parameters. */
private String sTargetMIME = MIMETypes.LATEX;
private boolean bRecurse = false;
private Vector configFileNames = new Vector();
private String sTemplateFileName = null;
private Hashtable options = new Hashtable();
private String sSource = null;
private String sTarget = null;
/**
* Main method
*
* @param args The argument passed on the command line.
*/
public static final void main (String[] args){
try {
Application app = new Application();
app.parseCommandLine(args);
app.doConversion();
} catch (IllegalArgumentException ex) {
String msg = ex.getMessage();
showUsage(msg);
}
}
// Convert the directory or file
private void doConversion() {
// Step 1: Say hello...
String sOutputFormat;
if (MIMETypes.LATEX.equals(sTargetMIME)) { sOutputFormat = "LaTeX"; }
else if (MIMETypes.BIBTEX.equals(sTargetMIME)) { sOutputFormat = "BibTeX"; }
else { sOutputFormat = "xhtml"; }
System.out.println();
System.out.println("This is Writer2" + sOutputFormat +
", Version " + ConverterFactory.getVersion() +
" (" + ConverterFactory.getDate() + ")");
System.out.println();
System.out.println("Starting conversion...");
// Step 2: Examine source
File source = new File(sSource);
if (!source.exists()) {
System.out.println("I'm sorry, I can't find "+sSource);
System.exit(1);
}
if (!source.canRead()) {
System.out.println("I'm sorry, I can't read "+sSource);
System.exit(1);
}
boolean bBatch = source.isDirectory();
// Step 3: Examine target
File target;
if (bBatch) {
if (sTarget==null) {
target=source;
}
else {
target = new File(sTarget);
}
}
else {
if (sTarget==null) {
target = new File(source.getParent(),Misc.removeExtension(source.getName()));
}
else {
target = new File(sTarget);
if (sTarget.endsWith(File.separator)) {
target = new File(target,Misc.removeExtension(source.getName()));
}
}
}
// Step 4: Create converters
Converter converter = ConverterFactory.createConverter(sTargetMIME);
if (converter==null) {
System.out.println("Failed to create converter for "+sTargetMIME);
System.exit(1);
}
BatchConverter batchCv = null;
if (bBatch) {
batchCv = ConverterFactory.createBatchConverter(MIMETypes.XHTML);
if (batchCv==null) {
System.out.println("Failed to create batch converter");
System.exit(1);
}
batchCv.setConverter(converter);
}
// Step 5: Read template
if (sTemplateFileName!=null) {
try {
System.out.println("Reading template "+sTemplateFileName);
byte [] templateBytes = Misc.inputStreamToByteArray(new FileInputStream(sTemplateFileName));
converter.readTemplate(new ByteArrayInputStream(templateBytes));
if (batchCv!=null) {
// Currently we use the same template for the directory and the files
batchCv.readTemplate(new ByteArrayInputStream(templateBytes));
}
}
catch (FileNotFoundException e) {
System.out.println("--> This file does not exist!");
System.out.println(" "+e.getMessage());
}
catch (IOException e) {
System.out.println("--> Failed to read the template file!");
System.out.println(" "+e.getMessage());
}
}
// Step 6: Read config
for (int i=0; i<configFileNames.size(); i++) {
String sConfigFileName = (String) configFileNames.get(i);
if (sConfigFileName.startsWith("*")) {
sConfigFileName = sConfigFileName.substring(1);
System.out.println("Reading default configuration "+sConfigFileName);
try {
converter.getConfig().readDefaultConfig(sConfigFileName);
}
catch (IllegalArgumentException e) {
System.err.println("--> This configuration is unknown!");
System.out.println(" "+e.getMessage());
}
}
else {
System.out.println("Reading configuration file "+sConfigFileName);
try {
byte[] configBytes = Misc.inputStreamToByteArray(new FileInputStream(sConfigFileName));
converter.getConfig().read(new ByteArrayInputStream(configBytes));
if (bBatch) {
// Currently we use the same configuration for the directory and the files
batchCv.getConfig().read(new ByteArrayInputStream(configBytes));
}
}
catch (IOException e) {
System.err.println("--> Failed to read the configuration!");
System.out.println(" "+e.getMessage());
}
}
}
// Step 7: Set options from command line
Enumeration keys = options.keys();
while (keys.hasMoreElements()) {
String sKey = (String) keys.nextElement();
String sValue = (String) options.get(sKey);
converter.getConfig().setOption(sKey,sValue);
if (batchCv!=null) {
batchCv.getConfig().setOption(sKey,sValue);
}
}
// Step 8: Perform conversion
if (bBatch) {
batchCv.convert(source,target,bRecurse, new BatchHandlerImpl());
}
else {
System.out.println("Converting "+source.getPath());
ConverterResult dataOut = null;
try {
dataOut = converter.convert(source,target.getName());
}
catch (FileNotFoundException e) {
System.out.println("--> The file "+source.getPath()+" does not exist!");
System.out.println(" "+e.getMessage());
System.exit(1);
}
catch (IOException e) {
System.out.println("--> Failed to convert the file "+source.getPath()+"!");
System.out.println(" "+e.getMessage());
System.exit(1);
}
// TODO: Should do some further checking on the feasability of writing
// the directory and the files.
File targetDir = target.getParentFile();
if (targetDir!=null && !targetDir.exists()) { targetDir.mkdirs(); }
try {
dataOut.write(targetDir);
}
catch (IOException e) {
System.out.println("--> Error writing out file!");
System.out.println(" "+e.getMessage());
System.exit(1);
}
}
// Step 9: Say goodbye!
System.out.println("Done!");
}
/**
* Display usage.
*/
private static void showUsage(String msg) {
System.out.println();
System.out.println("This is Writer2LaTeX, Version " + ConverterFactory.getVersion()
+ " (" + ConverterFactory.getDate() + ")");
System.out.println();
if (msg != null) System.out.println(msg);
System.out.println();
System.out.println("Usage:");
System.out.println(" java -jar <path>/writer2latex.jar <options> <source file/directory> [<target file/directory>]");
System.out.println("where the available options are:");
System.out.println(" -latex");
System.out.println(" -bibtex");
System.out.println(" -xhtml");
System.out.println(" -xhtml+mathml");
System.out.println(" -xhtml+mathml+xsl");
System.out.println(" -recurse");
System.out.println(" -template[=]<template file>");
System.out.println(" -ultraclean");
System.out.println(" -clean");
System.out.println(" -pdfprint");
System.out.println(" -pdfscreen");
System.out.println(" -cleanxhtml");
System.out.println(" -config[=]<configuration file>");
System.out.println(" -<configuration option>[=]<value>");
System.out.println("See the documentation for the available configuration options");
}
/**
* Parse command-line arguments.
*
* @param args Array of command line arguments.
*
* @throws IllegalArgumentException If an argument is invalid.
*/
private void parseCommandLine(String sArgs[])
throws IllegalArgumentException {
int i = 0;
while (i<sArgs.length) {
String sArg = getArg(i++,sArgs);
if (sArg.startsWith("-")) { // found an option
if ("-latex".equals(sArg)) { sTargetMIME = MIMETypes.LATEX; }
else if ("-bibtex".equals(sArg)) { sTargetMIME = MIMETypes.BIBTEX; }
else if ("-xhtml".equals(sArg)) { sTargetMIME = MIMETypes.XHTML; }
else if ("-xhtml+mathml".equals(sArg)) { sTargetMIME = MIMETypes.XHTML_MATHML; }
else if ("-xhtml+mathml+xsl".equals(sArg)) { sTargetMIME = MIMETypes.XHTML_MATHML_XSL; }
else if ("-recurse".equals(sArg)) { bRecurse = true; }
else if ("-ultraclean".equals(sArg)) { configFileNames.add("*ultraclean.xml"); }
else if ("-clean".equals(sArg)) { configFileNames.add("*clean.xml"); }
else if ("-pdfprint".equals(sArg)) { configFileNames.add("*pdfprint.xml"); }
else if ("-pdfscreen".equals(sArg)) { configFileNames.add("*pdfscreen.xml"); }
else if ("-cleanxhtml".equals(sArg)) { configFileNames.add("*cleanxhtml.xml"); }
else { // option with argument
int j=sArg.indexOf("=");
String sArg2;
if (j>-1) { // argument is separated by =
sArg2 = sArg.substring(j+1);
sArg = sArg.substring(0,j);
}
else { // argument is separated by space
sArg2 = getArg(i++,sArgs);
}
if ("-config".equals(sArg)) { configFileNames.add(sArg2); }
else if ("-template".equals(sArg)) { sTemplateFileName = sArg2; }
else { // configuration option
options.put(sArg.substring(1),sArg2);
}
}
}
else { // not an option, so this must be the source
sSource = sArg;
// Possibly followed by the target
if (i<sArgs.length) {
String sArgument = getArg(i++,sArgs);
if (sArgument.length()>0) { sTarget = sArgument; }
}
// Skip any trailing empty arguments and signal an error if there's more
while (i<sArgs.length) {
String sArgument = getArg(i++,sArgs);
if (sArgument.length()>0) {
throw new IllegalArgumentException("I didn't expect "+sArgument+"?");
}
}
}
}
if (sSource==null) {
throw new IllegalArgumentException("Please specify a source document/directory!");
}
// Parsing of command line ended successfully!
}
/**
* Extract the next argument from the array, while checking to see
* that the array size is not exceeded. Throw a friendly error
* message in case the arg is missing.
*
* @param i Argument index.
* @param args Array of command line arguments.
*
* @return The argument with the specified index.
*
* @throws IllegalArgumentException If an argument is invalid.
*/
private String getArg(int i, String args[])
throws IllegalArgumentException {
if (i < args.length) {
return args[i];
}
else throw new
IllegalArgumentException("I'm sorry, the commandline ended abnormally");
}
}

View file

@ -0,0 +1,94 @@
/************************************************************************
*
* BatchHandlerImpl.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-03)
*
*/
package writer2latex;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import writer2latex.api.BatchHandler;
/** This class implements a <code>BatchHandler</code> for command line usage
*/
public class BatchHandlerImpl implements BatchHandler {
private int nIndent = 0;
private void writeMessage(String sMsg) {
for (int i=0; i<nIndent; i++) {
System.out.print(" ");
}
System.out.println(sMsg);
}
public void startConversion() {
System.out.println("Press Enter to cancel the conversion");
}
public void endConversion() {
// No message
}
public void startDirectory(String sName) {
writeMessage("Converting directory "+sName);
nIndent++;
}
public void endDirectory(String sName, boolean bSuccess) {
nIndent--;
if (!bSuccess) {
writeMessage("--> Conversion of the directory "+sName+" failed!");
}
}
public void startFile(String sName) {
writeMessage("Converting file "+sName);
nIndent++;
}
public void endFile(String sName, boolean bSuccess) {
nIndent--;
if (!bSuccess) {
writeMessage("--> Conversion of the file "+sName+" failed!");
}
}
public boolean cancel() {
try {
if (System.in.available()>0) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
in.readLine();
System.out.print("Do you want to cancel the conversion (y/n)? ");
String s = in.readLine();
if (s!= null && s.toLowerCase().startsWith("y")) { return true; }
}
}
catch (IOException e) {
}
return false;
}
}

View file

@ -0,0 +1,96 @@
/************************************************************************
*
* 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-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;
/** This is an interface for a converter, which offers conversion of
* all OpenDocument (or OpenOffice.org 1.x) documents in a directory
* (and optionally subdirectories), creating index pages in a specific format.
* Instances of this interface are created using the
* {@link ConverterFactory}
*/
public interface BatchConverter {
/** Get the configuration interface for this batch converter
*
* @return the configuration
*/
public Config getConfig();
/** Define a <code>Converter</code> implementation to use for
* conversion of the individual documents.
* If no converter is given, the <code>convert</code> method cannot
* convert documents (but can still create index pages).
*
* @param converter the <code>Converter</code> 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 <code>BatchConverter</code>
* implementation.
*
* @param is an <code>InputStream</code> 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 <code>BatchConverter</code>
* 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 <code>IndexPageEntry</code> 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 <code>Converter</code> (if none is given,
* all files will be ignored).
* This method fails silently if you haven't set a converter.
*
* @param source a <code>File</code> representing the directory to convert
* @param target a <code>File</code> representing the directory to contain
* the converted documents
* @param bRecurse determines wether or not to recurse into subdirectories
* @param handler a </code>BatchHandler</code>
*/
public void convert(File source, File target, boolean bRecurse, BatchHandler handler);
}

View file

@ -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();
}

View file

@ -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 <code>InputStream</code> 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 <code>File</code> 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 <code>OutputStream</code> 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 <code>File</code> 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 <code>null</code> if the option does
* not exist or the given name is null
*/
public String getOption(String sName);
}

View file

@ -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
* <code>ConverterFactory</code>
*/
public interface Converter {
/** Get the interface for the configuration of this converter
*
* @return the configuration
*/
public Config getConfig();
/** Define a <code>GraphicConverter</code> 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 <code>GraphicConverter</code> 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 <code>Converter</code>
* implementation.
*
* @param is an <code>InputStream</code> 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 <code>Converter</code>
* 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 <code>InputStream</code> 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 <code>ConverterResult</code> 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 <code>File</code> 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 <code>ConverterResult</code> 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;
}

View file

@ -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; }
/** <p>Create a <code>Converter</code> implementation which supports
* conversion into the specified MIME type.</p>
* <p>Currently supported MIME types are:</p>
* <ul>
* <li><code>application/x-latex</code> for LaTeX format</li>
* <li><code>application/x-bibtex</code> for BibTeX format</li>
* <li><code>text/html</code> for XHTML 1.0 strict format</li>
* <li><code>application/xhtml+xml</code> for XHTML+MathML</li>
* <li><code>application/xml</code> for XHTML+MathML using stylesheets from w3c's
* math working group</li>
* </ul>
*
* @param sMIME the MIME type of the target format
* @return the required <code>Converter</code> 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;
}
/** <p>Create a <code>BatchConverter</code> implementation which supports
* conversion into the specified MIME type</p>
* <p>The only currently supported MIME type is <code>text/html</code>
* (XHTML 1.0 strict)</p>
*
* @param sMIME the MIME type of the target format
* @return the required <code>BatchConverter</code> 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 <code>StarMathConverter</code> 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;
}
}
}

View file

@ -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 <code>ConverterResult</code> represent a document, which is the result
* of a conversion performed by a <code>Converter</code>implementation.
*/
public interface ConverterResult {
/** Get the master document
* @return <code>OutputFile</code> the master document
*/
public OutputFile getMasterDocument();
/** Gets an <code>Iterator</code> to access all files in the
* <code>ConverterResult</code>. This <em>includes</em> the master document.
* @return an <code>Iterator</code> of all files
*/
public Iterator iterator();
/** Write all files of the <code>ConverterResult</code> to a directory.
* Subdirectories are created as required by the individual
* <code>OutputFile</code>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;
}

View file

@ -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);
}

View file

@ -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 <code>IndexPageEntry</code> 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;
}
}

View file

@ -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";
}

View file

@ -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 <code>OutputFile</code> represent a single file in a
* {@link ConverterResult}, which is output from a {@link Converter}
* implementation.
*/
public interface OutputFile {
/** Writes the <code>OutputFile</code> to an <code>OutputStream</code>.
*
* @param os <code>OutputStream</code> 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 <code>OutputFile</code>. This includes
* the file extension and may also include a relative path, always using
* / as separator.
*
* @return the file name of this <code>OutputFile</code>
*/
public String getFileName();
}

View file

@ -0,0 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The package writer2latex.api</title>
</head>
<body>
<p>This package contains the api for using Writer2LaTeX.</p>
<p>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.
</body>
</html>

View file

@ -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();
}

View file

@ -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 <code>writer2latex.api.BatchConverter</code>.
* 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; i<nLen; i++) {
if (contents[i].isDirectory()) {
getConfig().setOption("uplink","../"+getIndexFileName());
File newOutdir = new File(outdir,contents[i].getName());
String sNewHeading = sHeading + " - " + contents[i].getName();
boolean bResult = convertDirectory(contents[i],newOutdir,bRecurse,sNewHeading,handler);
getConfig().setOption("uplink", sUplink);
if (!bResult) { return false; }
// Create entry for this subdirectory
IndexPageEntry entry = new IndexPageEntry(Misc.makeHref(contents[i].getName()+"/"+getIndexFileName()),true);
entry.setDisplayName(contents[i].getName());
entries[i]=entry;
}
}
}
// Step 3: Traverse documents, if we have a converter
if (converter!=null) {
String sUplink = getConfig().getOption("uplink");
for (int i=0; i<nLen; i++) {
if (contents[i].isFile()) {
getConfig().setOption("uplink",getIndexFileName());
String sLinkFile = convertFile(contents[i],outdir,handler);
getConfig().setOption("uplink", sUplink);
if (sLinkFile!=null) {
// Create entry for this file
IndexPageEntry entry = new IndexPageEntry(Misc.makeHref(sLinkFile),false);
entry.setDisplayName(Misc.removeExtension(sLinkFile));
entries[i]=entry;
if (handler.cancel()) { return false; }
}
}
}
}
// Step 4: Create and write out the index file
OutputFile indexFile = createIndexFile(sHeading, entries);
if (!outdir.exists()) { outdir.mkdirs(); }
boolean bSuccess = true;
File outfile = new File(outdir,indexFile.getFileName());
try {
FileOutputStream fos = new FileOutputStream(outfile);
indexFile.write(fos);
fos.flush();
fos.close();
} catch (Exception writeExcept) {
bSuccess = false;
}
handler.endDirectory(indir.getPath(), bSuccess);
return !handler.cancel();
}
// Convert a single file, returning the name of the master file
// Returns null if conversion fails
private String convertFile(File infile, File outdir, BatchHandler handler) {
handler.startFile(infile.getPath());
// Currently we discriminate based on file extension
if (!(infile.getName().endsWith(".odt") || infile.getName().endsWith(".ods") || infile.getName().endsWith(".odp"))) {
handler.endFile(infile.getPath(),false);
return null;
}
// Do conversion
ConverterResult dataOut = null;
try {
// The target file name is always the same as the source
dataOut = converter.convert(infile,Misc.removeExtension(infile.getName()));
}
catch (FileNotFoundException e) {
handler.endFile(infile.getPath(),false);
return null;
}
catch (IOException e) {
handler.endFile(infile.getPath(),false);
return null;
}
// Write out files
if (!outdir.exists()) { outdir.mkdirs(); }
try {
dataOut.write(outdir);
}
catch (IOException e) {
handler.endFile(infile.getPath(),false);
return null;
}
handler.endFile(infile.getPath(),true);
return dataOut.getMasterDocument().getFileName();
}
}

View file

@ -0,0 +1,44 @@
/************************************************************************
*
* BooleanOption.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.base;
// A BooleanOption interprets the values as booleans
public class BooleanOption extends Option {
private boolean bValue;
public boolean getValue() { return bValue; }
public void setString(String sValue) {
super.setString(sValue);
bValue = "true".equals(sValue);
}
public BooleanOption(String sName, String sDefaultValue) {
super(sName,sDefaultValue);
}
}

View file

@ -0,0 +1,170 @@
/************************************************************************
*
* ConfigBase.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.base;
/** Base implementation of writer2latex.api.Config
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.DOMImplementation;
import writer2latex.xmerge.NewDOMDocument;
public abstract class ConfigBase implements writer2latex.api.Config {
protected abstract int getOptionCount();
protected abstract String getDefaultConfigPath();
protected Option[] options;
public ConfigBase() {
options = new Option[getOptionCount()];
}
public void setOption(String sName,String sValue) {
if (sName!=null && sValue!=null) {
for (int j=0; j<getOptionCount(); j++) {
if (sName.equals(options[j].getName())) {
options[j].setString(sValue);
break;
}
}
}
}
public String getOption(String sName) {
if (sName!=null) {
for (int j=0; j<getOptionCount(); j++) {
if (sName.equals(options[j].getName())) {
return options[j].getString();
}
}
}
return null;
}
public void readDefaultConfig(String sName) throws IllegalArgumentException {
InputStream is = this.getClass().getResourceAsStream(getDefaultConfigPath()+sName);
if (is==null) {
throw new IllegalArgumentException("The internal configuration '"+sName+ "' does not exist");
}
try {
read(is);
}
catch (IOException e) {
// This would imply a bug in the configuration file!
throw new IllegalArgumentException("The internal configuration '"+sName+ "' is invalid");
}
}
/** <p>Read configuration from a specified input stream</p>
* @param is the input stream to read the configuration from
*/
public void read(InputStream is) throws IOException {
NewDOMDocument doc = new NewDOMDocument("config",".xml");
doc.read(is); // may throw an IOException
Document dom = doc.getContentDOM();
if (dom==null) {
throw new IOException("Failed to parse configuration");
}
Node root = dom.getDocumentElement();
Node child = root.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
Element elm = (Element)child;
if (elm.getTagName().equals("option")) {
String sName = elm.getAttribute("name");
String sValue = elm.getAttribute("value");
if (sName!="") { setOption(sName,sValue); }
}
else {
readInner(elm);
}
}
child = child.getNextSibling();
}
}
public void read(File file) throws IOException {
read(new FileInputStream(file));
}
/** Read configuration information from an xml element.
* The subclass must define this to read richer configuration data
*/
protected abstract void readInner(Element elm);
public void write(OutputStream os) throws IOException {
NewDOMDocument doc = new NewDOMDocument("config",".xml");
Document dom = null;
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
DOMImplementation domImpl = builder.getDOMImplementation();
dom = domImpl.createDocument("","config",null);
}
catch (Throwable t) {
t.printStackTrace();
}
Element rootElement = dom.getDocumentElement();
for (int i=0; i<getOptionCount(); i++) {
Element optionNode = dom.createElement("option");
optionNode.setAttribute("name",options[i].getName());
optionNode.setAttribute("value",options[i].getString());
rootElement.appendChild(optionNode);
}
writeInner(dom);
doc.setContentDOM(dom);
doc.write(os); // may throw an IOException
}
public void write(File file) throws IOException {
write(new FileOutputStream(file));
}
/** Write configuration information to an xml document.
* The subclass must define this to write richer configuration data
*/
protected abstract void writeInner(Document dom);
}

View file

@ -0,0 +1,117 @@
/************************************************************************
*
* ConverterBase.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.base;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import writer2latex.api.GraphicConverter;
import writer2latex.api.Converter;
import writer2latex.api.ConverterResult;
import writer2latex.api.OutputFile;
import writer2latex.office.ImageLoader;
import writer2latex.office.MetaData;
import writer2latex.office.OfficeReader;
import writer2latex.xmerge.EmbeddedObject;
import writer2latex.xmerge.ConvertData;
import writer2latex.xmerge.OfficeDocument;
/**<p>Abstract base implementation of <code>writer2latex.api.Converter</code></p>
*/
public abstract class ConverterBase implements Converter {
// Helper
protected GraphicConverter graphicConverter;
// The source document
protected OfficeDocument odDoc;
protected OfficeReader ofr;
protected MetaData metaData;
protected ImageLoader imageLoader;
// The output file(s)
protected String sTargetFileName;
protected ConvertData convertData;
// Constructor
public ConverterBase() {
graphicConverter = null;
convertData = new ConvertData();
}
// Implement the interface
public void setGraphicConverter(GraphicConverter graphicConverter) {
this.graphicConverter = graphicConverter;
}
// Provide a do noting fallback method
public void readTemplate(InputStream is) throws IOException { }
// Provide a do noting fallback method
public void readTemplate(File file) throws IOException { }
public ConverterResult convert(File source, String sTargetFileName) throws FileNotFoundException,IOException {
return convert(new FileInputStream(source), sTargetFileName);
}
public ConverterResult convert(InputStream is, String sTargetFileName) throws IOException {
// Read document
odDoc = new OfficeDocument("InFile");
odDoc.read(is);
ofr = new OfficeReader(odDoc,false);
metaData = new MetaData(odDoc);
imageLoader = new ImageLoader(odDoc,sTargetFileName,true);
imageLoader.setGraphicConverter(graphicConverter);
// Prepare output
this.sTargetFileName = sTargetFileName;
convertData.reset();
convertInner();
return convertData;
}
// The subclass must provide the implementation
public abstract void convertInner() throws IOException;
public MetaData getMetaData() { return metaData; }
public ImageLoader getImageLoader() { return imageLoader; }
public void addDocument(OutputFile doc) { convertData.addDocument(doc); }
public EmbeddedObject getEmbeddedObject(String sHref) {
return odDoc.getEmbeddedObject(sHref);
}
}

View file

@ -0,0 +1,40 @@
/************************************************************************
*
* IntegerOption.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.base;
// An IntegerOption must always be subclassed (must override setString)
public abstract class IntegerOption extends Option {
protected int nValue;
public int getValue() { return nValue; }
public IntegerOption(String sName, String sDefaultValue) {
super(sName,sDefaultValue);
}
}

View file

@ -0,0 +1,45 @@
/************************************************************************
*
* Option.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.base;
// The mother of all options; reads and writes string values
public class Option {
protected String sValue;
private String sName;
public void setString(String sValue) { this.sValue = sValue; }
public String getString() { return sValue; }
public String getName() { return sName; }
public Option(String sName, String sDefaultValue) {
this.sName = sName;
setString(sDefaultValue);
}
}

View file

@ -0,0 +1,17 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The package writer2latex.base</title>
</head>
<body>
<p>This package contains (abstract) base implementations of some of the
interfaces in writer2latex.api</p>
<p>They are intended to be subclassed by converters into specific formats
e.g. LaTeX, xhtml</p>
</body>
</html>

View file

@ -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;
/**
* <p>Class representing a BibTeX document.</p>
*
*/
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;
/**
* <p>Constructs a new BibTeX Document.</p>
*
* <p>This new document is empty. Bibliographic data must added
* using the <code>put</code> method.</p>
*
* @param sName The name of the <code>BibTeXDocument</code>.
*/
public BibTeXDocument(String sName) {
this.sName = trimDocumentName(sName);
// Use default config (only ascii, no extra font packages)
i18n = new ClassicI18n(new LaTeXConfig());
}
/**
* <p>This method is supposed to read <code>byte</code> data from the InputStream.
* Currently it does nothing, since we don't need it.</p>
*
* @param is InputStream containing a BibTeX data file.
*
* @throws IOException In case of any I/O errors.
*/
public void read(InputStream is) throws IOException {
// Do nothing.
}
/**
* <p>Returns the <code>Document</code> name with no file extension.</p>
*
* @return The <code>Document</code> name with no file extension.
*/
public String getName() {
return sName;
}
/**
* <p>Returns the <code>Document</code> name with file extension.</p>
*
* @return The <code>Document</code> name with file extension.
*/
public String getFileName() {
return new String(sName + FILE_EXTENSION);
}
/**
* <p>Writes out the <code>Document</code> content to the specified
* <code>OutputStream</code>.</p>
*
* <p>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.</p>
*
* @param os <code>OutputStream</code> to write out the
* <code>Document</code> 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; i<BibMark.FIELD_COUNT; i++) {
String sValue = entry.getField(i);
if (sValue!=null) {
if (i==BibMark.AUTHOR || i==BibMark.EDITOR) {
// OOo uses ; to separate authors and editors - BibTeX uses and
sValue = sValue.replaceAll(";" , " and ");
}
osw.write(" ");
osw.write(getFieldName(i).toUpperCase());
osw.write(" = {");
for (int j=0; j<sValue.length(); j++) {
String s = i18n.convert(Character.toString(sValue.charAt(j)),false,"en");
if (s.charAt(0)=='\\') { osw.write("{"); }
osw.write(s);
if (s.charAt(0)=='\\') { osw.write("}"); }
}
osw.write("},\n");
}
}
osw.write("}\n\n");
}
osw.flush();
osw.close();
}
/**
* <p> Return BibTeX name of field </p>
*/
public static final String getFieldName(int nField) {
switch (nField) {
case BibMark.ADDRESS: return "address";
case BibMark.ANNOTE: return "annote";
case BibMark.AUTHOR: return "author";
case BibMark.BOOKTITLE: return "booktitle";
case BibMark.CHAPTER: return "chapter";
// case BibMark.CROSSREF: return "croosref"; // not in OOo
case BibMark.EDITION: return "edition";
case BibMark.EDITOR: return "editor";
case BibMark.HOWPUBLISHED: return "howpublished";
case BibMark.INSTITUTION: return "institution";
case BibMark.JOURNAL: return "journal";
// case BibMark.KEY: return "key"; // not in OOo
case BibMark.MONTH: return "month";
case BibMark.NOTE: return "note";
case BibMark.NUMBER: return "number";
case BibMark.ORGANIZATIONS: return "organization";
case BibMark.PAGES: return "pages";
case BibMark.PUBLISHER: return "publisher";
case BibMark.SCHOOL: return "school";
case BibMark.SERIES: return "series";
case BibMark.TITLE: return "title";
case BibMark.REPORT_TYPE: return "type";
case BibMark.VOLUME: return "volume";
case BibMark.YEAR: return "year";
case BibMark.URL: return "url";
case BibMark.CUSTOM1: return "custom1";
case BibMark.CUSTOM2: return "custom2";
case BibMark.CUSTOM3: return "custom3";
case BibMark.CUSTOM4: return "custom4";
case BibMark.CUSTOM5: return "custom5";
case BibMark.ISBN: return "isbn";
default: return null;
}
}
/*
* <p>Check if this entry exists</p>
*/
public boolean containsKey(String sIdentifier) {
return entries.containsKey(sIdentifier);
}
/*
* <p>Add an entry</p>
*/
public void put(BibMark entry) {
entries.put(entry.getIdentifier(),entry);
exportNames.addName(entry.getIdentifier());
}
/*
* <p>Get export name for an identifier</p>
*/
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;
}
}

View file

@ -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;
/**
* <p>BibTeX export</p>
*
* <p>This class extracts bibliographic information from an OpenDocument text file to a BibTeX data file.</p>
*
*/
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();
}
/**
* <p>Convert the data passed into the <code>InputStream</code>
* into BibTeX format.</p>
*
* @throws IOException If any I/O error occurs.
*/
public void convertInner() throws IOException {
sTargetFileName = Misc.trimDocumentName(sTargetFileName,".bib");
BibTeXDocument bibDoc = new BibTeXDocument(sTargetFileName);
// Collect all text:bibliography-mark elements from the content
Element doc = ofr.getContent();
NodeList list;
list = doc.getElementsByTagName(XMLString.TEXT_BIBLIOGRAPHY_MARK);
int nLen = list.getLength();
for (int i=0; i<nLen; i++) {
String sIdentifier = Misc.getAttribute(list.item(i),XMLString.TEXT_IDENTIFIER);
if (sIdentifier!=null && !bibDoc.containsKey(sIdentifier)) {
bibDoc.put(new BibMark(list.item(i)));
}
}
// Add result
convertData.addDocument(bibDoc);
}
}

View file

@ -0,0 +1,14 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The package writer2latex.bibtex</title>
</head>
<body>
<p>This package contains BibTeX specific code.</p>
<p>It contains a <code>writerlatex.api.Converter</code> implementation for
conversion into BibTeX, as well as code to convert to BibTeX as part of a
conversion into LaTeX.</p>
</body>
</html>

View file

@ -0,0 +1,157 @@
/************************************************************************
*
* BibConverter.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 org.w3c.dom.Element;
import writer2latex.bibtex.BibTeXDocument;
import writer2latex.latex.util.Context;
import writer2latex.office.BibMark;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
/**
* This class handles the bibliography. The result depends on these
* configuration options. The citations will be treated like this:
* <ul>
* <li><code>use_bibtex</code>: If true, citations will be exported as \cite
* commands. If false, citations will be exported as static text</li>
* </ul>
* The bibliography will be treated like this:
* <ul>
* <li><code>use_index</code>: If false, the bibliography will be omitted</li>
* <li><code>use_bibtex</code> true and <code>external_bibtex_files</code>
* empty: The citations will be exported to a BibTeX file, which will be used
* for the bibliography</li>
* <li><code>use_bibtex</code> true and <code>external_bibtex_files</code>
* non-empty: The citations will be not be exported to a BibTeX file, the
* files referred to by the option will be used instead</li>
* <li><code>use_bibtex</code> false: The bibliography will be exported as
* static text.
* <li><code>bibtex_style</code> If BibTeX is used, this style will be applied
* </ul>
*/
public class BibConverter extends ConverterHelper {
private BibTeXDocument bibDoc;
/** Construct a new BibConverter.
* @param config the configuration to use
* @param palette the ConverterPalette to use
*/
public BibConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
}
/** Append declarations needed by the <code>BibConverter</code> 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;
}
}

View file

@ -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;
/**
* <p>This class handles basic block content, including the main text body,
* sections, tables, lists, headings and paragraphs.</p>
*/
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..
}
/** <p> 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.</p>
* <p> (Note: As a rule, all handling of block level elements should add a
* newline to the LaTeX document at the end of the block)</p>
* @param node The element containing the block text
* @param ldp the <code>LaTeXDocumentPortion</code> 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+1<nLen && Misc.isElement(list.item(i+1),XMLString.TABLE_TABLE)) {
// Found table with caption above
palette.getTableCv().handleTable((Element)list.item(++i),child,true,ldp,ic);
}
else {
// Found lonely caption
palette.getTableCv().handleCaption(child,ldp,ic);
}
}
else {
palette.getParCv().handleParagraph(child,ldp,ic,i==nLen-1);
}
}
else if(sTagName.equals(XMLString.TEXT_H)) {
palette.getHeadingCv().handleHeading(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_LIST)) { // oasis
handleList(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_UNORDERED_LIST)) {
handleList(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_ORDERED_LIST)) {
handleList(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TABLE_TABLE)) {
// Next node *could* be a caption
if (i+1<nLen && Misc.isElement(list.item(i+1),XMLString.TEXT_P) &&
ofr.isTableSequenceName(ofr.getSequenceName((Element)list.item(i+1)))) {
// Found table with caption below
palette.getTableCv().handleTable(child,(Element)list.item(++i),false,ldp,oc);
}
else {
// Found table without caption
palette.getTableCv().handleTable(child,null,false,ldp,oc);
}
}
else if (sTagName.equals(XMLString.TABLE_SUB_TABLE)) {
palette.getTableCv().handleTable(child,null,true,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_SECTION)) {
palette.getSectionCv().handleSection(child,ldp,ic);
}
// Draw elements may appear in block context if they are
// anchored to page
else if (sTagName.startsWith("draw:")) {
palette.getDrawCv().handleDrawElement(child,ldp,ic);
}
// Indexes
else if (sTagName.equals(XMLString.TEXT_TABLE_OF_CONTENT)) {
palette.getIndexCv().handleTOC(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_ILLUSTRATION_INDEX)) {
palette.getIndexCv().handleLOF(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_TABLE_INDEX)) {
palette.getIndexCv().handleLOT(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_OBJECT_INDEX)) {
palette.getIndexCv().handleObjectIndex(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_USER_INDEX)) {
palette.getIndexCv().handleUserIndex(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_ALPHABETICAL_INDEX)) {
palette.getIndexCv().handleAlphabeticalIndex(child,ldp,ic);
}
else if (sTagName.equals(XMLString.TEXT_BIBLIOGRAPHY)) {
palette.getBibCv().handleBibliography(child,ldp,ic);
}
// Sequence declarations appear in the main text body (before the actual content)
else if (sTagName.equals(XMLString.TEXT_SEQUENCE_DECLS)) {
palette.getFieldCv().handleSequenceDecls(child);
}
// other tags are ignored
}
}
}
if (!oc.isInTable() && sBlockName!=null) {
// end current block
String sAfter = blockMap.getAfter(sBlockName);
if (sAfter.length()>0) ldp.append(sAfter).nl();
sBlockName = null;
}
palette.getFieldCv().flushReferenceMarks(ldp,ic);
palette.getIndexCv().flushIndexMarks(ldp,ic);
}
/** <p> Process a list (text:ordered-lst or text:unordered-list tag)</p>
* @param node The element containing the list
* @param ldp the <code>LaTeXDocumentPortion</code> 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;
}
}

View file

@ -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;
/**
* <p>This class converts captions (for figures and tables) to LaTeX.</p>
* <p>Packages:
* <ul><li>caption.sty is used implement non-floating captions</li></ul>
* <p>Options:
* <ul><li>use_caption is a boolean option to determine whether or not
* to use caption.sty. If this option is set to false, a simple definition of
* \captionof (borrowed from capt-of.sty) is inserted in the preamble</li></ul>
* <p>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();
}
}
}
/**
* <p> Process content of a text:p tag as a caption body (inluding label)</p>
* @param node The text:p element node containing the caption
* @param ldp The <code>LaTeXDocumentPortion</code> 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 <text:sequence>3</text:sequence>: Caption text
// The first part is the caption label which is autogenerated by LaTeX.
// Before converting, we remove this in 3 steps:
// nStep = 0: Remove all text before the text:sequence
// nStep = 1: Remove all text up to the first alphanumeric character
// after the text:sequence
// nStep = 2: Finished!
private int removeCaptionLabel(Element node, int nStep) {
if (nStep==2) { return 2; }
Node removeMe = null;
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
if (nStep==0 && child.getNodeName().equals(XMLString.TEXT_SEQUENCE)) {
removeMe = child;
seqField = (Element) child; // remember me...
nStep = 1;
}
else if (nStep<2 && !OfficeReader.isDrawElement(child)) {
// draw elements (frames) should not be touched..
nStep = removeCaptionLabel((Element)child,nStep);
}
}
else if (child.getNodeType()==Node.TEXT_NODE) {
if (nStep==0) {
child.setNodeValue("");
}
else if (nStep==1) {
String s = child.getNodeValue();
int n = s.length();
for (int j=0; j<n; j++) {
if (Character.isLetterOrDigit(s.charAt(j))) {
child.setNodeValue(s.substring(j));
nStep = 2;
break;
}
}
}
}
child = child.getNextSibling();
}
if (removeMe!=null) { node.removeChild(removeMe); }
return nStep;
}
}

View file

@ -0,0 +1,507 @@
/************************************************************************
*
* CharStyleConverter.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-03)
*
*/
package writer2latex.latex;
import java.util.Hashtable;
import writer2latex.util.*;
import writer2latex.office.*;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
import writer2latex.latex.util.StyleMap;
/** This class creates LaTeX code from OOo character formatting
Character formatting in OOo includes font, font effects/decorations and color.
In addition it includes color and language/country information, this is however handled
by the classes <code>writer2latex.latex.ColorConverter</code> and
<code>writer2latex.latex.style.I18n</code>
*/
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;
/** <p>Constructs a new <code>CharStyleConverter</code>.</p>
*/
public CharStyleConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
bUseUlem = config.useUlem();
// No character formatting at all:
bIgnoreAll = config.formatting()==LaTeXConfig.IGNORE_ALL;
// No font family or size:
bIgnoreFont = config.formatting()<=LaTeXConfig.IGNORE_MOST;
// No fontsize:
bIgnoreFontsize = config.formatting()<=LaTeXConfig.CONVERT_BASIC;
// No hard fontsize
bIgnoreHardFontsize = config.formatting()<=LaTeXConfig.CONVERT_MOST;
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bNeedUlem) {
pack.append("\\usepackage[normalem]{ulem}").nl();
}
if (bNeedSubscript && !config.getTextAttributeStyleMap().contains("subscript")) {
decl.append("\\newcommand\\textsubscript[1]{\\ensuremath{{}_{\\text{#1}}}}").nl();
}
if (!styleNames.isEmpty()) {
decl.append("% Text styles").nl().append(declarations);
}
}
/** <p>Use a text style in LaTeX.</p>
* @param sName the name of the text style
* @param ba a <code>BeforeAfter</code> 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));
}
/** <p>Apply hard character formatting (no inheritance).</p>
* <p>This is used in sections and {foot|end}notes</p>
* @param style the style to use
* @param ba the <code>BeforeAfter</code> 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(" ",""); }
}
/** <p>Apply all font attributes (family, series, shape, size and color).</p>
* @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 the <code>BeforeAfter</code> 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);
}
/** <p>Reset to normal font, size and color.</p>
* @param ba the <code>BeforeAfter</code> to add LaTeX code to.
*/
public void applyNormalFont(BeforeAfter ba) {
ba.add("\\normalfont\\normalsize","");
palette.getColorCv().applyNormalColor(ba);
}
/** <p>Apply default font attributes (family, series, shape, size and color).</p>
* @param style the OOo style to read attributesfrom
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
/** <p>Apply font effects (position, underline, crossout, change case.</p>
* @param style the OOo style to read attributesfrom
* @param bInherit true if inherited properties should be used
* @param ba the <code>BeforeAfter</code> 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
/** <p>Apply font family.</p>
* @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 the <code>BeforeAfter</code> 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
}
/** <p>Apply font series.</p>
* @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 the <code>BeforeAfter</code> 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+"{","}"); }
}
}
}
}
/** <p>Apply font shape.</p>
* @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 the <code>BeforeAfter</code> 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+"{","}");
}
}
}
}
/** <p>Apply font size.</p>
* @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 the <code>BeforeAfter</code> 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
/** <p>Apply text position.</p>
* @param style the OOo style to read attributesfrom
* @param bInherit true if inherited properties should be used
* @param ba the <code>BeforeAfter</code> 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+"{","}");
}
}
}
/** <p>Apply text underline.</p>
* @param style the OOo style to read attributesfrom
* @param bInherit true if inherited properties should be used
* @param ba the <code>BeforeAfter</code> 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+"{","}"); }
}
/** <p>Apply text crossout.</p>
* @param style the OOo style to read attributesfrom
* @param bInherit true if inherited properties should be used
* @param ba the <code>BeforeAfter</code> 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+"{","}"); }
}
/** <p>Apply change case.</p>
* @param style the OOo style to read attributesfrom
* @param bInherit true if inherited properties should be used
* @param ba the <code>BeforeAfter</code> 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+"{","}"); }
}
/** <p>Convert font declarations to LaTeX.</p>
* <p>It returns a generic LaTeX font family (rm, tt, sf).</p>
* <p>It returns null if the font declaration doesn't exist.</p>
* @param sName the name of the font declaration
* @return <code>String</code> 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;
}
}

View file

@ -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;
/** <p>Constructs a new <code>CharStyleConverter</code>.</p>
*/
public ColorConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
// We use color if requested in the configuration, however ignoring
// all formatting overrides this
bUseColor = config.useColor() && config.formatting()>LaTeXConfig.IGNORE_ALL;
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bUseColor) {
pack.append("\\usepackage{color}").nl();
}
}
public void setNormalColor(String sColor, LaTeXDocumentPortion ldp) {
if (bUseColor && sColor!=null) {
ldp.append("\\renewcommand\\normalcolor{\\color")
.append(color(sColor)).append("}").nl();
}
}
public void applyNormalColor(BeforeAfter ba) {
if (bUseColor) { ba.add("\\normalcolor",""); }
}
/** <p>Apply foreground color.</p>
* @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 the <code>BeforeAfter</code> 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); }
}
}
}
}
/** <p>Apply a specific foreground color.</p>
* @param sColor the rgb color to use
* @param bDecl true if declaration form is required
* @param ba the <code>BeforeAfter</code> 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;
}
}

View file

@ -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;
}
}

View file

@ -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;
/**
* <p>This is an abstract superclass for converter helpers.</p>
*/
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) {
}
}

View file

@ -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;
/**
* <p>This class converts a Writer XML file to a LaTeX file<.</p>
*/
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; i<nCPLen; i++) {
declarations.append( (String) customPreamble.get(i) ).nl();
}
// Set \title, \author and \date (for \maketitle)
createMeta("title",metaData.getTitle(),declarations);
if (config.metadata()) {
createMeta("author",metaData.getCreator(),declarations);
// According to the spec, the date has the format YYYY-MM-DDThh:mm:ss
String sDate = metaData.getDate();
if (sDate.length()==19 && sDate.charAt(10)=='T') {
sDate = sDate.substring(0,10);
}
createMeta("date",sDate,declarations);
}
// Create options for documentclass
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
StyleWithProperties dpStyle = ofr.getDefaultParStyle();
if (dpStyle!=null) {
String s = dpStyle.getProperty(XMLString.FO_FONT_SIZE);
if ("10pt".equals(s)) { globalOptions.addValue("10pt"); }
if ("11pt".equals(s)) { globalOptions.addValue("11pt"); }
if ("12pt".equals(s)) { globalOptions.addValue("12pt"); }
}
}
// Temp solution. TODO: Fix when new CSVList is implemented
if (config.getGlobalOptions().length()>0) {
globalOptions.addValue(config.getGlobalOptions());
}
// Assemble the document
LaTeXDocumentPortion result = texDoc.getContents();
if (!config.noPreamble()) {
// Create document class declaration
result.append("% This file was converted to LaTeX by Writer2LaTeX ver. "+ConverterFactory.getVersion()).nl()
.append("% see http://www.hj-gym.dk/~hj/writer2latex for more info").nl();
result.append("\\documentclass");
if (!globalOptions.isEmpty()) {
result.append("[").append(globalOptions.toString()).append("]");
}
result.append("{").append(config.getDocumentclass()).append("}").nl();
result.append(packages)
.append(declarations)
.append("\\begin{document}").nl();
}
result.append(body);
if (!config.noPreamble()) {
result.append("\\end{document}").nl();
}
else {
result.append("\\endinput").nl();
}
// Add BibTeX document if there's any bibliographic data
if (bibCv.getBibTeXDocument()!=null) {
convertData.addDocument(bibCv.getBibTeXDocument());
}
}
private void createMeta(String sName, String sValue,LaTeXDocumentPortion ldp) {
if (sValue==null) { return; }
// Meta data is assumed to be in the default language:
ldp.append("\\"+sName+"{"+i18n.convert(sValue,false,mainContext.getLang())+"}").nl();
}
}

View file

@ -0,0 +1,496 @@
/************************************************************************
*
* DrawConverter.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 java.util.LinkedList;
import java.util.Stack;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
//import org.w3c.dom.Node;
import writer2latex.xmerge.EmbeddedObject;
import writer2latex.xmerge.EmbeddedXMLObject;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
//import writer2latex.office.ImageLoader;
import writer2latex.office.MIMETypes;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Misc;
import writer2latex.xmerge.BinaryGraphicsDocument;
/**
* <p>This class handles draw elements.</p>
*/
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 is <point size><paragraph sign><mode><paragraph sign><TeX code>
int n=0;
if (sOOoLaTeX!=null) {
if ((n=sOOoLaTeX.indexOf("\u00A7display\u00A7"))>-1) {
ldp.append("\\[").append(sOOoLaTeX.substring(n+9)).append("\\]");
bNeedOOoLaTeXPreamble = true;
return;
}
else if ((n=sOOoLaTeX.indexOf("\u00A7inline\u00A7"))>-1) {
ldp.append("$").append(sOOoLaTeX.substring(n+8)).append("$");
bNeedOOoLaTeXPreamble = true;
return;
}
else if ((n=sOOoLaTeX.indexOf("\u00A7text\u00A7"))>-1) {
ldp.append(sOOoLaTeX.substring(n+6));
bNeedOOoLaTeXPreamble = true;
return;
}
}
}
//if (oc.isInFrame() || "as-char".equals(sAnchor)) {
if ("as-char".equals(sAnchor)) {
handleDrawImageAsChar(node,ldp,oc);
}
else {
((LinkedList) floatingFramesStack.peek()).add(node);
}
}
private void handleDrawImageAsChar(Element node, LaTeXDocumentPortion ldp, Context oc) {
ldp.append(" ");
includeGraphics(node,ldp,oc);
ldp.append(" ");
}
private void handleDrawImageFloat(Element node, LaTeXDocumentPortion ldp, Context oc) {
Context ic = (Context) oc.clone();
BeforeAfter ba = new BeforeAfter();
applyFigureFloat(ba,ic);
ldp.append(ba.getBefore());
includeGraphics(node,ldp,ic);
ldp.append(ba.getAfter());
}
private void includeGraphics(Element node, LaTeXDocumentPortion ldp, Context oc) {
String sFileName = null;
boolean bCommentOut = true;
String sHref = node.getAttribute(XMLString.XLINK_HREF);
if (node.hasAttribute(XMLString.XLINK_HREF) && !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);
}
int nExtStart = sHref.lastIndexOf(".");
String sExt = nExtStart>=0 ? sHref.substring(nExtStart).toLowerCase() : "";
// Accept only relative filenames and supported filetypes:
bCommentOut = sFileName.indexOf(":")>-1 || !(
config.getBackend()==LaTeXConfig.UNSPECIFIED ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.JPEG_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.PNG_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.PDF_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.JPEG_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.PNG_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.PDF_EXT.equals(sExt)) ||
(config.getBackend()==LaTeXConfig.DVIPS && MIMETypes.EPS_EXT.equals(sExt)));
}
else { // embedded or base64 encoded image
BinaryGraphicsDocument bgd = palette.getImageLoader().getImage(node);
if (bgd!=null) {
palette.addDocument(bgd);
sFileName = bgd.getFileName();
String sMIME = bgd.getDocumentMIMEType();
bCommentOut = !(
config.getBackend()==LaTeXConfig.UNSPECIFIED ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.JPEG.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.PNG.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.PDFTEX && MIMETypes.PDF.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.JPEG.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.PNG.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.XETEX && MIMETypes.PDF.equals(sMIME)) ||
(config.getBackend()==LaTeXConfig.DVIPS && MIMETypes.EPS.equals(sMIME)));
}
}
if (sFileName==null) {
ldp.append("[Warning: Image not found]");
return;
}
// Now for the actual inclusion:
bNeedGraphicx = true;
/* TODO: handle cropping and mirror:
style:mirror can be none, vertical (lodret), horizontal (vandret),
horizontal-on-odd, or
horizontal-on-even (horizontal on odd or even pages).
mirror is handled with scalebox, eg:
%\\scalebox{-1}[1]{...}
can check for even/odd page first!!
fo:clip="rect(t,r,b,l) svarer til trim
value can be auto - no clip!
cropping is handled with clip and trim:
\\includegraphics[clip,trim=l b r t]{...}
note the different order from xsl-fo!
*/
if (bCommentOut) {
ldp.append(" [Warning: Image ignored] ");
ldp.append("% Unhandled or unsupported graphics:").nl().append("%");
}
ldp.append("\\includegraphics");
CSVList options = new CSVList(',');
if (!config.originalImageSize()) {
Element frame = getFrame(node);
String sWidth = Misc.truncateLength(frame.getAttribute(XMLString.SVG_WIDTH));
String sHeight = Misc.truncateLength(frame.getAttribute(XMLString.SVG_HEIGHT));
if (sWidth!=null) { options.addValue("width="+sWidth); }
if (sHeight!=null) { options.addValue("height="+sHeight); }
}
if (config.getImageOptions().length()>0) {
options.addValue(config.getImageOptions()); // TODO: New CSVList...
}
if (!options.isEmpty()) {
ldp.append("[").append(options.toString()).append("]");
}
if (config.removeGraphicsExtension()) {
sFileName = Misc.removeExtension(sFileName);
}
ldp.append("{").append(sFileName).append("}");
if (bCommentOut) { ldp.nl(); }
}
//--------------------------------------------------------------------------
// handle draw:text-box element
private void handleDrawTextBox(Element node, LaTeXDocumentPortion ldp, Context oc) {
Element frame = getFrame(node);
//String sName = frame.getAttribute(XMLString.DRAW_NAME);
palette.getFieldCv().addTarget(frame,"|frame",ldp);
String sAnchor = frame.getAttribute(XMLString.TEXT_ANCHOR_TYPE);
//if (oc.isInFrame() || "as-char".equals(sAnchor)) {
if ("as-char".equals(sAnchor)) {
makeDrawTextBox(node, ldp, oc);
}
else {
((LinkedList) floatingFramesStack.peek()).add(node);
}
}
private void handleDrawTextBoxFloat(Element node, LaTeXDocumentPortion ldp, Context oc) {
BeforeAfter ba = new BeforeAfter();
Context ic = (Context) oc.clone();
applyFigureFloat(ba,ic);
ldp.append(ba.getBefore());
makeDrawTextBox(node, ldp, ic);
ldp.append(ba.getAfter());
}
private void makeDrawTextBox(Element node, LaTeXDocumentPortion ldp, Context oc) {
Context ic = (Context) oc.clone();
ic.setInFrame(true);
ic.setNoFootnotes(true);
// Check to see, if this is really a container for a figure caption
boolean bIsCaption = false;
if (OfficeReader.isSingleParagraph(node)) {
Element par = Misc.getFirstChildElement(node);
String sSeqName = ofr.getSequenceName(par);
if (ofr.isFigureSequenceName(sSeqName)) { bIsCaption = true; }
}
String sWidth = Misc.truncateLength(getFrame(node).getAttribute(XMLString.SVG_WIDTH));
if (!bIsCaption) {
ldp.append("\\begin{minipage}{").append(sWidth).append("}").nl();
}
floatingFramesStack.push(new LinkedList());
palette.getBlockCv().traverseBlockText(node,ldp,ic);
flushFloatingFrames(ldp,ic);
floatingFramesStack.pop();
if (!bIsCaption) {
ldp.append("\\end{minipage}");
}
if (!oc.isNoFootnotes()) { palette.getNoteCv().flushFootnotes(ldp,oc); }
}
//-------------------------------------------------------------------------
//handle any pending floating frames
public void flushFloatingFrames(LaTeXDocumentPortion ldp, Context oc) {
// todo: fix language
LinkedList floatingFrames = (LinkedList) floatingFramesStack.peek();
int n = floatingFrames.size();
if (n==0) { return; }
for (int i=0; i<n; i++) {
Element node = (Element) floatingFrames.get(i);
String sName = node.getNodeName();
if (sName.equals(XMLString.DRAW_IMAGE)) {
handleDrawImageFloat(node,ldp,oc);
}
else if (sName.equals(XMLString.DRAW_TEXT_BOX)) {
handleDrawTextBoxFloat(node,ldp,oc);
}
}
floatingFrames.clear();
}
}

View file

@ -0,0 +1,672 @@
/************************************************************************
*
* FieldConverter.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.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.latex.util.Context;
import writer2latex.latex.util.HeadingMap;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.ExportNameCollection;
import writer2latex.util.Misc;
import writer2latex.util.SimpleInputBuffer;
/**
* This class handles text fields and links in the document.
* Packages: lastpage, hyperref, titleref, oooref (all optional)
* TODO: Need proper treatment of "caption" and "text" for sequence
* references not to figures and tables (should be fairly rare, though)
*/
public class FieldConverter extends ConverterHelper {
// Links & references
private ExportNameCollection targets = new ExportNameCollection(true);
private ExportNameCollection refnames = new ExportNameCollection(true);
private ExportNameCollection bookmarknames = new ExportNameCollection(true);
private ExportNameCollection seqnames = new ExportNameCollection(true);
private ExportNameCollection seqrefnames = new ExportNameCollection(true);
// sequence declarations (maps name->text:sequence-decl element)
private Hashtable seqDecl = new Hashtable();
// first usage of sequence (maps name->text:sequence element)
private Hashtable seqFirst = new Hashtable();
private Vector postponedReferenceMarks = new Vector();
private Vector postponedBookmarks = new Vector();
private boolean bUseHyperref = false;
private boolean bUsesPageCount = false;
private boolean bUsesTitleref = false;
private boolean bUsesOooref = false;
public FieldConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
// hyperref.sty is not compatible with titleref.sty and oooref.sty:
bUseHyperref = config.useHyperref() && !config.useTitleref() && !config.useOooref();
}
/** <p>Append declarations needed by the <code>FieldConverter</code> to
* the preamble.</p>
* @param pack the <code>LaTeXDocumentPortion</code> to which
* declarations of packages should be added (<code>\\usepackage</code>).
* @param decl the <code>LaTeXDocumentPortion</code> 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();
}
}
/** <p>Process sequence declarations</p>
* @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();
}
}
/** <p>Process a sequence field (text:sequence tag)</p>
* @param node The element containing the sequence field
* @param ldp the <code>LaTeXDocumentPortion</code> 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("}");
}
}
}
}
/** <p>Create label for a sequence field (text:sequence tag)</p>
* @param node The element containing the sequence field
* @param ldp the <code>LaTeXDocumentPortion</code> 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:<number>, ooow:<name>, ooow:<name>+<number>
// and ooow:<name>-<number>
// Note: In OOo a counter is a 16 bit unsigned integer, whereas a (La)TeX
// counter can be negative - thus there will be a slight deviation in the
// (rare) case of a negative number
private String changeCounter(String sName, String sFormula, boolean bRef) {
if (sFormula!=null) {
sFormula = sFormula.trim();
if (sFormula.startsWith("ooow:")) {
SimpleInputBuffer input = new SimpleInputBuffer(sFormula.substring(5));
if (input.peekChar()>='0' && input.peekChar()<='9') {
// Value is <number>
String sNumber = input.getInteger();
if (input.atEnd()) {
return setCounter(sName, Misc.getPosInteger(sNumber,0), bRef);
}
}
else if (input.peekChar()=='-') {
// Value is a negative <number>
input.getChar();
if (input.peekChar()>='0' && input.peekChar()<='9') {
String sNumber = input.getInteger();
if (input.atEnd()) {
return setCounter(sName, -Misc.getPosInteger(sNumber,0), bRef);
}
}
}
else {
// Value starts with <name>
String sToken = input.getIdentifier();
if (sToken.equals(sName)) {
input.skipSpaces();
if (input.peekChar()=='+') {
// Value is <name>+<number>
input.getChar();
input.skipSpaces();
String sNumber = input.getInteger();
if (input.atEnd()) {
return addtoCounter(sName, Misc.getPosInteger(sNumber,0), bRef);
}
}
else if (input.peekChar()=='-') {
// Value is <name>-<number>
input.getChar();
input.skipSpaces();
String sNumber = input.getInteger();
if (input.atEnd()) {
return addtoCounter(sName, -Misc.getPosInteger(sNumber,0), bRef);
}
}
else if (input.atEnd()) {
// Value is <name>
return addtoCounter(sName, 0, bRef);
}
}
}
}
}
// No formula, or a formula we don't understand -> use default behavior
return stepCounter(sName, bRef);
}
private String stepCounter(String sName, boolean bRef) {
if (bRef) {
return "\\refstepcounter{" + seqnames.getExportName(sName) + "}";
}
else {
return "\\stepcounter{" + seqnames.getExportName(sName) + "}";
}
}
private String addtoCounter(String sName, int nValue, boolean bRef) {
if (nValue==1) {
return stepCounter(sName, bRef);
}
else if (bRef) {
return "\\addtocounter{" + seqnames.getExportName(sName) + "}"
+ "{" + Integer.toString(nValue-1) + "}"
+ "\\refstepcounter{" + seqnames.getExportName(sName) + "}";
}
else if (nValue!=0) {
return "\\addtocounter{" + seqnames.getExportName(sName) + "}"
+ "{" + Integer.toString(nValue) + "}";
}
else {
return "";
}
}
private String setCounter(String sName, int nValue, boolean bRef) {
if (bRef) {
return "\\setcounter{" + seqnames.getExportName(sName) + "}"
+ "{" + Integer.toString(nValue-1) + "}"
+ "\\refstepcounter{" + seqnames.getExportName(sName) + "}";
}
else {
return "\\setcounter{" + seqnames.getExportName(sName) + "}"
+ "{" + Integer.toString(nValue) + "}";
}
}
/** <p>Process a sequence reference (text:sequence-ref tag)</p>
* @param node The element containing the sequence reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
}
/** <p>Process a reference mark (text:reference-mark tag)</p>
* @param node The element containing the reference mark
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Process a reference (text:reference-ref tag)</p>
* @param node The element containing the reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Process a bookmark (text:bookmark tag)</p>
* <p>A bookmark may be the target for either a hyperlink or a reference,
* so this will generate a <code>\\hyperref</code> and/or a <code>\\label</code></p>
* @param node The element containing the bookmark
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Process a bookmark reference (text:bookmark-ref tag).</p>
* @param node The element containing the bookmark reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Process pending reference marks and bookmarks (which may have been
* postponed within sections, captions or verbatim text.</p>
* @param ldp the <code>LaTeXDocumentPortion</code> 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; i<n; i++) {
handleReferenceMark((Element) postponedReferenceMarks.get(i),ldp,oc);
}
postponedReferenceMarks.clear();
// Type out all postponed bookmarks
n = postponedBookmarks.size();
for (int i=0; i<n; i++) {
handleBookmark((Element) postponedBookmarks.get(i),ldp,oc);
}
postponedBookmarks.clear();
}
}
/** <p>Process a hyperlink (text:a tag)</p>
* @param node The element containing the hyperlink
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Add a <code>\\hypertarget</code></p>
* @param node The element containing the name of the target
* @param sSuffix A suffix to be added to the target,
* e.g. "|table" for a reference to a table.
* @param ldp the <code>LaTeXDocumentPortion</code> 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("}{}");
}
/** <p>Add a <code>\\hypertarget</code></p>
* @param sName The name of the target
* @param sSuffix A suffix to be added to the target,
* e.g. "|table" for a reference to a table.
* @param ldp the <code>LaTeXDocumentPortion</code> 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("}{}");
}
}
/** <p>Process a page number field (text:page-number tag)</p>
* @param node The element containing the page number field
* @param ldp the <code>LaTeXDocumentPortion</code> 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{}");
}
/** <p>Process a page count field (text:page-count tag)</p>
* @param node The element containing the page count field
* @param ldp the <code>LaTeXDocumentPortion</code> 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; i<s.length(); i++) {
if (s.charAt(i)=='#') { buf.append("\\#"); }
else { buf.append(s.charAt(i)); }
}
return buf.toString();
}
}

View file

@ -0,0 +1,357 @@
/************************************************************************
*
* HeadingConverter.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.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;
/* This class converts OpenDocument headings (<code>text:h</code>) and
* paragraph styles/formatting into LaTeX
* Export of formatting depends on the option "formatting":
* <ul>
* <li><code>ignore_all</code>
* <li><code>ignore_most</code>
* <li><code>convert_basic</code>
* <li><code>convert_most</code>
* <li><code>convert_all</code>
* </ul>
*/
public class HeadingConverter extends ConverterHelper {
private String[] sHeadingStyles = new String[11];
/** Constructs a new <code>HeadingConverter</code>.
*/
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 <code>nLevel</code> The level of this heading
* @param <code>sStyleName</code> the name of the paragraph style to use
* @param <code>baPage</code> a <code>BeforeAfter</code> to put page break code into
* @param <code>baText</code> a <code>BeforeAfter</code> to put character formatting code into
* @param <code>context</code> 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; j<i; j++) {
ldp.append(sNumFormat[j])
.append("{").append(sectionName(j)).append("}")
.append(".");
}
ldp.append(sNumFormat[i])
.append("{").append(hm.getName(i)).append("}")
.append("}").nl();
}
}
if (!bOnlyNum) {
ldp.append("\\makeatother").nl();
}
}
/* Check to see if this node contains any element nodes, except reference marks */
public boolean containsElements(Node node) {
if (!node.hasChildNodes()) { return false; }
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 &&
!child.getNodeName().startsWith(XMLString.TEXT_REFERENCE_MARK)) {
return true;
}
}
return false;
}
static final String sectionName(int nLevel){
switch (nLevel) {
case 1: return "section";
case 2: return "subsection";
case 3: return "subsubsection";
case 4: return "paragraph";
case 5: return "subparagraph";
default: return null;
}
}
}

View file

@ -0,0 +1,242 @@
/************************************************************************
*
* IndexConverter.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.Vector;
import org.w3c.dom.Element;
//import org.w3c.dom.Node;
import writer2latex.util.Misc;
import writer2latex.office.IndexMark;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.latex.util.Context;
/**
* <p>This 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.</p>
*/
public class IndexConverter extends ConverterHelper {
private boolean bContainsAlphabeticalIndex = false;
private Vector postponedIndexMarks = new Vector();
/** <p>Construct a new <code>IndexConverter</code>.
* @param config the configuration to use
* @param palette the <code>ConverterPalette</code> to link to
* if such a document is created by the <code>IndexConverter</code>
*/
public IndexConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
}
/** <p>Append declarations needed by the <code>IndexConverter</code> to
* the preamble.
* @param pack the <code>LaTeXDocumentPortion</code> to which
* declarations of packages should be added (<code>\\usepackage</code>).
* @param decl the <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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 <code>LaTeXDocumentPortion</code> 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<n; i++) {
handleAlphabeticalIndexMark((Element) postponedIndexMarks.get(i),ldp,oc);
}
postponedIndexMarks.clear();
}
}
// Helper: Write the text of an index mark, escaping special characters
private void writeIndexText(String sText, LaTeXDocumentPortion ldp, Context oc) {
String sTextOut = palette.getI18n().convert(sText,false,oc.getLang());
// need to escape !, @, | and ":
int nLen = sTextOut.length();
boolean bBackslash = false;
for (int i=0; i<nLen; i++) {
if (bBackslash) {
ldp.append(sTextOut.substring(i,i+1));
bBackslash = false;
}
else {
switch (sTextOut.charAt(i)) {
case '\\' : bBackslash = true;
ldp.append("\\");
break;
case '~' :
case '\u00A0' :
// Non-breaking space causes trouble in index:
ldp.append(" ");
break;
case '!' :
case '@' :
case '|' :
case '"' : ldp.append("\"");
default : ldp.append(sTextOut.substring(i,i+1));
}
}
}
}
}

View file

@ -0,0 +1,636 @@
/************************************************************************
*
* InlineConverter.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.latex;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import writer2latex.util.Misc;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
import writer2latex.latex.util.HeadingMap;
/**
* <p>This class handles basic inline text.</p>
*/
public class InlineConverter extends ConverterHelper {
private String sTabstop = "\\ \\ ";
private boolean bHasPdfannotation = false;
public InlineConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
// Get custom code for tab stops
if (config.getTabstop().length()>0) {
sTabstop = config.getTabstop();
}
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bHasPdfannotation) {
decl.append("\\newcommand\\pdfannotation[1]")
.append("{\\ifx\\pdfoutput\\undefined\\marginpar{#1}\\else")
.append("\\pdfstringdef\\tempstring{#1}\\marginpar{")
.append("\\pdfannot width 5cm height 12pt depth 4cm ")
.append("{ /Subtype /Text /Open false /Contents(\\tempstring) /Color [1 0 0]}")
.append("}\\fi}").nl();
}
}
/** Handle a text:span element
*/
public void handleTextSpan(Element node, LaTeXDocumentPortion ldp, Context oc) {
if (oc.isMathMode()) { handleTextSpanMath(node, ldp, oc); }
else { handleTextSpanText(node, ldp, oc); }
}
private void handleTextSpanMath(Element node, LaTeXDocumentPortion ldp, Context oc) {
// TODO: Handle a selection of formatting attributes: color, supscript...
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
StyleWithProperties style = ofr.getTextStyle(sStyleName);
// Always push the font used
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(style));
// Convert formatting
BeforeAfter ba = new BeforeAfter();
if (style!=null) {
String sPos = style.getProperty(XMLString.STYLE_TEXT_POSITION, true);
if (sPos!=null) {
if (sPos.startsWith("sub") || sPos.startsWith("-")) {
ba.add("_{", "}");
}
else if (sPos.startsWith("super") || !sPos.startsWith("0%")) {
ba.add("^{", "}");
}
}
}
ldp.append(ba.getBefore());
traverseInlineMath(node, ldp, oc);
ldp.append(ba.getAfter());
// finally pop the font table
palette.getI18n().popSpecialTable();
}
private void handleTextSpanText(Element node, LaTeXDocumentPortion ldp, Context oc) {
String styleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
// Check for strict handling of styles
String sDisplayName = ofr.getTextStyles().getDisplayName(styleName);
if (config.otherStyles()!=LaTeXConfig.ACCEPT && !config.getTextStyleMap().contains(sDisplayName)) {
if (config.otherStyles()==LaTeXConfig.WARNING) {
System.err.println("Warning: Text with style "+sDisplayName+" was ignored");
}
else if (config.otherStyles()==LaTeXConfig.ERROR) {
ldp.append("% Error in source document: Text with style ")
.append(palette.getI18n().convert(sDisplayName,false,oc.getLang()))
.append(" was ignored").nl();
}
// Ignore this text:
return;
}
boolean styled = true;
// don't style it if a {foot|end}note is the only content
if (onlyNote(node) || OfficeReader.getCharacterCount(node)==0) { styled = false; }
// Also don't style it if we're already within a verbatim environment
if (oc.isVerbatim()) { styled = false; }
boolean bNoFootnotes = false;
// Always push the font used
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getTextStyle(styleName)));
// Apply the style
BeforeAfter ba = new BeforeAfter();
Context ic = (Context) oc.clone();
if (styled) { palette.getCharSc().applyTextStyle(styleName,ba,ic); }
// Footnote problems:
// No footnotes in sub/superscript (will disappear)
// No multiparagraph footnotes embedded in text command (eg. \textbf{..})
// Simple solution: styled text element is forbidden footnote area
if (styled && !ic.isInFootnote()) { bNoFootnotes = true; }
// Temp solution: Ignore hard formatting in header/footer (name clash problem)
// only in package format.
StyleWithProperties style = ofr.getTextStyle(styleName);
if (ofr.isPackageFormat() && (style!=null && style.isAutomatic()) && ic.isInHeaderFooter()) {
styled = false;
}
if (styled) {
if (bNoFootnotes) { ic.setNoFootnotes(true); }
ldp.append(ba.getBefore());
}
traverseInlineText(node,ldp,ic);
if (styled) {
ldp.append(ba.getAfter());
ic.setNoFootnotes(false);
if (!ic.isInFootnote()) { palette.getNoteCv().flushFootnotes(ldp,oc); }
}
// Flush any pending index marks and reference marks
palette.getFieldCv().flushReferenceMarks(ldp,oc);
palette.getIndexCv().flushIndexMarks(ldp,oc);
// finally pop the special table
palette.getI18n().popSpecialTable();
}
public void traverseInlineText(Element node, LaTeXDocumentPortion ldp, Context oc) {
if (oc.isVerbatim()) {
traverseVerbatimInlineText(node,ldp,oc);
}
else if (oc.isMathMode()) {
traverseInlineMath(node,ldp,oc);
}
else {
traverseOrdinaryInlineText(node,ldp,oc);
}
}
// Traverse ordinary inline text in text mode (temporarily changing to math
// mode for a sequence of text:span with style "OOoLaTeX")
private void traverseOrdinaryInlineText(Element node,LaTeXDocumentPortion ldp, Context oc) {
Node childNode = node.getFirstChild();
while (childNode!=null) {
short nodeType = childNode.getNodeType();
switch (nodeType) {
case Node.TEXT_NODE:
String s = childNode.getNodeValue();
if (s.length() > 0) {
ldp.append(palette.getI18n().convert(s, false, oc.getLang()));
}
break;
case Node.ELEMENT_NODE:
Element child = (Element)childNode;
String sName = child.getTagName();
if (sName.equals(XMLString.TEXT_SPAN)) {
String sStyleName = child.getAttribute(XMLString.TEXT_STYLE_NAME);
boolean bIsMathSpan = "OOoLaTeX".equals(ofr.getTextStyles().getDisplayName(sStyleName));
if (bIsMathSpan) {
// Temporarily change to math mode
Context ic = (Context) oc.clone();
ic.setMathMode(true);
ldp.append("$");
Node remember;
boolean bContinue = false;
do {
handleTextSpanMath((Element)childNode, ldp, ic);
remember = childNode;
childNode = childNode.getNextSibling();
bContinue = false;
if (childNode!=null && childNode.getNodeType()==Node.ELEMENT_NODE &&
childNode.getNodeName().equals(XMLString.TEXT_SPAN)) {
sStyleName = Misc.getAttribute(childNode,XMLString.TEXT_STYLE_NAME);
if ("OOoLaTeX".equals(ofr.getTextStyles().getDisplayName(sStyleName)))
//child = (Element) childNode;
bContinue = true;
}
} while(bContinue);
childNode = remember;
ldp.append("$");
}
else {
handleTextSpan(child,ldp,oc);
}
}
else if (child.getNodeName().startsWith("draw:")) {
palette.getDrawCv().handleDrawElement(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_S)) {
if (config.ignoreDoubleSpaces()) {
ldp.append(" ");
}
else {
int count= Misc.getPosInteger(child.getAttribute(XMLString.TEXT_C),1);
//String sSpace = config.ignoreDoubleSpaces() ? " " : "\\ ";
for ( ; count > 0; count--) { ldp.append("\\ "); }
}
}
else if (sName.equals(XMLString.TEXT_TAB_STOP) || sName.equals(XMLString.TEXT_TAB)) { // text:tab in oasis
// tab stops are not supported by the converter, but the special usage
// of tab stops in header and footer can be emulated with \hfill
// TODO: Sometimes extra \hfill should be added at end of line
if (oc.isInHeaderFooter()) { ldp.append("\\hfill "); }
else { ldp.append(sTabstop); }
}
else if (sName.equals(XMLString.TEXT_LINE_BREAK)) {
if (!oc.isInHeaderFooter() && !config.ignoreHardLineBreaks()) {
ldp.append("\\newline").nl();
}
else { ldp.append(" "); }
}
else if (sName.equals(XMLString.TEXT_A)) {
palette.getFieldCv().handleAnchor(child,ldp,oc);
}
else if (sName.equals(XMLString.OFFICE_ANNOTATION)) {
handleOfficeAnnotation(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_PAGE_NUMBER)) {
palette.getFieldCv().handlePageNumber(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_PAGE_COUNT)) {
palette.getFieldCv().handlePageCount(child,ldp,oc);
}
else if (oc.isInHeaderFooter()) {
if (sName.equals(XMLString.TEXT_CHAPTER)) {
handleChapterField(child,ldp,oc);
}
else if (sName.startsWith("text:")) {
traverseInlineText(child,ldp,oc);
}
}
else {
// These tags are ignored in header and footer
if (sName.equals(XMLString.TEXT_FOOTNOTE)) {
palette.getNoteCv().handleFootnote(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_ENDNOTE)) {
palette.getNoteCv().handleEndnote(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_NOTE)) {
if ("endnote".equals(child.getAttribute(XMLString.TEXT_NOTE_CLASS))) {
palette.getNoteCv().handleEndnote(child,ldp,oc);
}
else {
palette.getNoteCv().handleFootnote(child,ldp,oc);
}
}
else if (sName.equals(XMLString.TEXT_SEQUENCE)) {
palette.getFieldCv().handleSequence(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_SEQUENCE_REF)) {
palette.getFieldCv().handleSequenceRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_FOOTNOTE_REF)) {
palette.getNoteCv().handleFootnoteRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_ENDNOTE_REF)) {
palette.getNoteCv().handleEndnoteRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_NOTE_REF)) { // oasis
palette.getNoteCv().handleNoteRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_REFERENCE_MARK)) {
palette.getFieldCv().handleReferenceMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_REFERENCE_MARK_START)) {
palette.getFieldCv().handleReferenceMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_REFERENCE_REF)) {
palette.getFieldCv().handleReferenceRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BOOKMARK)) {
palette.getFieldCv().handleBookmark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BOOKMARK_START)) {
palette.getFieldCv().handleBookmark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BOOKMARK_REF)) {
palette.getFieldCv().handleBookmarkRef(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BIBLIOGRAPHY_MARK)) {
palette.getBibCv().handleBibliographyMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_ALPHABETICAL_INDEX_MARK)) {
palette.getIndexCv().handleAlphabeticalIndexMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_ALPHABETICAL_INDEX_MARK_START)) {
palette.getIndexCv().handleAlphabeticalIndexMark(child,ldp,oc);
}
else if (sName.startsWith("text:")) {
traverseInlineText(child,ldp,oc);
}
}
break;
default:
// Do nothing
}
childNode = childNode.getNextSibling();
}
}
/* traverse inline text, ignoring any draw objects, footnotes, formatting and hyperlinks */
public void traversePlainInlineText(Element node,LaTeXDocumentPortion ldp, Context oc) {
String styleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
// Always push the font used
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getTextStyle(styleName)));
Node childNode = node.getFirstChild();
while (childNode!=null) {
short nodeType = childNode.getNodeType();
switch (nodeType) {
case Node.TEXT_NODE:
String s = childNode.getNodeValue();
if (s.length() > 0) {
// Need to protect ]
for (int j=0; j<s.length(); j++) {
if (s.charAt(j)!=']') {
ldp.append(palette.getI18n().convert(Character.toString(s.charAt(j)),false,oc.getLang()));
}
else {
ldp.append("{]}");
}
}
}
break;
case Node.ELEMENT_NODE:
Element child = (Element)childNode;
String sName = child.getTagName();
if (sName.equals(XMLString.TEXT_SPAN)) {
traversePlainInlineText(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_S)) {
int count= Misc.getPosInteger(child.getAttribute(XMLString.TEXT_C),1);
for ( ; count > 0; count--) {
ldp.append("\\ ");
}
}
else if (sName.equals(XMLString.TEXT_TAB_STOP) || sName.equals(XMLString.TEXT_TAB)) { // text:tab in oasis
// tab stops are not supported by the converter
ldp.append(sTabstop);
}
else if (OfficeReader.isNoteElement(child)) {
// ignore
}
else if (OfficeReader.isTextElement(child)) {
traversePlainInlineText(child,ldp,oc);
}
break;
default:
// Do nothing
}
childNode = childNode.getNextSibling();
}
// finally pop the special table
palette.getI18n().popSpecialTable();
}
/* traverse inline math, ignoring any draw objects, footnotes, formatting and hyperlinks */
public void traverseInlineMath(Element node,LaTeXDocumentPortion ldp, Context oc) {
String styleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
// Always push the font used
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getTextStyle(styleName)));
Node childNode = node.getFirstChild();
while (childNode!=null) {
short nodeType = childNode.getNodeType();
switch (nodeType) {
case Node.TEXT_NODE:
String s = childNode.getNodeValue();
ldp.append(palette.getI18n().convert(s,true,oc.getLang()));
break;
case Node.ELEMENT_NODE:
Element child = (Element)childNode;
String sName = child.getTagName();
if (sName.equals(XMLString.TEXT_S)) {
int count= Misc.getPosInteger(child.getAttribute(XMLString.TEXT_C),1);
for ( ; count > 0; count--) {
ldp.append("\\ ");
}
}
else if (sName.equals(XMLString.TEXT_TAB_STOP) || sName.equals(XMLString.TEXT_TAB)) { // text:tab in oasis
// tab stops are not supported by the converter
ldp.append(" ");
}
else if (OfficeReader.isNoteElement(child)) {
// ignore
}
else if (OfficeReader.isTextElement(child)) {
traversePlainInlineText(child,ldp,oc);
}
break;
default:
// Do nothing
}
childNode = childNode.getNextSibling();
}
// finally pop the special table
palette.getI18n().popSpecialTable();
}
/* traverse verbatim inline text, ignoring any draw objects, footnotes, formatting and hyperlinks */
private void traverseVerbatimInlineText(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);
short nodeType = childNode.getNodeType();
switch (nodeType) {
case Node.TEXT_NODE:
String s = childNode.getNodeValue();
if (s.length() > 0) {
// text is copied verbatim! (Will be replaced by
// question marks if outside inputenc)
ldp.append(s);
}
break;
case Node.ELEMENT_NODE:
Element child = (Element)childNode;
String sName = child.getTagName();
if (sName.equals(XMLString.TEXT_S)) {
int count= Misc.getPosInteger(child.getAttribute(XMLString.TEXT_C),1);
for ( ; count > 0; count--) {
ldp.append(" ");
}
}
else if (sName.equals(XMLString.TEXT_TAB_STOP) || sName.equals(XMLString.TEXT_TAB)) { // text:tab in oasis
// tab stops are not supported by the onverter
ldp.append(sTabstop);
}
else if (sName.equals(XMLString.TEXT_LINE_BREAK)) {
if (!oc.isNoLineBreaks()) { ldp.nl(); }
}
else if (sName.equals(XMLString.TEXT_NOTE)) {
// oasis; ignore
}
else if (sName.equals(XMLString.TEXT_FOOTNOTE)) {
// ignore
}
else if (sName.equals(XMLString.TEXT_ENDNOTE)) {
// ignore
}
// The respective handlers know how to postpone these marks in verbatim context:
else if (sName.equals(XMLString.TEXT_ALPHABETICAL_INDEX_MARK)) {
palette.getIndexCv().handleAlphabeticalIndexMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_ALPHABETICAL_INDEX_MARK_START)) {
palette.getIndexCv().handleAlphabeticalIndexMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_REFERENCE_MARK)) {
palette.getFieldCv().handleReferenceMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_REFERENCE_MARK_START)) {
palette.getFieldCv().handleReferenceMark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BOOKMARK)) {
palette.getFieldCv().handleBookmark(child,ldp,oc);
}
else if (sName.equals(XMLString.TEXT_BOOKMARK_START)) {
palette.getFieldCv().handleBookmark(child,ldp,oc);
}
else if (sName.startsWith("text:")) {
traverseVerbatimInlineText(child,ldp,oc);
}
break;
default:
// Do nothing
}
}
}
}
public void traversePCDATA(Element node, LaTeXDocumentPortion ldp, Context oc) {
if (node.hasChildNodes()) {
NodeList nl = node.getChildNodes();
int nLen = nl.getLength();
for (int i=0; i<nLen; i++) {
if (nl.item(i).getNodeType()==Node.TEXT_NODE) {
ldp.append(palette.getI18n().convert(nl.item(i).getNodeValue(),false,oc.getLang()));
}
}
}
}
private void handleChapterField(Element node, LaTeXDocumentPortion ldp, Context oc) {
HeadingMap hm = config.getHeadingMap();
int nLevel = Misc.getPosInteger(node.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
if (nLevel<=hm.getMaxLevel()) {
int nLaTeXLevel = hm.getLevel(nLevel);
if (nLaTeXLevel==1) {
palette.getPageSc().setChapterField1(node.getAttribute(XMLString.TEXT_DISPLAY));
ldp.append("{\\leftmark}");
}
else if (nLaTeXLevel==2) {
palette.getPageSc().setChapterField2(node.getAttribute(XMLString.TEXT_DISPLAY));
ldp.append("{\\rightmark}");
}
}
}
////////////////////////////////////////////////////////////////////
// Annotations
private void handleOfficeAnnotation(Element node, LaTeXDocumentPortion ldp, Context oc) {
String sCommand = null;
switch (config.notes()) {
case LaTeXConfig.IGNORE: return;
case LaTeXConfig.COMMENT:
// Get the unformatted text of all paragraphs and insert each paragraph as a single comment
ldp.append("%").nl();
Node child = node.getFirstChild();
while (child!=null) {
if (Misc.isElement(child, XMLString.TEXT_P)) {
ldp.append("%");
traversePlainInlineText((Element)child, ldp, oc);
ldp.nl();
}
child = child.getNextSibling();
}
return;
case LaTeXConfig.PDFANNOTATION:
bHasPdfannotation = true;
sCommand = "\\pdfannotation";
break;
case LaTeXConfig.MARGINPAR:
sCommand = "\\marginpar";
break;
case LaTeXConfig.CUSTOM:
sCommand = config.getNotesCommand();
break;
}
// Get the unformatted text of all paragraphs, separated by spaces
ldp.append(sCommand).append("{");
boolean bFirst = true;
Node child = node.getFirstChild();
while (child!=null) {
if (Misc.isElement(child, XMLString.TEXT_P)) {
if (!bFirst) ldp.append(" ");
traversePlainInlineText((Element)child, ldp, oc);
bFirst = false;
}
child = child.getNextSibling();
}
ldp.append("}");
}
/* Check to see if this node has a footnote or endnote as the only subnode */
private boolean onlyNote(Node node) {
if (!node.hasChildNodes()) { return false; }
NodeList nList = node.getChildNodes();
int nLen = nList.getLength();
for (int i = 0; i < nLen; i++) {
Node child = nList.item(i);
short nType = child.getNodeType();
switch (nType) {
case Node.TEXT_NODE: return false;
case Node.ELEMENT_NODE:
if (!OfficeReader.isNoteElement(child)) { return false; }
}
}
return true;
}
}

View file

@ -0,0 +1,543 @@
/************************************************************************
*
* LaTeXConfig.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 java.util.LinkedList;
import java.util.Hashtable;
import java.util.Enumeration;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import writer2latex.base.BooleanOption;
import writer2latex.base.IntegerOption;
import writer2latex.base.Option;
import writer2latex.latex.util.HeadingMap;
import writer2latex.latex.i18n.ClassicI18n;
import writer2latex.latex.i18n.ReplacementTrie;
import writer2latex.latex.util.StyleMap;
import writer2latex.util.Misc;
public class LaTeXConfig extends writer2latex.base.ConfigBase {
protected int getOptionCount() { return 59; }
protected String getDefaultConfigPath() { return "/writer2latex/latex/config/"; }
// Override setOption to be backwards compatible
public void setOption(String sName,String sValue) {
// this option has been renamed:
if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
super.setOption(sName, sValue);
}
// Backend
public static final int GENERIC = 0;
public static final int DVIPS = 1;
public static final int PDFTEX = 2;
public static final int UNSPECIFIED = 3;
public static final int XETEX = 4;
// Formatting (must be ordered)
public static final int IGNORE_ALL = 0;
public static final int IGNORE_MOST = 1;
public static final int CONVERT_BASIC = 2;
public static final int CONVERT_MOST = 3;
public static final int CONVERT_ALL = 4;
// Page formatting
public static final int CONVERT_HEADER_FOOTER = 5;
// Handling of other formatting
public static final int IGNORE = 0;
public static final int ACCEPT = 1;
public static final int WARNING = 2;
public static final int ERROR = 3;
// Notes
//public static final int IGNORE = 0;
public static final int COMMENT = 1;
public static final int PDFANNOTATION = 2;
public static final int MARGINPAR = 3;
public static final int CUSTOM = 4;
// Options
protected int OPTION_COUNT = 59;
private static final int BACKEND = 0;
private static final int NO_PREAMBLE = 1;
private static final int NO_INDEX = 2;
private static final int DOCUMENTCLASS = 3;
private static final int GLOBAL_OPTIONS = 4;
private static final int INPUTENCODING = 5;
private static final int MULTILINGUAL = 6;
private static final int GREEK_MATH = 7;
private static final int USE_OOOMATH = 8;
private static final int USE_PIFONT = 9;
private static final int USE_IFSYM = 10;
private static final int USE_WASYSYM = 11;
private static final int USE_BBDING = 12;
private static final int USE_EUROSYM = 13;
private static final int USE_TIPA = 14;
private static final int USE_COLOR = 15;
private static final int USE_COLORTBL = 16;
private static final int USE_GEOMETRY = 17;
private static final int USE_FANCYHDR = 18;
private static final int USE_HYPERREF = 19;
private static final int USE_CAPTION = 20;
private static final int USE_LONGTABLE = 21;
private static final int USE_SUPERTABULAR = 22;
private static final int USE_TABULARY = 23;
private static final int USE_ENDNOTES = 24;
private static final int USE_ULEM = 25;
private static final int USE_LASTPAGE = 26;
private static final int USE_TITLEREF = 27;
private static final int USE_OOOREF = 28;
private static final int USE_BIBTEX = 29;
private static final int BIBTEX_STYLE = 30;
private static final int EXTERNAL_BIBTEX_FILES = 31;
private static final int FORMATTING = 32;
private static final int PAGE_FORMATTING = 33;
private static final int OTHER_STYLES = 34;
private static final int IMAGE_CONTENT = 35;
private static final int TABLE_CONTENT = 36;
private static final int IGNORE_HARD_PAGE_BREAKS = 37;
private static final int IGNORE_HARD_LINE_BREAKS = 38;
private static final int IGNORE_EMPTY_PARAGRAPHS = 39;
private static final int IGNORE_DOUBLE_SPACES = 40;
private static final int ALIGN_FRAMES = 41;
private static final int FLOAT_FIGURES = 42;
private static final int FLOAT_TABLES = 43;
private static final int FLOAT_OPTIONS = 44;
private static final int FIGURE_SEQUENCE_NAME = 45;
private static final int TABLE_SEQUENCE_NAME = 46;
private static final int IMAGE_OPTIONS = 47;
private static final int REMOVE_GRAPHICS_EXTENSION = 48;
private static final int ORIGINAL_IMAGE_SIZE = 49;
private static final int SIMPLE_TABLE_LIMIT = 50;
private static final int NOTES = 51;
private static final int METADATA = 52;
private static final int TABSTOP = 53;
private static final int WRAP_LINES_AFTER = 54;
private static final int SPLIT_LINKED_SECTIONS = 55;
private static final int SPLIT_TOPLEVEL_SECTIONS = 56;
private static final int SAVE_IMAGES_IN_SUBDIR = 57;
private static final int DEBUG = 58;
protected LinkedList customPreamble = new LinkedList();
protected StyleMap par = new StyleMap();
protected StyleMap parBlock = new StyleMap();
protected StyleMap text = new StyleMap();
protected StyleMap list = new StyleMap();
protected StyleMap listItem = new StyleMap();
protected StyleMap textAttr = new StyleMap();
protected HeadingMap headingMap = new HeadingMap(5);
protected Hashtable mathSymbols = new Hashtable();
protected ReplacementTrie stringReplace = new ReplacementTrie();
public LaTeXConfig() {
super();
// create options with default values
options[NO_PREAMBLE] = new BooleanOption("no_preamble","false");
options[NO_INDEX] = new BooleanOption("no_index","false");
options[DOCUMENTCLASS] = new Option("documentclass","article");
options[GLOBAL_OPTIONS] = new Option("global_options","");
options[BACKEND] = new IntegerOption("backend","pdftex") {
public void setString(String sValue) {
super.setString(sValue);
if ("generic".equals(sValue)) nValue = GENERIC;
else if ("dvips".equals(sValue)) nValue = DVIPS;
else if ("pdftex".equals(sValue)) nValue = PDFTEX;
else if ("unspecified".equals(sValue)) nValue = UNSPECIFIED;
else if ("xetex".equals(sValue)) nValue = XETEX;
}
};
options[INPUTENCODING] = new IntegerOption("inputencoding",ClassicI18n.writeInputenc(ClassicI18n.ASCII)) {
public void setString(String sValue) {
super.setString(sValue);
nValue = ClassicI18n.readInputenc(sValue);
}
};
options[MULTILINGUAL] = new BooleanOption("multilingual","true");
options[GREEK_MATH] = new BooleanOption("greek_math","true");
options[USE_OOOMATH] = new BooleanOption("use_ooomath","false");
options[USE_PIFONT] = new BooleanOption("use_pifont","false");
options[USE_IFSYM] = new BooleanOption("use_ifsym","false");
options[USE_WASYSYM] = new BooleanOption("use_wasysym","false");
options[USE_BBDING] = new BooleanOption("use_bbding","false");
options[USE_EUROSYM] = new BooleanOption("use_eurosym","false");
options[USE_TIPA] = new BooleanOption("use_tipa","false");
options[USE_COLOR] = new BooleanOption("use_color","true");
options[USE_COLORTBL] = new BooleanOption("use_colortbl","false");
options[USE_GEOMETRY] = new BooleanOption("use_geometry","false");
options[USE_FANCYHDR] = new BooleanOption("use_fancyhdr","false");
options[USE_HYPERREF] = new BooleanOption("use_hyperref","true");
options[USE_CAPTION] = new BooleanOption("use_caption","false");
options[USE_LONGTABLE] = new BooleanOption("use_longtable","false");
options[USE_SUPERTABULAR] = new BooleanOption("use_supertabular","true");
options[USE_TABULARY] = new BooleanOption("use_tabulary","false");
options[USE_ENDNOTES] = new BooleanOption("use_endnotes","false");
options[USE_ULEM] = new BooleanOption("use_ulem","false");
options[USE_LASTPAGE] = new BooleanOption("use_lastpage","false");
options[USE_TITLEREF] = new BooleanOption("use_titleref","false");
options[USE_OOOREF] = new BooleanOption("use_oooref","false");
options[USE_BIBTEX] = new BooleanOption("use_bibtex","false");
options[BIBTEX_STYLE] = new Option("bibtex_style","plain");
options[EXTERNAL_BIBTEX_FILES] = new Option("external_bibtex_files","");
options[FORMATTING] = new IntegerOption("formatting","convert_basic") {
public void setString(String sValue) {
super.setString(sValue);
if ("convert_all".equals(sValue)) nValue = CONVERT_ALL;
else if ("convert_most".equals(sValue)) nValue = CONVERT_MOST;
else if ("convert_basic".equals(sValue)) nValue = CONVERT_BASIC;
else if ("ignore_most".equals(sValue)) nValue = IGNORE_MOST;
else if ("ignore_all".equals(sValue)) nValue = IGNORE_ALL;
}
};
options[PAGE_FORMATTING] = new IntegerOption("page_formatting","convert_all") {
public void setString(String sValue) {
super.setString(sValue);
if ("convert_all".equals(sValue)) nValue = CONVERT_ALL;
else if ("convert_header_footer".equals(sValue)) nValue = CONVERT_HEADER_FOOTER;
else if ("ignore_all".equals(sValue)) nValue = IGNORE_ALL;
}
};
options[OTHER_STYLES] = new ContentHandlingOption("other_styles","accept");
options[IMAGE_CONTENT] = new ContentHandlingOption("image_content","accept");
options[TABLE_CONTENT] = new ContentHandlingOption("table_content","accept");
options[IGNORE_HARD_PAGE_BREAKS] = new BooleanOption("ignore_hard_page_breaks","false");
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[ALIGN_FRAMES] = new BooleanOption("align_frames","true");
options[FLOAT_FIGURES] = new BooleanOption("float_figures","false");
options[FLOAT_TABLES] = new BooleanOption("float_tables","false");
options[FLOAT_OPTIONS] = new Option("float_options","h");
options[FIGURE_SEQUENCE_NAME] = new BooleanOption("figure_sequence_name","");
options[TABLE_SEQUENCE_NAME] = new BooleanOption("table_sequence_name","");
options[IMAGE_OPTIONS] = new Option("image_options","");
options[REMOVE_GRAPHICS_EXTENSION] = new BooleanOption("remove_graphics_extension","false");
options[ORIGINAL_IMAGE_SIZE] = new BooleanOption("original_image_size","false");
options[SIMPLE_TABLE_LIMIT] = new IntegerOption("simple_table_limit","0") {
public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[NOTES] = new IntegerOption("notes","comment") {
public void setString(String sValue) {
super.setString(sValue);
if ("ignore".equals(sValue)) nValue = IGNORE;
else if ("comment".equals(sValue)) nValue = COMMENT;
else if ("pdfannotation".equals(sValue)) nValue = PDFANNOTATION;
else if ("marginpar".equals(sValue)) nValue = MARGINPAR;
else nValue = CUSTOM;
}
};
options[METADATA] = new BooleanOption("metadata","true");
options[TABSTOP] = new Option("tabstop","");
options[WRAP_LINES_AFTER] = new IntegerOption("wrap_lines_after","72") {
public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[SPLIT_LINKED_SECTIONS] = new BooleanOption("split_linked_sections","false");
options[SPLIT_TOPLEVEL_SECTIONS] = new BooleanOption("split_toplevel_sections","false");
options[SAVE_IMAGES_IN_SUBDIR] = new BooleanOption("save_images_in_subdir","false");
options[DEBUG] = new BooleanOption("debug","false");
// Headings for article class:
headingMap.setLevelData(1,"section",1);
headingMap.setLevelData(2,"subsection",2);
headingMap.setLevelData(3,"subsubsection",3);
headingMap.setLevelData(4,"paragraph",4);
headingMap.setLevelData(5,"subparagraph",5);
// Standard string replace:
// Fix french spacing; replace nonbreaking space
// right before em-dash, !, ?, : and ; (babel handles this)
stringReplace.put("\u00A0\u2014"," \u2014",ClassicI18n.readFontencs("any"));
stringReplace.put("\u00A0!"," !",ClassicI18n.readFontencs("any"));
stringReplace.put("\u00A0?"," ?",ClassicI18n.readFontencs("any"));
stringReplace.put("\u00A0:"," :",ClassicI18n.readFontencs("any"));
stringReplace.put("\u00A0;"," ;",ClassicI18n.readFontencs("any"));
// Right after opening guillemet and right before closing guillemet:
// Here we must *keep* the non-breaking space
// TODO: Use \og and \fg if the document contains french...
//stringReplace.put("\u00AB\u00A0","\u00AB ",I18n.readFontencs("any"));
//stringReplace.put("\u00A0\u00BB"," \u00BB",I18n.readFontencs("any"));
}
protected void readInner(Element elm) {
if (elm.getTagName().equals("style-map")) {
String sName = elm.getAttribute("name");
String sFamily = elm.getAttribute("family");
if (sFamily.length()==0) { // try old name
sFamily = elm.getAttribute("class");
}
String sBefore = elm.getAttribute("before");
String sAfter = elm.getAttribute("after");
boolean bLineBreak = !"false".equals(elm.getAttribute("line-break"));
boolean bVerbatim = "true".equals(elm.getAttribute("verbatim"));
if ("paragraph".equals(sFamily)) {
par.put(sName,sBefore,sAfter,bLineBreak,bVerbatim);
}
if ("paragraph-block".equals(sFamily)) {
String sNext = elm.getAttribute("next");
parBlock.put(sName,sBefore,sAfter,sNext,bVerbatim);
}
else if ("text".equals(sFamily)) {
text.put(sName,sBefore,sAfter,false,bVerbatim);
}
else if ("list".equals(sFamily)) {
list.put(sName,sBefore,sAfter);
}
else if ("listitem".equals(sFamily)) {
listItem.put(sName,sBefore,sAfter);
}
else if ("text-attribute".equals(sFamily)) {
textAttr.put(sName, sBefore, sAfter);
}
}
else if (elm.getTagName().equals("heading-map")) {
readHeadingMap(elm);
}
else if (elm.getTagName().equals("string-replace")) {
String sInput = elm.getAttribute("input");
String sLaTeXCode = elm.getAttribute("latex-code");
String sFontencs = elm.getAttribute("fontencs");
int nFontencs = ClassicI18n.readFontencs(sFontencs.length()>0 ? sFontencs : "any");
stringReplace.put(sInput,sLaTeXCode,nFontencs);
}
else if (elm.getTagName().equals("custom-preamble")) {
Node child = elm.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.TEXT_NODE) {
customPreamble.add(child.getNodeValue());
}
child = child.getNextSibling();
}
}
else if (elm.getTagName().equals("math-symbol-map")) {
String sName = elm.getAttribute("name");
String sLatex = elm.getAttribute("latex");
mathSymbols.put(sName,sLatex);
}
}
public void readHeadingMap(Element node) {
int nMaxLevel = Misc.getPosInteger(node.getAttribute("max-level"),0);
headingMap.reset(nMaxLevel);
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
Element elm = (Element) child;
if (elm.getTagName().equals("heading-level-map")) {
int nWriterLevel = Misc.getPosInteger(elm.getAttribute("writer-level"),1);
String sName = elm.getAttribute("name");
int nLevel = Misc.getPosInteger(elm.getAttribute("level"),0);
headingMap.setLevelData(nWriterLevel,sName,nLevel);
}
}
child = child.getNextSibling();
}
}
protected void writeInner(Document dom) {
// Write math symbol map
Enumeration msEnum = mathSymbols.keys();
while (msEnum.hasMoreElements()) {
String sName = (String) msEnum.nextElement();
String sLatex = (String) mathSymbols.get(sName);
Element msNode = dom.createElement("math-symbol-map");
msNode.setAttribute("name",sName);
msNode.setAttribute("latex",sLatex);
dom.getDocumentElement().appendChild(msNode);
}
writeStyleMap(dom,par,"paragraph");
writeStyleMap(dom,parBlock,"paragraph-block");
writeStyleMap(dom,text,"text");
writeStyleMap(dom,list,"list");
writeStyleMap(dom,listItem,"listitem");
writeStyleMap(dom,textAttr,"text-attribute");
Element hmNode = dom.createElement("heading-map");
hmNode.setAttribute("max-level",Integer.toString(headingMap.getMaxLevel()));
dom.getDocumentElement().appendChild(hmNode);
for (int i=1; i<=headingMap.getMaxLevel(); i++) {
Element hlmNode = dom.createElement("heading-level-map");
hlmNode.setAttribute("writer-level",Integer.toString(i));
hlmNode.setAttribute("name",headingMap.getName(i));
hlmNode.setAttribute("level",Integer.toString(headingMap.getLevel(i)));
hmNode.appendChild(hlmNode);
}
// TODO: Export string replacements
//String[] sInputStrings = stringReplace.getInputStrings();
/*
int nSize = sInputStrings.size();
for (int i=0; i<nSize; i++) {
String sInput = sInputStrings[i];
ReplacementTrieNode node = stringReplace.get(sInput);
Element srNode = dom.createElement("string-replace");
srNode.setAttribute("input",sInput);
srNode.setAttribute("latex-code",node.getLaTeXCode());
srNode.setAttribute("fontenc",I18n.writeFontencs(node.getFontencs()));
hmNode.appendChild(srNode);
}
*/
writeContent(dom,customPreamble,"custom-preamble");
}
private void writeStyleMap(Document dom, StyleMap sm, String sFamily) {
Enumeration smEnum = sm.getNames();
while (smEnum.hasMoreElements()) {
String sName = (String) smEnum.nextElement();
Element smNode = dom.createElement("style-map");
smNode.setAttribute("name",sName);
smNode.setAttribute("family",sFamily);
smNode.setAttribute("before",sm.getBefore(sName));
smNode.setAttribute("after",sm.getAfter(sName));
if (sm.getNext(sName)!=null) {
smNode.setAttribute("next",sm.getNext(sName));
}
if (!sm.getLineBreak(sName)) {
smNode.setAttribute("line-break","false");
}
if (sm.getVerbatim(sName)) {
smNode.setAttribute("verbatim","true");
}
dom.getDocumentElement().appendChild(smNode);
}
}
private void writeContent(Document dom, LinkedList list, String sElement) {
Element node = dom.createElement(sElement);
int nLen = list.size();
for (int i=0; i<nLen; i++) {
node.appendChild( dom.createTextNode( (String) list.get(i) ) );
}
dom.getDocumentElement().appendChild(node);
}
// Convenience accessor methods
// String replace
public ReplacementTrie getStringReplace() { return stringReplace; }
// Common options
public boolean debug() { return ((BooleanOption) options[DEBUG]).getValue(); }
// General options
public String getDocumentclass() { return options[DOCUMENTCLASS].getString(); }
public String getGlobalOptions() { return options[GLOBAL_OPTIONS].getString(); }
public int getBackend() { return ((IntegerOption) options[BACKEND]).getValue(); }
public int getInputencoding() { return ((IntegerOption) options[INPUTENCODING]).getValue(); }
public boolean multilingual() { return ((BooleanOption) options[MULTILINGUAL]).getValue(); }
public boolean greekMath() { return ((BooleanOption) options[GREEK_MATH]).getValue(); }
public boolean noPreamble() { return ((BooleanOption) options[NO_PREAMBLE]).getValue(); }
public boolean noIndex() { return ((BooleanOption) options[NO_INDEX]).getValue(); }
// Package options
public boolean useOoomath() { return ((BooleanOption) options[USE_OOOMATH]).getValue(); }
public boolean usePifont() { return ((BooleanOption) options[USE_PIFONT]).getValue(); }
public boolean useIfsym() { return ((BooleanOption) options[USE_IFSYM]).getValue(); }
public boolean useWasysym() { return ((BooleanOption) options[USE_WASYSYM]).getValue(); }
public boolean useBbding() { return ((BooleanOption) options[USE_BBDING]).getValue(); }
public boolean useEurosym() { return ((BooleanOption) options[USE_EUROSYM]).getValue(); }
public boolean useTipa() { return ((BooleanOption) options[USE_TIPA]).getValue(); }
public boolean useColor() { return ((BooleanOption) options[USE_COLOR]).getValue(); }
public boolean useColortbl() { return ((BooleanOption) options[USE_COLORTBL]).getValue(); }
public boolean useGeometry() { return ((BooleanOption) options[USE_GEOMETRY]).getValue(); }
public boolean useFancyhdr() { return ((BooleanOption) options[USE_FANCYHDR]).getValue(); }
public boolean useHyperref() { return ((BooleanOption) options[USE_HYPERREF]).getValue(); }
public boolean useCaption() { return ((BooleanOption) options[USE_CAPTION]).getValue(); }
public boolean useLongtable() { return ((BooleanOption) options[USE_LONGTABLE]).getValue(); }
public boolean useSupertabular() { return ((BooleanOption) options[USE_SUPERTABULAR]).getValue(); }
public boolean useTabulary() { return ((BooleanOption) options[USE_TABULARY]).getValue(); }
public boolean useEndnotes() { return ((BooleanOption) options[USE_ENDNOTES]).getValue(); }
public boolean useUlem() { return ((BooleanOption) options[USE_ULEM]).getValue(); }
public boolean useLastpage() { return ((BooleanOption) options[USE_LASTPAGE]).getValue(); }
public boolean useTitleref() { return ((BooleanOption) options[USE_TITLEREF]).getValue(); }
public boolean useOooref() { return ((BooleanOption) options[USE_OOOREF]).getValue(); }
public boolean useBibtex() { return ((BooleanOption) options[USE_BIBTEX]).getValue(); }
public String bibtexStyle() { return options[BIBTEX_STYLE].getString(); }
public String externalBibtexFiles() { return options[EXTERNAL_BIBTEX_FILES].getString(); }
// Formatting options
public int formatting() { return ((IntegerOption) options[FORMATTING]).getValue(); }
public int pageFormatting() { return ((IntegerOption) options[PAGE_FORMATTING]).getValue(); }
public int otherStyles() { return ((IntegerOption) options[OTHER_STYLES]).getValue(); }
public int imageContent() { return ((IntegerOption) options[IMAGE_CONTENT]).getValue(); }
public int tableContent() { return ((IntegerOption) options[TABLE_CONTENT]).getValue(); }
public boolean ignoreHardPageBreaks() { return ((BooleanOption) options[IGNORE_HARD_PAGE_BREAKS]).getValue(); }
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(); }
// Graphics options
public boolean alignFrames() { return ((BooleanOption) options[ALIGN_FRAMES]).getValue(); }
public boolean floatFigures() { return ((BooleanOption) options[FLOAT_FIGURES]).getValue(); }
public boolean floatTables() { return ((BooleanOption) options[FLOAT_TABLES]).getValue(); }
public String getFloatOptions() { return options[FLOAT_OPTIONS].getString(); }
public String getFigureSequenceName() { return options[FIGURE_SEQUENCE_NAME].getString(); }
public String getTableSequenceName() { return options[TABLE_SEQUENCE_NAME].getString(); }
public String getImageOptions() { return options[IMAGE_OPTIONS].getString(); }
public boolean removeGraphicsExtension() { return ((BooleanOption) options[REMOVE_GRAPHICS_EXTENSION]).getValue(); }
public boolean originalImageSize() { return ((BooleanOption) options[ORIGINAL_IMAGE_SIZE]).getValue(); }
// Tables
public int getSimpleTableLimit() { return ((IntegerOption) options[SIMPLE_TABLE_LIMIT]).getValue(); }
// Notes
public int notes() { return ((IntegerOption) options[NOTES]).getValue(); }
public String getNotesCommand() { return options[NOTES].getString(); }
// Metadata
public boolean metadata() { return ((BooleanOption) options[METADATA]).getValue(); }
// Tab stops
public String getTabstop() { return options[TABSTOP].getString(); }
// Files
public int getWrapLinesAfter() { return ((IntegerOption) options[WRAP_LINES_AFTER]).getValue(); }
public boolean splitLinkedSections() { return ((BooleanOption) options[SPLIT_LINKED_SECTIONS]).getValue(); }
public boolean splitToplevelSections() { return ((BooleanOption) options[SPLIT_TOPLEVEL_SECTIONS]).getValue(); }
public boolean saveImagesInSubdir() { return ((BooleanOption) options[SAVE_IMAGES_IN_SUBDIR]).getValue(); }
public Hashtable getMathSymbols() { return mathSymbols; }
public StyleMap getParStyleMap() { return par; }
public StyleMap getParBlockStyleMap() { return parBlock; }
public StyleMap getTextStyleMap() { return text; }
public StyleMap getListStyleMap() { return list; }
public StyleMap getListItemStyleMap() { return listItem; }
public StyleMap getTextAttributeStyleMap() { return textAttr; }
public HeadingMap getHeadingMap() { return headingMap; }
public LinkedList getCustomPreamble() { return customPreamble; }
}

View file

@ -0,0 +1,152 @@
/************************************************************************
*
* LaTeXDocument.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.xmerge.Document;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
* <p>Class representing a LaTeX document.</p>
*
*/
public class LaTeXDocument implements Document {
private static final String FILE_EXTENSION = ".tex";
private String sName;
private String sEncoding = "ASCII";
private int nWrap;
private LaTeXDocumentPortion contents;
/**
* <p>Constructs a new LaTeX Document.</p>
*
* <p>This new document is empty. Document data must added to the preamble and
* the body using appropriate methods.</p>
*
* @param sName The name of the <code>LaTeXDocument</code>.
* @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);
}
/**
* <p>This method is supposed to read <code>byte</code> data from the InputStream.
* Currently it does nothing, since we don't need it.</p>
*
* @param is InputStream containing a LaTeX data file.
*
* @throws IOException In case of any I/O errors.
*/
public void read(InputStream is) throws IOException {
// Do nothing.
}
/**
* <p>Returns the <code>Document</code> name with no file extension.</p>
*
* @return The <code>Document</code> name with no file extension.
*/
public String getName() {
return sName;
}
/**
* <p>Returns the <code>Document</code> name with file extension.</p>
*
* @return The <code>Document</code> name with file extension.
*/
public String getFileName() {
return new String(sName + FILE_EXTENSION);
}
/**
* <p>Writes out the <code>Document</code> content to the specified
* <code>OutputStream</code>.</p>
*
* <p>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.</p>
*
* @param os <code>OutputStream</code> to write out the
* <code>Document</code> 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();
}
/**
* <p> Set the output encoding to use when writing the document.</p>
*/
public void setEncoding(String sEncoding) { this.sEncoding = sEncoding; }
/**
* <p>Returns the <code>LaTeXDocumentPortion</code>, that contains the
* contents of the document.</p>
*
* @return The content <code>LaTeXDocumentPortion</code>.
*/
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;
}
}

View file

@ -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; i<nEnd; i++) { osw.write(s.charAt(i)); }
}
/** write the contents of a StringBuffer to the output */
private void writeBuffer(StringBuffer text, OutputStreamWriter osw, int nLineLen, String sNewline) throws IOException {
String s = text.toString();
int nLen = s.length();
int[] nBreakPoints = new int[100];
int nLastBPIndex = 99;
int nStart = 0;
while (nStart<nLen) {
// identify line and breakpoints
int nBPIndex = 0;
boolean bEscape = false;
boolean bComment = false;
int nNewline = nStart;
char c;
while (nNewline<nLen) {
if (nBPIndex==nLastBPIndex) {
nBreakPoints = Misc.doubleIntArray(nBreakPoints);
nLastBPIndex = nBreakPoints.length-1;
}
c = s.charAt(nNewline);
if (c=='\n') {
nBreakPoints[nBPIndex++] = nNewline;
break;
}
if (bEscape) { bEscape = false; }
else if (c=='\\') { bEscape = true; }
else if (c=='%') { bComment = true; }
else if (!bComment && c==' ') { nBreakPoints[nBPIndex++] = nNewline; }
nNewline++;
}
if (nBPIndex==nLastBPIndex) {
nBreakPoints = Misc.doubleIntArray(nBreakPoints);
nLastBPIndex = nBreakPoints.length-1;
}
if (nNewline==nLen) { nBreakPoints[nBPIndex++] = nNewline; }
// write out line
int nCurLineLen = nBreakPoints[0]-nStart;
writeSegment(s,nStart,nBreakPoints[0],osw);
for (int i=0; i<nBPIndex-1; i++) {
int nSegmentLen = nBreakPoints[i+1]-nBreakPoints[i];
if (nSegmentLen+nCurLineLen>nLineLen) {
// break line before this segment
osw.write(sNewline);
nCurLineLen = nSegmentLen;
}
else {
// segment fits in current line
osw.write(" ");
nCurLineLen += nSegmentLen;
}
writeSegment(s,nBreakPoints[i]+1,nBreakPoints[i+1],osw);
}
osw.write(sNewline);
nStart = nNewline+1;
}
}
/** write the contents of a StringBuffer to the output without wrap */
private void writeBuffer(StringBuffer text, OutputStreamWriter osw, String sNewline) throws IOException {
String s = text.toString();
int nLen = s.length();
int nStart = 0;
while (nStart<nLen) {
// identify line
int nNewline = nStart;
while (nNewline<nLen) {
if (s.charAt(nNewline)=='\n') { break; }
nNewline++;
}
// write out line
writeSegment(s,nStart,nNewline,osw);
osw.write(sNewline);
nStart = nNewline+1;
}
}
/** Write this portion to the output (note: nLineLen=0 means no wrap) */
public void write(OutputStreamWriter osw, int nLineLen, String sNewline) throws IOException {
int n = nodes.size();
for (int i=0; i<n; i++) {
if (nodes.get(i) instanceof LaTeXDocumentPortion) {
((LaTeXDocumentPortion) nodes.get(i)).write(osw,nLineLen,sNewline);
}
else if (bWrap && nLineLen>0) {
writeBuffer((StringBuffer) nodes.get(i),osw,nLineLen,sNewline);
}
else {
writeBuffer((StringBuffer) nodes.get(i),osw,sNewline);
}
}
if (!bEmpty) { // write current node as well
if (bWrap && nLineLen>0) {
writeBuffer(curText,osw,nLineLen,sNewline);
}
else {
writeBuffer(curText,osw,sNewline);
}
}
}
/** Return the content of this LaTeXDocumentStream as a string */
public String toString() {
StringBuffer buf = new StringBuffer();
int n = nodes.size();
for (int i=0; i<n; i++) {
if (nodes.get(i) instanceof LaTeXDocumentPortion) {
buf.append(((LaTeXDocumentPortion) nodes.get(i)).toString());
}
else {
buf.append(((StringBuffer) nodes.get(i)).toString());
}
}
if (!bEmpty) { // write current node as well
buf.append(curText.toString());
}
return buf.toString();
}
} // end class LaTeXDocumentPortion
// TO DO: consider StringBuffer->ByteArrayOutputStream (performance??)

View file

@ -0,0 +1,384 @@
/************************************************************************
*
* ListStyleConverter.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 java.util.Hashtable;
import writer2latex.util.*;
import writer2latex.office.*;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
/* This class creates LaTeX code from OOo list styles
*/
public class ListStyleConverter extends StyleConverter {
boolean bNeedSaveEnumCounter = false;
private Hashtable listStyleLevelNames = new Hashtable();
/** <p>Constructs a new <code>ListStyleConverter</code>.</p>
*/
public ListStyleConverter(OfficeReader ofr, LaTeXConfig config,
ConverterPalette palette) {
super(ofr,config,palette);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (config.formatting()>=LaTeXConfig.CONVERT_MOST || !styleNames.isEmpty()) {
decl.append("% List styles").nl();
// May need an extra counter to handle continued numbering in lists
if (bNeedSaveEnumCounter) {
decl.append("\\newcounter{saveenum}").nl();
}
// If we export formatting, we need some hooks from lists to paragraphs:
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
decl.append("\\newcommand\\writerlistleftskip{}").nl()
.append("\\newcommand\\writerlistparindent{}").nl()
.append("\\newcommand\\writerlistlabel{}").nl()
.append("\\newcommand\\writerlistremovelabel{")
.append("\\aftergroup\\let\\aftergroup\\writerlistparindent\\aftergroup\\relax")
.append("\\aftergroup\\let\\aftergroup\\writerlistlabel\\aftergroup\\relax}").nl();
}
super.appendDeclarations(pack,decl);
}
}
/** <p>Apply a list style to an ordered or unordered list.</p> */
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+"}");
}
}
/** <p>Apply a list style to a list item.</p> */
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 ","");
}
}
/** <p>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();
}
/** <p>Create "Writer style" lists based on a List Style.
<p>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();
}
}
/** <p>Create LaTeX list labels from an OOo list style. Examples:</p>
* <p>Bullets:</p>
* <pre>\newcommand\labelliststylei{\textbullet}
* \newcommand\labelliststyleii{*}
* \newcommand\labelliststyleiii{\textstylebullet{>}}</pre>
* <p>Numbering:</p>
* <pre>\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 )}}</pre>
*
* @param <code>style</code> the OOo list style to use
* @param <code>sName</code> an array of label basenames to use
* @param <code>nMaxLevel</code> the highest level in this numbering
* @param <code>bDeclareCounters</code> true if counters should be declared (they may
* exist already, eg. "section", "subsection"... or "enumi", "enumii"...
* @param <code>bRenewLabels</code> true if labels should be defined with \renewcommand
* @param <code>bUseTextStyle</code> true if labels should be formatted with the associated text style
* (rather than \newcommand).
* @param <code>ldp</code> the <code>LaTeXDocumentPortion</code> 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; j<i; j++) {
if (style.isNumber(j)) {
ldp.append(sNumFormat[j]).append(".");
}
}
ldp.append(sNumFormat[i]);
ldp.append("}").nl();
}
}
// Create labels (ie. define "\labelcountername"):
for (int i=1; i<=nMaxLevel; i++) {
ldp.append(bRenewLabels ? "\\renewcommand" : "\\newcommand")
.append("\\label").append(sName[i]).append("{");
// Apply text style if required
BeforeAfter baText = new BeforeAfter();
if (bUseTextStyle) {
String sStyleName = style.getLevelProperty(i,XMLString.TEXT_STYLE_NAME);
palette.getCharSc().applyTextStyle(sStyleName,baText,new Context());
}
// Create label content
if (style.isNumber(i)) {
String sPrefix = style.getLevelProperty(i,XMLString.STYLE_NUM_PREFIX);
String sSuffix = style.getLevelProperty(i,XMLString.STYLE_NUM_SUFFIX);
// Apply style
ldp.append(baText.getBefore());
if (sPrefix!=null) { ldp.append(sPrefix); }
ldp.append("\\the").append(sName[i]);
if (sSuffix!=null) { ldp.append(sSuffix); }
ldp.append(baText.getAfter());
}
else if (style.isBullet(i)) {
String sBullet = style.getLevelProperty(i,XMLString.TEXT_BULLET_CHAR);
// Apply style
ldp.append(baText.getBefore());
if (sBullet!=null) {
// Bullets are usually symbols, so this should be OK:
ldp.append(palette.getI18n().convert(sBullet,false,"en"));
}
ldp.append(baText.getAfter());
}
else {
// TODO: Support images!
ldp.append("\\textbullet");
}
ldp.append("}").nl();
}
}
/* Helper: Get a length property that defaults to 0cm. */
private String getLength(ListStyle style,int nLevel,String sProperty) {
String s = style.getLevelStyleProperty(nLevel,sProperty);
if (s==null) { return "0cm"; }
else { return s; }
}
/* Helper: Get display name, or original name if it doesn't exist */
private String getDisplayName(String sName) {
String sDisplayName = ofr.getListStyles().getDisplayName(sName);
return sDisplayName!=null ? sDisplayName : sName;
}
/* Helper: Convert OOo number format to LaTeX number format */
public static final String numFormat(String sFormat){
if ("1".equals(sFormat)) { return "\\arabic"; }
else if ("i".equals(sFormat)) { return "\\roman"; }
else if ("I".equals(sFormat)) { return "\\Roman"; }
else if ("a".equals(sFormat)) { return "\\alph"; }
else if ("A".equals(sFormat)) { return "\\Alph"; }
else { return null; }
}
}

View file

@ -0,0 +1,232 @@
/************************************************************************
*
* MathmlConverter.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.latex;
//import java.util.Hashtable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
//import writer2latex.latex.i18n.I18n;
import writer2latex.office.MIMETypes;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
import writer2latex.xmerge.EmbeddedObject;
import writer2latex.xmerge.EmbeddedXMLObject;
/**
* This class converts mathml nodes to LaTeX.
* (Actually it only converts the starmath annotation currently, if available).
*/
public final class MathmlConverter extends ConverterHelper {
private StarMathConverter smc;
private boolean bContainsFormulas = false;
public MathmlConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
smc = new StarMathConverter(palette.getI18n(),config);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bContainsFormulas) {
if (config.useOoomath()) {
pack.append("\\usepackage{ooomath}").nl();
}
else {
smc.appendDeclarations(pack,decl);
}
}
}
public String convert(Node settings, Node formula) {
// TODO: Use settings to determine display mode/text mode
// formula must be a math:math node
// First try to find a StarMath annotation
Node semantics = Misc.getChildByTagName(formula,XMLString.MATH_SEMANTICS);
if (semantics!=null) {
Node annotation = Misc.getChildByTagName(semantics,XMLString.MATH_ANNOTATION);
if (annotation!=null) {
String sStarMath = "";
if (annotation.hasChildNodes()) {
NodeList anl = annotation.getChildNodes();
int nLen = anl.getLength();
for (int i=0; i<nLen; i++) {
if (anl.item(i).getNodeType() == Node.TEXT_NODE) {
sStarMath+=anl.item(i).getNodeValue();
}
}
bContainsFormulas = true;
return smc.convert(sStarMath);
}
}
}
// No annotation was found. In this case we should convert the mathml,
// but currently we ignore the problem.
// TODO: Investigate if Vasil I. Yaroshevich's MathML->LaTeX
// 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; i<nLen; i++) {
char c = s.charAt(i);
if (c!='(' && c!=')' && c!='[' && c!=']' && c!='{' && c!='}' && c!=' ' && c!='\u00A0') {
// Characters except brackets and whitespace -> not a display
return false;
}
}
}
child = child.getNextSibling();
}
return true;
}
// TODO: Extend OfficeReader to handle frames
private Node getFormula(Node node) {
if (Misc.isElement(node,XMLString.DRAW_FRAME)) {
node=Misc.getFirstChildElement(node);
}
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 formuladoc = ((EmbeddedXMLObject) object).getContentDOM();
return Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
}
catch (org.xml.sax.SAXException e) {
e.printStackTrace();
}
catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
}
}
else { // flat xml, object is contained in node
return Misc.getChildByTagName(node,XMLString.MATH_MATH);
}
return null;
}
}

View file

@ -0,0 +1,391 @@
/************************************************************************
*
* NoteConverter.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.LinkedList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import writer2latex.util.Misc;
import writer2latex.util.ExportNameCollection;
import writer2latex.office.OfficeReader;
import writer2latex.office.PropertySet;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
/**
* <p>This class handles conversion of footnotes and endnotes, including
* references. It takes advantage of the packages <code>endnotes.sty</code>
* and <code>perpage.sty</code> if allowed in the configuration.</p>
*/
public class NoteConverter extends ConverterHelper {
private ExportNameCollection footnotenames = new ExportNameCollection(true);
private ExportNameCollection endnotenames = new ExportNameCollection(true);
private boolean bContainsEndnotes = false;
private boolean bContainsFootnotes = false;
// Keep track of footnotes (inside minipage etc.), that should be typeset later
private LinkedList postponedFootnotes = new LinkedList();
public NoteConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
}
/** <p>Append declarations needed by the <code>NoteConverter</code> to
* the preamble.
* @param pack the <code>LaTeXDocumentPortion</code> to which
* declarations of packages should be added (<code>\\usepackage</code>).
* @param decl the <code>LaTeXDocumentPortion</code> 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);
}
/** <p>Process a footnote (text:footnote tag)
* @param node The element containing the footnote
* @param ldp the <code>LaTeXDocumentPortion</code> 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; i<n; i++) {
ldp.append("\\stepcounter{footnote}\\footnotetext{");
traverseNoteBody((Element) postponedFootnotes.get(i),ldp,ic);
ldp.append("}").nl();
}
postponedFootnotes.clear();
}
}
/** <p>Process an endnote (text:endnote tag)
* @param node The element containing the endnote
* @param ldp the <code>LaTeXDocumentPortion</code> 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("}");
}
}
}
/** <p>Insert the endnotes into the documents.
* @param ldp the <code>LaTeXDocumentPortion</code> to which
* the endnotes should be added.
*/
public void insertEndnotes(LaTeXDocumentPortion ldp) {
if (bContainsEndnotes) {
ldp.append("\\clearpage").nl()
.append("\\theendnotes").nl();
}
}
/** <p>Process a note reference (text:note-ref tag, oasis)
* @param node The element containing the note reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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); }
}
/** <p>Process a footnote reference (text:footnote-ref tag)
* @param node The element containing the footnote reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Process an endnote reference (text:endnote-ref tag)
* @param node The element containing the endnote reference
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}
/** <p>Add a footnote name. The method <code>handleFootnote</code> includes
* a <code>\label</code> only if the footnote name is already known to the
* <code>NoteConverter</code>. 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); }
/** <p>Add an endnote name. The method <code>handleEndnote</code> includes
* a <code>\label</code> only if the endnote name is already known to the
* <code>NoteConverter</code>. 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 (i<len-1) {
if (nList.item(i+1).getNodeName().startsWith(XMLString.TEXT_)) {
ldp.append("\\par ");
}
else {
ldp.nl();
}
}
}
else if (nodeName.equals(XMLString.TEXT_LIST)) { // oasis
palette.getBlockCv().handleList(child,ldp,oc);
}
if (nodeName.equals(XMLString.TEXT_ORDERED_LIST)) {
palette.getBlockCv().handleList(child,ldp,oc);
}
if (nodeName.equals(XMLString.TEXT_UNORDERED_LIST)) {
palette.getBlockCv().handleList(child,ldp,oc);
}
}
}
}
}
// Convert footnotes configuration.
private void convertFootnotesConfiguration(LaTeXDocumentPortion ldp) {
// Note: Continuation notices are not supported in LaTeX
// TODO: Support text:footnotes-postion="document" (footnotes as endnotes)
// TODO: Support text:start-numbering-at="page" (footnpag.sty/footmisc.sty)
convertFootEndnotesConfiguration(ofr.getFootnotesConfiguration(),"foot",ldp);
}
// Convert endnotes configuration.
private void convertEndnotesConfiguration(LaTeXDocumentPortion ldp) {
// Note: Continuation notices are not supported in LaTeX
convertFootEndnotesConfiguration(ofr.getEndnotesConfiguration(),"end",ldp);
}
/* Convert {foot|end}notes configuration.
* Note: All {foot|end}notes are formatted with the default style for {foot|end}footnotes.
* (This doesn't conform with the file format specification, but in LaTeX
* all {foot|end}notes are usually formatted in a fixed style.)
*/
private void convertFootEndnotesConfiguration(PropertySet notes, String sType, LaTeXDocumentPortion ldp) {
if (config.formatting()<LaTeXConfig.CONVERT_BASIC) { return; }
String sTypeShort = sType.equals("foot") ? "fn" : "en";
if (notes==null) { return; }
ldp.append("% ").append(sType).append("notes configuration").nl()
.append("\\makeatletter").nl();
// The numbering style is controlled by \the{foot|end}note
String sFormat = notes.getProperty(XMLString.STYLE_NUM_FORMAT);
if (sFormat!=null) {
ldp.append("\\renewcommand\\the").append(sType).append("note{")
.append(ListStyleConverter.numFormat(sFormat))
.append("{").append(sType).append("note}}").nl();
}
// Number {foot|end}notes by sections
if ("chapter".equals(notes.getProperty(XMLString.TEXT_START_NUMBERING_AT))) {
ldp.append("\\@addtoreset{").append(sType).append("note}{section}").nl();
}
// Set start value offset (default 0)
int nStartValue = Misc.getPosInteger(notes.getProperty(XMLString.TEXT_START_VALUE),0);
if (nStartValue!=0) {
ldp.append("\\setcounter{").append(sType).append("note}{"+nStartValue+"}").nl();
}
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
// The formatting of the {foot|end}note citation is controlled by \@make{fn|en}mark
String sCitBodyStyle = notes.getProperty(XMLString.TEXT_CITATION_BODY_STYLE_NAME);
if (sCitBodyStyle!=null && ofr.getTextStyle(sCitBodyStyle)!=null) {
BeforeAfter baText = new BeforeAfter();
palette.getCharSc().applyTextStyle(sCitBodyStyle,baText,new Context());
ldp.append("\\renewcommand\\@make").append(sTypeShort).append("mark{\\mbox{")
.append(baText.getBefore())
.append("\\@the").append(sTypeShort).append("mark")
.append(baText.getAfter())
.append("}}").nl();
}
// The layout and formatting of the {foot|end}note is controlled by \@make{fn|en}text
String sCitStyle = notes.getProperty(XMLString.TEXT_CITATION_STYLE_NAME);
String sStyleName = notes.getProperty(XMLString.TEXT_DEFAULT_STYLE_NAME);
if (sStyleName!=null) {
BeforeAfter baText = new BeforeAfter();
palette.getCharSc().applyTextStyle(sCitStyle,baText,new Context());
StyleWithProperties style = ofr.getParStyle(sStyleName);
if (style!=null) {
BeforeAfter baPar = new BeforeAfter();
palette.getCharSc().applyHardCharFormatting(style,baPar);
ldp.append("\\renewcommand\\@make").append(sTypeShort)
.append("text[1]{\\noindent")
.append(baText.getBefore())
.append("\\@the").append(sTypeShort).append("mark\\ ")
.append(baText.getAfter())
.append(baPar.getBefore())
.append("#1")
.append(baPar.getAfter());
ldp.append("}").nl();
}
}
}
ldp.append("\\makeatother").nl();
}
}

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The package writer2latex.latex</title>
</head>
<body>
<p>This package contains LaTeX specific code.</p>
<p>It contains a <code>writerlatex.api.Converter</code> implementation for
conversion into LaTeX.</p>
<p>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).</p>
</body>
</html>

View file

@ -0,0 +1,596 @@
/************************************************************************
*
* 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-11-23)
*
*/
package writer2latex.latex;
import java.util.Enumeration;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.util.CSVList;
import writer2latex.util.Misc;
import writer2latex.office.*;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
// TODO: chngpage.sty??
/* This class creates LaTeX code from OOo page layouts/master pages
*/
public class PageStyleConverter extends StyleConverter {
// Value of attribute text:display of most recent text:chapter field
// This is used to handle chaptermarks in headings
private String sChapterField1 = null;
private String sChapterField2 = null;
// The page layout used for the page geometry
// (LaTeX only supports one page geometry per page)
private PageLayout mainPageLayout;
/** <p>Constructs a new <code>PageStyleConverter</code>.</p>
*/
public PageStyleConverter(OfficeReader ofr, LaTeXConfig config,
ConverterPalette palette) {
super(ofr,config,palette);
// Determine the main page master
MasterPage firstMasterPage = ofr.getFirstMasterPage();
String sPageLayoutName = null;
if (firstMasterPage!=null) {
MasterPage nextMasterPage = ofr.getMasterPage(
firstMasterPage.getProperty(XMLString.STYLE_NEXT_STYLE_NAME));
if (nextMasterPage!=null) {
sPageLayoutName = nextMasterPage.getPageLayoutName();
}
else {
sPageLayoutName = firstMasterPage.getPageLayoutName();
}
}
mainPageLayout = ofr.getPageLayout(sPageLayoutName);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (config.useFancyhdr()) { pack.append("\\usepackage{fancyhdr}").nl(); }
// The first master page must be known
MasterPage firstMasterPage = ofr.getFirstMasterPage();
if (firstMasterPage!=null) {
styleNames.addName(getDisplayName(firstMasterPage.getName()));
}
// Convert page geometry
convertPageMasterGeometry(pack,decl);
// Convert master pages
convertMasterPages(decl);
if (firstMasterPage!=null) {
BeforeAfter ba = new BeforeAfter();
applyMasterPage(firstMasterPage.getName(),ba);
decl.append(ba.getBefore());
}
}
public void setChapterField1(String s) { sChapterField1 = s; }
public void setChapterField2(String s) { sChapterField2 = s; }
public boolean isTwocolumn() {
return mainPageLayout!=null && mainPageLayout.getColCount()>1;
}
/** <p>Apply page break properties from a style.</p>
* @param style the style to use
* @param bInherit true if inheritance from parent style should be used
* @param ba a <code>BeforeAfter</code> 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);
}
/** <p>Use a Master Page (pagestyle in LaTeX)</p>
* @param sName name of the master page to use
* @param ba the <code>BeforeAfter</code> 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;
}
}

View file

@ -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;
/* <p>This class converts OpenDocument paragraphs (<code>text:p</code>) and
* paragraph styles/formatting into LaTeX</p>
* <p>Export of formatting depends on the option "formatting":</p>
* <ul>
* <li><code>ignore_all</code>
* <li><code>ignore_most</code>
* <li><code>convert_basic</code>
* <li><code>convert_most</code>
* <li><code>convert_all</code>
* </ul>
* <p>TODO: Captions and {foot|end}notes should also use this class
*/
public class ParConverter extends StyleConverter {
private boolean bNeedArrayBslash = false;
/** <p>Constructs a new <code>ParConverter</code>.</p>
*/
public ParConverter(OfficeReader ofr, LaTeXConfig config,
ConverterPalette palette) {
super(ofr,config,palette);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bNeedArrayBslash) {
// centering and raggedright redefines \\, fix this
// Note: aviods nameclash with tabularx (arraybackslash)
// TODO: Should perhaps choose to load tabularx instead?
decl.append("\\makeatletter").nl()
.append("\\newcommand\\arraybslash{\\let\\\\\\@arraycr}").nl()
.append("\\makeatother").nl();
}
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
// We typeset with \raggedbottom since OOo doesn't use rubber lengths
// TODO: Maybe turn vertical spacing from OOo into rubber lengths?
decl.append("\\raggedbottom").nl();
}
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
decl.append("% Paragraph styles").nl();
// First default paragraph style
palette.getCharSc().applyDefaultFont(ofr.getDefaultParStyle(),decl);
super.appendDeclarations(pack,decl);
}
}
/**
* <p> Process a text:p tag</p>
* @param node The text:h element node containing the heading
* @param ldp The <code>LaTeXDocumentPortion</code> 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));
}
/** <p>Use a paragraph style in LaTeX.</p>
* @param <code>sName</code> the name of the text style
* @param <code>ba</code> a <code>BeforeAfter</code> to put code into
* @param <code>context</code> the current context. This method will use and update the formatting context
* @param <code>bNoTextPar</code> 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));
}
/** <p>Convert a paragraph style to LaTeX. </p>
* <p>A soft style is declared in <code>styleDeclarations</code> as
* <code>\newenvironment...</code></p>
* <p>A hard style is used by applying LaTeX code directly</p>
* @param <code>sName</code> 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
/** <p>Apply line spacing from a style.</p>
* @param <code>style</code> the paragraph style to use
* @param <code>ba</code> a <code>BeforeAfter</code> 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+"}","");
}
/** <p>Helper: Create a horizontal border. Currently unused</p>
*/
/*private String createBorder(String sLeft, String sRight, String sTop,
String sHeight, String sColor) {
BeforeAfter baColor = new BeforeAfter();
palette.getColorCv().applyColor(sColor,false,baColor, new Context());
return "{\\setlength\\parindent{0pt}\\setlength\\leftskip{" + sLeft + "}"
+ "\\setlength\\baselineskip{0pt}\\setlength\\parskip{" + sHeight + "}"
+ baColor.getBefore()
+ "\\rule{\\textwidth-" + sLeft + "-" + sRight + "}{" + sHeight + "}"
+ baColor.getAfter()
+ "\\par}";
}*/
/** <p>Apply margin+alignment properties from a style.</p>
* @param <code>style</code> the paragraph style to use
* @param <code>ba</code> a <code>BeforeAfter</code> 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",""); }
}
/** <p>Apply all paragraph properties.</p>
* @param <code>style</code> the paragraph style to use
* @param <code>ba</code> a <code>BeforeAfter</code> 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);
}
}

View file

@ -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;
/** <p>This class creates LaTeX code from OOo sections.
* <p>Sections are converted to multicols environments using <code>multicol.sty</code>
*/
public class SectionConverter extends ConverterHelper {
// Do we need multicols.sty?
private boolean bNeedMulticol = false;
// Filenames for external sections
private ExportNameCollection fileNames = new ExportNameCollection(true);
/** <p>Constructs a new <code>SectionStyleConverter</code>.</p>
*/
public SectionConverter(OfficeReader ofr, LaTeXConfig config,
ConverterPalette palette) {
super(ofr,config,palette);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
if (bNeedMulticol) { pack.append("\\usepackage{multicol}").nl(); }
}
/** <p> Process a section (text:section tag)</p>
* @param node The element containing the section
* @param ldp the <code>LaTeXDocumentPortion</code> 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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,51 @@
/************************************************************************
*
* 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-09-08)
*
*/
package writer2latex.latex;
import writer2latex.latex.util.StyleMap;
import writer2latex.util.ExportNameCollection;
import writer2latex.office.OfficeReader;
/**
* <p>This is an abstract superclass for style converters.</p>
*/
public abstract class StyleConverter extends ConverterHelper {
// Names and maps + necessary declarations for these styles
protected ExportNameCollection styleNames = new ExportNameCollection(false);
protected StyleMap styleMap = new StyleMap();
protected LaTeXDocumentPortion declarations = new LaTeXDocumentPortion(false);
protected StyleConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
super(ofr,config,palette);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
decl.append(declarations);
}
}

View file

@ -0,0 +1,366 @@
/************************************************************************
*
* 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-11-23)
*
*/
package writer2latex.latex;
import org.w3c.dom.Element;
import writer2latex.util.*;
import writer2latex.office.*;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
/** <p>This class converts OpenDocument tables to LaTeX.</p>
* <p>The following LaTeX packages are used; some of them are optional</p>
* <p>array.sty, longtable.sty, supertabular.sty, tabulary.sty, hhline.sty,
* colortbl.sty.</p>
* <p>Options:</p>
* <ul>
* <li>use_longtable = true|false</li>
* <li>use_supertabular = true|false</li>
* <li>use_tabulary = true|false</li>
* <li>use_colortbl = true|false</li>
* <li>float_tables = true|false</li>
* <li>float_options = &lt;string&gt;</li>
* <li>table_content = accept|ignore|warning|error</li>
* </ul>
*
*/
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;
/** <p>Constructs a new <code>TableConverter</code>.</p>
*/
public TableConverter(OfficeReader ofr, LaTeXConfig config,
ConverterPalette palette) {
super(ofr,config,palette);
}
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
pack.append("\\usepackage{array}").nl(); // TODO: Make this optional
if (bNeedLongtable) { pack.append("\\usepackage{longtable}").nl(); }
if (bNeedSupertabular) { pack.append("\\usepackage{supertabular}").nl(); }
if (bNeedTabulary) { pack.append("\\usepackage{tabulary}").nl(); }
pack.append("\\usepackage{hhline}").nl(); // TODO: Make this optional
if (bNeedColortbl) { pack.append("\\usepackage{colortbl}").nl(); }
// Set padding for table cells (1mm is default in OOo!)
// For vertical padding we can only specify a relative size
if (bContainsTables) {
decl.append("\\setlength\\tabcolsep{1mm}").nl();
decl.append("\\renewcommand\\arraystretch{1.3}").nl();
}
}
// Export a lonely table caption
public void handleCaption(Element node, LaTeXDocumentPortion ldp, Context oc) {
ldp.append("\\captionof{table}");
palette.getCaptionCv().handleCaptionBody(node,ldp,oc,true);
}
/** <p> Process a table (table:table or table:sub-table tag)</p>
* @param node The element containing the table
* @param ldp the <code>LaTeXDocumentPortion</code> 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<nEnd; nRow++) {
// Export columns in this row
Context icRow = (Context) oc.clone();
BeforeAfter baRow = new BeforeAfter();
formatter.applyRowStyle(nRow,baRow,icRow);
if (!baRow.isEmpty()) {
ldp.append(baRow.getBefore());
if (!formatter.isSimple()) { ldp.nl(); }
}
int nCol = 0;
while (nCol<nColCount) {
Element cell = (Element) table.getCell(nRow,nCol);
if (XMLString.TABLE_TABLE_CELL.equals(cell.getNodeName())) {
Context icCell = (Context) icRow.clone();
BeforeAfter baCell = new BeforeAfter();
formatter.applyCellStyle(nRow,nCol,baCell,icCell);
ldp.append(baCell.getBefore());
if (nCol==nColCount-1) { icCell.setInLastTableColumn(true); }
palette.getBlockCv().traverseBlockText(cell,ldp,icCell);
ldp.append(baCell.getAfter());
}
// Otherwise ignore; the cell is covered by a \multicolumn entry.
// (table:covered-table-cell)
int nColSpan = Misc.getPosInteger(cell.getAttribute(
XMLString.TABLE_NUMBER_COLUMNS_SPANNED),1);
if (nCol+nColSpan<nColCount) {
if (formatter.isSimple()) { ldp.append(" & "); }
else { ldp.append(" &").nl(); }
}
nCol+=nColSpan;
}
ldp.append("\\\\").append(formatter.getInterrowMaterial(nRow+1));
// Add newline, except after last row
if (nRow<nEnd-1) { ldp.nl(); }
}
}
}
}

View file

@ -0,0 +1,451 @@
/************************************************************************
*
* TableFormatter.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.latex;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.util.*;
import writer2latex.office.*;
import writer2latex.latex.util.BeforeAfter;
import writer2latex.latex.util.Context;
/**
* <p>This class converts OOo table styles to LaTeX.</p>
* <p> In OOo the table style is distributed on table, column and cell styles.
* <p> In LaTeX we have to rearrange this information slightly, so this class
* takes care of that.</p>
*/
public class TableFormatter extends ConverterHelper {
//private boolean bApplyCellFormat;
private TableReader table;
private char[][] cAlign;
private char[] cGlobalAlign;
private boolean[][] bHBorder;
private boolean[][] bVBorder;
private boolean[] bGlobalVBorder;
private String[] sRowColor;
private String[][] sCellColor;
private String[] sColumnWidth;
private boolean bIsLongtable;
private boolean bIsSupertabular;
private boolean bIsTabulary;
private boolean bIsColortbl;
private boolean bIsSimple;
/** <p>Constructor: Create from a TableReader.</p>
*/
public TableFormatter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette,
TableReader table, boolean bAllowPageBreak, boolean bIsInTable) {
super(ofr,config,palette);
this.table = table;
//bApplyCellFormat = config.formatting()>=LaTeXConfig.CONVERT_MOST;
int nRowCount = table.getRowCount();
int nColCount = table.getColCount();
int nSimpleTableLimit = config.getSimpleTableLimit();
// Step 1: Collect alignment and identify simple tables
bIsSimple = true;
cAlign = new char[nRowCount][nColCount];
cGlobalAlign = new char[nColCount];
// Keep track of characters to be counted
int[] nPendingChars = new int[nRowCount];
int[] nPendingColSpan = new int[nRowCount];
int nTableWidth = 0;
for (int nCol=0; nCol<nColCount; nCol++) {
// Collect chars to be counted in this column
for (int nRow=0; nRow<nRowCount; nRow++) {
Element cell = table.getCell(nRow, nCol);
if (Misc.isElement(cell, XMLString.TABLE_TABLE_CELL)) {
// Now we're here: Collect alignment
if (OfficeReader.isSingleParagraph(cell)) {
Node par = Misc.getChildByTagName(cell,XMLString.TEXT_P);
StyleWithProperties style = ofr.getParStyle(Misc.getAttribute(par,XMLString.TEXT_STYLE_NAME));
cAlign[nRow][nCol] = 'l';
if (style!=null) {
String sAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true);
if ("center".equals(sAlign)) { cAlign[nRow][nCol] = 'c'; }
else if ("end".equals(sAlign)) { cAlign[nRow][nCol] = 'r'; }
}
}
else {
// Found cell with more than one paragraph
bIsSimple = false;
}
// Collect characters (the cell contains this many characters that should be distributed over that many columns)
nPendingChars[nRow] = OfficeReader.getCharacterCount(cell);
nPendingColSpan[nRow] = Misc.getPosInteger(cell.getAttribute(XMLString.TABLE_NUMBER_COLUMNS_SPANNED), 1);
}
}
// Determine the number of characters to count *now* (because they cannot be postponed to next column)
int nColChars = 0;
for (int nRow=0; nRow<nRowCount; nRow++) {
if (nPendingColSpan[nRow]==1) {
nColChars = Math.max(nColChars, nPendingChars[nRow]);
}
}
// Reduce pending chars and increase table width
nTableWidth += nColChars;
for (int nRow=0; nRow<nRowCount; nRow++) {
if (nPendingColSpan[nRow]>=1) {
nPendingChars[nRow] = Math.max(0, nPendingChars[nRow]-nColChars);
nPendingColSpan[nRow]--;
}
}
}
if (nTableWidth>nSimpleTableLimit) bIsSimple = false;
// Step 2: Create global alignment
for (int nCol=0; nCol<nColCount; nCol++) {
int nCenter = 0;
int nRight = 0;
for (int nRow=0; nRow<nRowCount; nRow++) {
if (cAlign[nRow][nCol]=='c') { nCenter++; }
else if (cAlign[nRow][nCol]=='r') { nRight++; }
}
cGlobalAlign[nCol] = 'l';
int nLeft = nColCount-nCenter-nRight;
if (nCenter>nLeft) {
if (nRight>nLeft) { cGlobalAlign[nCol] = 'r'; }
else { cGlobalAlign[nCol] = 'c'; }
}
else if (nRight>nLeft) {
cGlobalAlign[nCol] = 'r';
}
}
// Step 3: Initialize borders:
bHBorder = new boolean[nRowCount+1][nColCount];
for (int nRow=0; nRow<=nRowCount; nRow++) {
for (int nCol=0; nCol<nColCount; nCol++) {
bHBorder[nRow][nCol] = false;
}
}
bVBorder = new boolean[nRowCount][nColCount+1];
for (int nRow=0; nRow<nRowCount; nRow++) {
for (int nCol=0; nCol<=nColCount; nCol++) {
bVBorder[nRow][nCol] = false;
}
}
// Step 4: Collect borders from cell styles:
for (int nRow=0; nRow<nRowCount; nRow++) {
int nCol = 0;
while (nCol<nColCount) {
Node cell = table.getCell(nRow,nCol);
String sStyleName = Misc.getAttribute(cell,XMLString.TABLE_STYLE_NAME);
StyleWithProperties style = ofr.getCellStyle(sStyleName);
int nColSpan = Misc.getPosInteger(Misc.getAttribute(cell,
XMLString.TABLE_NUMBER_COLUMNS_SPANNED),1);
boolean bLeft = false;
boolean bRight = false;
boolean bTop = false;
boolean bBottom = false;
if (style!=null) {
String sBorder = style.getProperty(XMLString.FO_BORDER);
if (sBorder!=null && !"none".equals(sBorder)) {
bLeft = true; bRight = true; bTop = true; bBottom = true;
}
sBorder = style.getProperty(XMLString.FO_BORDER_LEFT);
if (sBorder!=null && !"none".equals(sBorder)) {
bLeft = true;
}
sBorder = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (sBorder!=null && !"none".equals(sBorder)) {
bRight = true;
}
sBorder = style.getProperty(XMLString.FO_BORDER_TOP);
if (sBorder!=null && !"none".equals(sBorder)) {
bTop = true;
}
sBorder = style.getProperty(XMLString.FO_BORDER_BOTTOM);
if (sBorder!=null && !"none".equals(sBorder)) {
bBottom = true;
}
}
bVBorder[nRow][nCol] |= bLeft;
bVBorder[nRow][nCol+nColSpan] |= bRight;
do {
bHBorder[nRow][nCol] |= bTop;
bHBorder[nRow+1][nCol] |= bBottom;
nCol++;
} while (--nColSpan>0);
}
}
// Step 5: Create global vertical borders based on simple majority
// (in order to minimize the number of \multicolum{1} entries)
bGlobalVBorder = new boolean[nColCount+1];
for (int nCol=0; nCol<=nColCount; nCol++) {
int nBalance = 0;
for (int nRow=0; nRow<nRowCount; nRow++) {
nBalance += bVBorder[nRow][nCol] ? 1 : -1;
}
bGlobalVBorder[nCol] = nBalance>0;
}
// Step 6: Get background colors
sRowColor = new String[nRowCount];
sCellColor = new String[nRowCount][nColCount];
if (config.useColortbl()) {
// Table background
String sTableColor = null;
StyleWithProperties tableStyle = ofr.getTableStyle(table.getTableStyleName());
if (tableStyle!=null) {
sTableColor = tableStyle.getProperty(XMLString.FO_BACKGROUND_COLOR);
}
// Row background
for (int nRow=0; nRow<nRowCount; nRow++) {
StyleWithProperties rowStyle = ofr.getRowStyle(table.getRow(nRow).getStyleName());
if (rowStyle!=null) {
sRowColor[nRow] = rowStyle.getProperty(XMLString.FO_BACKGROUND_COLOR);
}
if (sRowColor[nRow]==null) {
sRowColor[nRow] = sTableColor;
}
if (sRowColor[nRow]!=null) {
bIsColortbl = true;
}
}
// Cell background
for (int nRow=0; nRow<nRowCount; nRow++) {
for (int nCol=0; nCol<nColCount; nCol++) {
StyleWithProperties cellStyle = ofr.getCellStyle(Misc.getAttribute(table.getCell(nRow,nCol),XMLString.TABLE_STYLE_NAME));
if (cellStyle!=null) {
sCellColor[nRow][nCol] = cellStyle.getProperty(XMLString.FO_BACKGROUND_COLOR);
if (sCellColor[nRow][nCol]!=null) {
bIsColortbl = true;
if (sCellColor[nRow][nCol].equals(sRowColor[nRow])) {
// Avoid redundant cell background
sCellColor[nRow][nCol] = null;
}
}
}
}
}
}
// Step 7: Read column style information
sColumnWidth = new String[nColCount];
for (int nCol=0; nCol<nColCount; nCol++) {
StyleWithProperties colStyle
= ofr.getColumnStyle(table.getCol(nCol).getStyleName());
if (colStyle!=null) {
sColumnWidth[nCol]
= colStyle.getProperty(XMLString.STYLE_COLUMN_WIDTH);
}
if (sColumnWidth[nCol]==null) { // Emergency! should never happen!
sColumnWidth[nCol]="2cm";
}
}
// Step 8: Identify longtable, supertabular or tabulary
bIsLongtable = false; bIsSupertabular = false; bIsTabulary = false;
if (!table.isSubTable() && !bIsInTable) {
String sStyleName = table.getTableStyleName();
StyleWithProperties style = ofr.getTableStyle(sStyleName);
boolean bMayBreak = style==null ||
!"false".equals(style.getProperty(XMLString.STYLE_MAY_BREAK_BETWEEN_ROWS));
if (config.useLongtable() && bMayBreak && bAllowPageBreak) {
bIsLongtable = true;
}
else if (config.useSupertabular() && bMayBreak && bAllowPageBreak) {
bIsSupertabular = true;
}
else if (!bIsSimple && config.useTabulary()) {
bIsTabulary = true;
}
}
}
/** is this a longtable? */
public boolean isLongtable() { return bIsLongtable; }
/** is this a supertabular? */
public boolean isSupertabular() { return bIsSupertabular; }
/** is this a tabulary? */
public boolean isTabulary() { return bIsTabulary; }
/** is this a colortbl? */
public boolean isColortbl() { return bIsColortbl; }
/** is this a simple table (lcr columns rather than p{})? */
public boolean isSimple() { return bIsSimple; }
/**
* <p>Create table environment based on table style.</p>
* <p>Returns eg. "\begin{longtable}{m{2cm}|m{4cm}}", "\end{longtable}".</p>
*/
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; nCol<nColCount; nCol++){
if (bIsSimple) {
ba.add(Character.toString(cGlobalAlign[nCol]),"");
}
else if (!bIsTabulary) {
// note: The column width in OOo includes padding, which we subtract
ba.add("m{"+Misc.add(sColumnWidth[nCol],"-0.2cm")+"}","");
}
else {
ba.add("J","");
}
if (bGlobalVBorder[nCol+1]) { ba.add("|",""); }
}
ba.add("}","");
}
/** <p>Create interrow material</p> */
public String getInterrowMaterial(int nRow) {
int nColCount = table.getColCount();
int nCount = 0;
for (int nCol=0; nCol<nColCount; nCol++) {
if (bHBorder[nRow][nCol]) { nCount++; }
}
if (nCount==0) { // no borders at this row
return "";
}
else if (nCount==nColCount) { // complete set of borders
return "\\hline";
}
else { // individual borders for each column
StringBuffer buf = new StringBuffer();
buf.append("\\hhline{");
for (int nCol=0; nCol<nColCount; nCol++) {
if (bHBorder[nRow][nCol]) { buf.append("-"); }
else { buf.append("~"); }
}
buf.append("}");
/* TODO: hhline.sty should be optional, and i not used, do as before:
boolean bInCline = false;
for (int nCol=0; nCol<nColCount; nCol++) {
if (bInCline && !bHBorder[nRow][nCol]) { // close \cline
buf.append(nCol).append("}");
bInCline = false;
}
else if (!bInCline && bHBorder[nRow][nCol]) { // open \cline
buf.append("\\cline{").append(nCol+1).append("-");
bInCline = true;
}
}
if (bInCline) { buf.append(nColCount).append("}"); }
*/
return buf.toString();
}
}
/** <p>Get material to put before a table row (background color)
*/
public void applyRowStyle(int nRow, BeforeAfter ba, Context context) {
palette.getColorCv().applyBgColor("\\rowcolor",sRowColor[nRow],ba,context);
}
/** Get material to put before and after a table cell.
* In case of columnspan or different borders this will contain a \multicolumn command.
*/
public void applyCellStyle(int nRow, int nCol, BeforeAfter ba, Context context) {
Node cell = table.getCell(nRow,nCol);
int nColSpan = Misc.getPosInteger(Misc.getAttribute(cell,
XMLString.TABLE_NUMBER_COLUMNS_SPANNED),1);
// Construct column declaration as needed
boolean bNeedLeft = (nCol==0) && (bVBorder[nRow][0]!=bGlobalVBorder[0]);
boolean bNeedRight = bVBorder[nRow][nCol+1]!=bGlobalVBorder[nCol+1];
boolean bNeedAlign = bIsSimple && cGlobalAlign[nCol]!=cAlign[nRow][nCol];
// calculate column width
String sTotalColumnWidth = sColumnWidth[nCol];
for (int i=nCol+1; i<nCol+nColSpan; i++) {
sTotalColumnWidth = Misc.add(sTotalColumnWidth,sColumnWidth[i]);
}
sTotalColumnWidth = Misc.add(sTotalColumnWidth,"-0.2cm");
if (bNeedAlign || bNeedLeft || bNeedRight || nColSpan>1) {
ba.add("\\multicolumn{"+nColSpan+"}{","");
if (nCol==0 && bVBorder[nRow][0]) { ba.add("|",""); }
if (bIsSimple) {
ba.add(Character.toString(cAlign[nRow][nCol]),"");
}
else {
ba.add("m{"+sTotalColumnWidth+"}","");
}
if (bVBorder[nRow][nCol+nColSpan]) { ba.add("|",""); }
ba.add("}{","}");
}
palette.getColorCv().applyBgColor("\\cellcolor",sCellColor[nRow][nCol],ba,context);
}
}

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- clean.xml
This is a sample configuration file for Writer2LaTeX.
The options are set to produce a clean
LaTeX file from an arbitrary Writer document
- at the expense of loss of formatting.
An even cleaner LaTeX file is produced with ultraclean.xml.
-->
<config>
<option name="documentclass" value="article" />
<option name="backend" value="generic" />
<option name="inputencoding" value="ascii" />
<option name="multilingual" value="false" />
<option name="use_ooomath" value="false" />
<option name="use_color" value="true" />
<option name="use_colortbl" value="false" />
<option name="use_geometry" value="true" />
<option name="use_fancyhdr" value="false" />
<option name="use_hyperref" value="true" />
<option name="use_caption" value="true" />
<option name="use_endnotes" value="false" />
<option name="use_bibtex" value="true" />
<option name="bibtex_style" value="plain" />
<option name="formatting" value="ignore_most" />
<option name="page_formatting" value="convert_geometry" />
<option name="ignore_empty_paragraphs" value="true" />
<option name="ignore_hard_page_breaks" value="false" />
<option name="ignore_hard_line_breaks" value="false" />
<option name="ignore_double_spaces" value="true" />
<option name="debug" value="false" />
<heading-map max-level="5">
<heading-level-map writer-level="1" name="section" level="1" />
<heading-level-map writer-level="2" name="subsection" level="2" />
<heading-level-map writer-level="3" name="subsubsection" level="3" />
<heading-level-map writer-level="4" name="paragraph" level="4" />
<heading-level-map writer-level="5" name="subparagraph" level="5" />
</heading-map>
<custom-preamble />
<!-- Style maps: These rules defines how styles in OOo are mapped to LaTeX code.
A number of predefined Writer styles are converted -->
<!-- "Title" is mapped to \maketitle. If the user chooses to export meta data,
the author and date will be inserted automatically -->
<style-map name="Title" class="paragraph" before="\title{" after="}&#10;\maketitle" line-break="false" />
<!-- "Quotations" is mapped to a quotation environment -->
<style-map name="Quotations" family="paragraph-block" next="Quotations" before="\begin{quotation}" after="\end{quotation}" />
<style-map name="Quotations" family="paragraph" before="" after="" />
<!-- Preformatted Text is mapped to a verbatim environment
Note the attribute verbatim, which instructs OOo to output the content
verbatim (characters not available in the inputencoding will be replaced
by question marks; other content will be lost). -->
<style-map name="Preformatted Text" family="paragraph-block" next="Preformatted Text" before="\begin{verbatim}" after="\end{verbatim}" />
<style-map name="Preformatted Text" family="paragraph" before="" after="" verbatim="true" />
<!-- "Horizontal line" is mapped to a \hrule -->
<style-map name="Horizontal Line" family="paragraph" before="" after="&#10;\begin{center}\hrule\end{center}" />
<!-- "Emphasis" text style is mapped to \emph -->
<style-map name="Emphasis" family="text" before="\emph{" after="}" />
<!-- "Strong Emphasis" text style is mapped to \textbf -->
<style-map name="Strong Emphasis" family="text" before="\textbf{" after="}" />
<!-- "Teletype" text style is mapped to \texttt -->
<style-map name="Teletype" family="text" before="\texttt{" after="}" />
<!-- "List Heading" and "List Contents" are mapped to a description environment -->
<style-map name="List Heading" family="paragraph-block" next="List Heading;List Contents" before="\begin{description}" after="\end{description}"/>
<style-map name="List Heading" family="paragraph" before="\item[" after="]" line-break="false" />
<style-map name="List Contents" family="paragraph" before="" after="" />
</config>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- default.xml
This is a sample configuration file for Writer2LaTeX.
It sets no options, thus using defaults everywhere
-->
<config/>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- pdfprint.xml
This is a sample configuration file for Writer2LaTeX.
The output will be for pdfTeX, using all the packages pifont, ifsym,
wasysym, eurosym, hyperref, endnotes and ulem. -->
<config>
<option name="documentclass" value="article" />
<option name="backend" value="pdftex" />
<option name="inputencoding" value="ascii" />
<option name="use_geometry" value="true" />
<option name="use_fancyhdr" value="true" />
<option name="use_ooomath" value="true" />
<option name="use_pifont" value="true" />
<option name="use_ifsym" value="true" />
<option name="use_wasysym" value="true" />
<option name="use_eurosym" value="true" />
<option name="use_color" value="true" />
<option name="use_colortbl" value="true" />
<option name="use_hyperref" value="true" />
<option name="use_endnotes" value="true" />
<option name="use_ulem" value="true" />
<option name="use_lastpage" value="true" />
<option name="formatting" value="convert_all" />
<option name="page_formatting" value="convert_all" />
<option name="ignore_empty_paragraphs" value="false" />
<option name="ignore_hard_page_breaks" value="false" />
<option name="ignore_hard_line_breaks" value="false" />
<option name="ignore_double_spaces" value="false" />
<option name="debug" value="false" />
<heading-map max-level="5">
<heading-level-map writer-level="1" name="section" level="1" />
<heading-level-map writer-level="2" name="subsection" level="2" />
<heading-level-map writer-level="3" name="subsubsection" level="3" />
<heading-level-map writer-level="4" name="paragraph" level="4" />
<heading-level-map writer-level="5" name="subparagraph" level="5" />
</heading-map>
<!-- We add \sloppy to avoid overful hboxes. To get better results,
this should be removed and overful hboxes fixed by hand. -->
<custom-preamble>\sloppy</custom-preamble>
</config>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- pdfscreen.xml
This is a sample configuration file for Writer2LaTeX.
The output will be for pdfTeX, using all the packages pifont, ifsym,
wasysym, eurosym, hyperref, endnotes and ulem.
The package pdfscreen.sty will be loaded to create a pdf file
suitable for viewing on screen. -->
<config>
<option name="documentclass" value="article" />
<option name="backend" value="pdftex" />
<option name="inputencoding" value="ascii" />
<option name="use_ooomath" value="true" />
<option name="use_pifont" value="true" />
<option name="use_ifsym" value="true" />
<option name="use_wasysym" value="true" />
<option name="use_bbding" value="false" />
<option name="use_eurosym" value="true" />
<option name="use_color" value="true" />
<option name="use_colortbl" value="true" />
<option name="use_hyperref" value="true" />
<option name="use_endnotes" value="true" />
<option name="use_ulem" value="true" />
<option name="use_lastpage" value="true" />
<option name="formatting" value="convert_all" />
<option name="page_formatting" value="ignore_all" />
<option name="ignore_empty_paragraphs" value="false" />
<option name="ignore_hard_page_breaks" value="false" />
<option name="ignore_hard_line_breaks" value="false" />
<option name="ignore_double_spaces" value="true" />
<option name="debug" value="false" />
<heading-map max-level="5">
<heading-level-map writer-level="1" name="section" level="1" />
<heading-level-map writer-level="2" name="subsection" level="2" />
<heading-level-map writer-level="3" name="subsubsection" level="3" />
<heading-level-map writer-level="4" name="paragraph" level="4" />
<heading-level-map writer-level="5" name="subparagraph" level="5" />
</heading-map>
<!-- load pdfscreen.sty with suitable options. (Note that export of page
formatting is disabled above; pdfscreen.sty takes care of page setup.)
The lines are relatively short, so we add \sloppy to avoid overful hboxes.
-->
<custom-preamble>\usepackage{palatino}
\usepackage[bluelace,screen,nopanel,sectionbreak]{pdfscreen}
%\hypersetup{pdfpagemode={FullScreen}}
\margins{0.5in}{0.5in}{0.5in}{0.5in}
\screensize{6in}{8in}
\sloppy</custom-preamble>
</config>

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ultraclean.xml
This is a sample configuration file for Writer2LaTeX.
The options are set to produce the cleanest possible
LaTeX file from an arbitrary Writer document
- by removing practically all formatting.
-->
<config>
<option name="documentclass" value="article" />
<option name="backend" value="generic" />
<option name="inputencoding" value="ascii" />
<option name="multilingual" value="false" />
<option name="use_ooomath" value="false" />
<option name="use_color" value="false" />
<option name="use_colortbl" value="false" />
<option name="use_geometry" value="false" />
<option name="use_fancyhdr" value="false" />
<option name="use_hyperref" value="false" />
<option name="use_caption" value="true" />
<option name="use_endnotes" value="false" />
<option name="use_bibtex" value="true" />
<option name="bibtex_style" value="plain" />
<option name="formatting" value="ignore_all" />
<option name="page_formatting" value="ignore_all" />
<option name="ignore_empty_paragraphs" value="true" />
<option name="ignore_hard_page_breaks" value="true" />
<option name="ignore_hard_line_breaks" value="true" />
<option name="ignore_double_spaces" value="true" />
<option name="debug" value="false" />
<heading-map max-level="5">
<heading-level-map writer-level="1" name="section" level="1" />
<heading-level-map writer-level="2" name="subsection" level="2" />
<heading-level-map writer-level="3" name="subsubsection" level="3" />
<heading-level-map writer-level="4" name="paragraph" level="4" />
<heading-level-map writer-level="5" name="subparagraph" level="5" />
</heading-map>
<custom-preamble />
<!-- Style maps: These rules defines how styles in OOo are mapped to LaTeX code.
A number of predefined Writer styles are converted -->
<!-- "Title" is mapped to \maketitle. If the user chooses to export meta data,
the author and date will be inserted automatically -->
<style-map name="Title" class="paragraph" before="\title{" after="}&#10;\maketitle" line-break="false" />
<!-- "Quotations" is mapped to a quotation environment -->
<style-map name="Quotations" family="paragraph-block" next="Quotations" before="\begin{quotation}" after="\end{quotation}" />
<style-map name="Quotations" family="paragraph" before="" after="" />
<!-- Preformatted Text is mapped to a verbatim environment
Note the attribute verbatim, which instructs OOo to output the content
verbatim (characters not available in the inputencoding will be replaced
by question marks; other content will be lost). -->
<style-map name="Preformatted Text" family="paragraph-block" next="Preformatted Text" before="\begin{verbatim}" after="\end{verbatim}" />
<style-map name="Preformatted Text" family="paragraph" before="" after="" verbatim="true" />
<!-- "Horizontal line" is mapped to a \hrule -->
<style-map name="Horizontal Line" family="paragraph" before="" after="&#10;\begin{center}\hrule\end{center}" />
<!-- "Emphasis" text style is mapped to \emph -->
<style-map name="Emphasis" family="text" before="\emph{" after="}" />
<!-- "Strong Emphasis" text style is mapped to \textbf -->
<style-map name="Strong Emphasis" family="text" before="\textbf{" after="}" />
<!-- "Teletype" text style is mapped to \texttt -->
<style-map name="Teletype" family="text" before="\texttt{" after="}" />
<!-- "List Heading" and "List Contents" are mapped to a description environment -->
<style-map name="List Heading" family="paragraph-block" next="List Heading;List Contents" before="\begin{description}" after="\end{description}"/>
<style-map name="List Heading" family="paragraph" before="\item[" after="]" line-break="false" />
<style-map name="List Contents" family="paragraph" before="" after="" />
</config>

Some files were not shown because too many files have changed in this diff Show more