Remove latex code
This commit is contained in:
parent
0570002006
commit
1b0e0ace67
76 changed files with 4 additions and 24210 deletions
|
@ -1,480 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ApplicationsDialog.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.sun.star.awt.XContainerWindowEventHandler;
|
||||
import com.sun.star.awt.XDialog;
|
||||
import com.sun.star.awt.XDialogProvider2;
|
||||
import com.sun.star.awt.XWindow;
|
||||
import com.sun.star.lang.XMultiComponentFactory;
|
||||
import com.sun.star.lang.XServiceInfo;
|
||||
import com.sun.star.uno.AnyConverter;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
import com.sun.star.lib.uno.helper.WeakBase;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogAccess;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.FilePicker;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.StreamGobbler;
|
||||
|
||||
/** This class provides a UNO component which implements the configuration
|
||||
* of applications for the Writer2LaTeX toolbar
|
||||
*/
|
||||
public final class ApplicationsDialog
|
||||
extends WeakBase
|
||||
implements XServiceInfo, XContainerWindowEventHandler {
|
||||
|
||||
private XComponentContext xContext;
|
||||
private FilePicker filePicker;
|
||||
|
||||
private ExternalApps externalApps;
|
||||
|
||||
/** The component will be registered under this name.
|
||||
*/
|
||||
public static String __serviceName = "org.openoffice.da.writer2latex.ApplicationsDialog"; //$NON-NLS-1$
|
||||
|
||||
/** The component should also have an implementation name.
|
||||
*/
|
||||
public static String __implementationName = "org.openoffice.da.comp.writer2latex.ApplicationsDialog"; //$NON-NLS-1$
|
||||
|
||||
/** Create a new ApplicationsDialog */
|
||||
public ApplicationsDialog(XComponentContext xContext) {
|
||||
this.xContext = xContext;
|
||||
externalApps = new ExternalApps(xContext);
|
||||
filePicker = new FilePicker(xContext);
|
||||
}
|
||||
|
||||
// **** Implement XContainerWindowEventHandler
|
||||
|
||||
public boolean callHandlerMethod(XWindow xWindow, Object event, String sMethod)
|
||||
throws com.sun.star.lang.WrappedTargetException {
|
||||
XDialog xDialog = (XDialog)UnoRuntime.queryInterface(XDialog.class, xWindow);
|
||||
DialogAccess dlg = new DialogAccess(xDialog);
|
||||
|
||||
try {
|
||||
if (sMethod.equals("external_event") ){ //$NON-NLS-1$
|
||||
return handleExternalEvent(dlg, event);
|
||||
}
|
||||
else if (sMethod.equals("AfterExportChange")) { //$NON-NLS-1$
|
||||
return changeProcessingLevel(dlg);
|
||||
}
|
||||
else if (sMethod.equals("ApplicationChange")) { //$NON-NLS-1$
|
||||
return changeApplication(dlg);
|
||||
}
|
||||
else if (sMethod.equals("UseDefaultChange")) { //$NON-NLS-1$
|
||||
return useDefaultChange(dlg) && updateApplication(dlg);
|
||||
}
|
||||
else if (sMethod.equals("BrowseClick")) { //$NON-NLS-1$
|
||||
return browseForExecutable(dlg);
|
||||
}
|
||||
else if (sMethod.equals("ExecutableUnfocus")) { //$NON-NLS-1$
|
||||
return updateApplication(dlg);
|
||||
}
|
||||
else if (sMethod.equals("OptionsUnfocus")) { //$NON-NLS-1$
|
||||
return updateApplication(dlg);
|
||||
}
|
||||
else if (sMethod.equals("AutomaticClick")) { //$NON-NLS-1$
|
||||
return autoConfigure(dlg);
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.uno.RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
throw new com.sun.star.lang.WrappedTargetException(sMethod, this, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedMethodNames() {
|
||||
String[] sNames = { "external_event", "AfterExportChange", "ApplicationChange", "BrowseClick", "ExecutableUnfocus", "OptionsUnfocus", "AutomaticClick" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
|
||||
return sNames;
|
||||
}
|
||||
|
||||
// **** 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;
|
||||
}
|
||||
|
||||
// **** Event handlers
|
||||
|
||||
private boolean handleExternalEvent(DialogAccess dlg, Object aEventObject)
|
||||
throws com.sun.star.uno.Exception {
|
||||
try {
|
||||
String sMethod = AnyConverter.toString(aEventObject);
|
||||
if (sMethod.equals("ok")) { //$NON-NLS-1$
|
||||
externalApps.save();
|
||||
return true;
|
||||
} else if (sMethod.equals("back") || sMethod.equals("initialize")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.load();
|
||||
updateProcessingLevel(dlg);
|
||||
return changeApplication(dlg);
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.lang.IllegalArgumentException e) {
|
||||
throw new com.sun.star.lang.IllegalArgumentException(
|
||||
"Method external_event requires a string in the event object argument.", this,(short) -1); //$NON-NLS-1$
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean changeProcessingLevel(DialogAccess dlg) {
|
||||
externalApps.setProcessingLevel(dlg.getListBoxSelectedItem("AfterExport")); //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateProcessingLevel(DialogAccess dlg) {
|
||||
dlg.setListBoxSelectedItem("AfterExport", externalApps.getProcessingLevel()); //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean changeApplication(DialogAccess dlg) {
|
||||
String sAppName = getSelectedAppName(dlg);
|
||||
if (sAppName!=null) {
|
||||
String[] s = externalApps.getApplication(sAppName);
|
||||
dlg.setComboBoxText("Executable", s[0]); //$NON-NLS-1$
|
||||
dlg.setComboBoxText("Options", s[1]); //$NON-NLS-1$
|
||||
dlg.setCheckBoxStateAsBoolean("UseDefault", externalApps.getUseDefaultApplication(sAppName)); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("UseDefault", externalApps.isViewer(sAppName)); //$NON-NLS-1$
|
||||
useDefaultChange(dlg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useDefaultChange(DialogAccess dlg) {
|
||||
boolean bCustomApp = !dlg.getCheckBoxStateAsBoolean("UseDefault"); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("ExecutableLabel", bCustomApp); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("Executable", bCustomApp); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("OptionsLabel", bCustomApp); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("Options", bCustomApp); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BrowseButton", bCustomApp); //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean browseForExecutable(DialogAccess dlg) {
|
||||
String sPath = filePicker.getPath();
|
||||
if (sPath!=null) {
|
||||
try {
|
||||
dlg.setComboBoxText("Executable", new File(new URI(sPath)).getCanonicalPath()); //$NON-NLS-1$
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
}
|
||||
updateApplication(dlg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updateApplication(DialogAccess dlg) {
|
||||
String sAppName = getSelectedAppName(dlg);
|
||||
if (sAppName!=null) {
|
||||
externalApps.setApplication(sAppName, dlg.getComboBoxText("Executable"), dlg.getComboBoxText("Options")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setUseDefaultApplication(sAppName, dlg.getCheckBoxStateAsBoolean("UseDefault")); //$NON-NLS-1$
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean autoConfigure(DialogAccess dlg) {
|
||||
String sOsName = System.getProperty("os.name"); //$NON-NLS-1$
|
||||
String sOsVersion = System.getProperty("os.version"); //$NON-NLS-1$
|
||||
String sOsArch = System.getProperty("os.arch"); //$NON-NLS-1$
|
||||
StringBuilder info = new StringBuilder();
|
||||
info.append(Messages.getString("ApplicationsDialog.configresults")+":\n\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
info.append(Messages.getString("ApplicationsDialog.systemident")+" "+sOsName+" "+Messages.getString("ApplicationsDialog.version")+" "+sOsVersion+ " (" + sOsArch +")\n\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
|
||||
if (sOsName.startsWith("Windows")) { //$NON-NLS-1$
|
||||
autoConfigureWindows(dlg, info);
|
||||
}
|
||||
else {
|
||||
autoConfigureUnix(dlg, info);
|
||||
}
|
||||
displayAutoConfigInfo(info.toString());
|
||||
changeApplication(dlg);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void displayAutoConfigInfo(String sText) {
|
||||
XDialog xDialog = getDialog("W2LDialogs2.AutoConfigInfo"); //$NON-NLS-1$
|
||||
if (xDialog!=null) {
|
||||
DialogAccess info = new DialogAccess(xDialog);
|
||||
info.setTextFieldText("Info", sText); //$NON-NLS-1$
|
||||
xDialog.execute();
|
||||
xDialog.endExecute();
|
||||
}
|
||||
}
|
||||
|
||||
private XDialog getDialog(String sDialogName) {
|
||||
XMultiComponentFactory xMCF = xContext.getServiceManager();
|
||||
try {
|
||||
Object provider = xMCF.createInstanceWithContext(
|
||||
"com.sun.star.awt.DialogProvider2", xContext); //$NON-NLS-1$
|
||||
XDialogProvider2 xDialogProvider = (XDialogProvider2)
|
||||
UnoRuntime.queryInterface(XDialogProvider2.class, provider);
|
||||
String sDialogUrl = "vnd.sun.star.script:"+sDialogName+"?location=application"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return xDialogProvider.createDialogWithHandler(sDialogUrl, this);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSelectedAppName(DialogAccess dlg) {
|
||||
short nItem = dlg.getListBoxSelectedItem("Application"); //$NON-NLS-1$
|
||||
//String sAppName = null;
|
||||
switch (nItem) {
|
||||
case 0: return ExternalApps.LATEX;
|
||||
case 1: return ExternalApps.PDFLATEX;
|
||||
case 2: return ExternalApps.XELATEX;
|
||||
case 3: return ExternalApps.DVIPS;
|
||||
case 4: return ExternalApps.BIBTEX;
|
||||
case 5: return ExternalApps.MAKEINDEX;
|
||||
//case 6: return ExternalApps.MK4HT;
|
||||
case 6: return ExternalApps.DVIVIEWER;
|
||||
case 7: return ExternalApps.PDFVIEWER;
|
||||
case 8: return ExternalApps.POSTSCRIPTVIEWER;
|
||||
}
|
||||
return "???"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// **** Automatic configuration of applications for Windows systems (assuming MikTeX)
|
||||
|
||||
private void autoConfigureWindows(DialogAccess dlg, StringBuilder info) {
|
||||
String sMikTeXPath = getMikTeXPath();
|
||||
|
||||
// Configure TeX and friends + yap (DVi viewer) + TeXworks (PDF viewer)
|
||||
boolean bFoundTexworks = false;
|
||||
if (sMikTeXPath!=null) {
|
||||
info.append(Messages.getString("ApplicationsDialog.foundmiktex")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.LATEX, "latex", "--interaction=batchmode %s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.PDFLATEX, "pdflatex", "--interaction=batchmode %s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.XELATEX, "xelatex", "--interaction=batchmode %s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.DVIPS, "dvips", "%s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.BIBTEX, "bibtex", "%s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.MAKEINDEX, "makeindex", "%s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//configureMikTeX(sMikTeXPath, ExternalApps.MK4HT, "mk4ht", "%c %s", info, true);
|
||||
configureMikTeX(sMikTeXPath, ExternalApps.DVIVIEWER, "yap", "--single-instance %s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setUseDefaultApplication(ExternalApps.DVIVIEWER, false);
|
||||
// MikTeX 2.8 provides texworks for pdf viewing
|
||||
bFoundTexworks = configureMikTeX(sMikTeXPath, ExternalApps.PDFVIEWER, "texworks", "%s", info, true); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
else {
|
||||
info.append(Messages.getString("ApplicationsDialog.failedtofindmiktex")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
info.append(Messages.getString("ApplicationsDialog.miktexdefaultconfig")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.LATEX, "latex", "--interaction=batchmode %s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.PDFLATEX, "pdflatex", "--interaction=batchmode %s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.XELATEX, "xelatex", "--interaction=batchmode %s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.DVIPS, "dvips", "%s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.BIBTEX, "bibtex", "%s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setApplication(ExternalApps.MAKEINDEX, "makeindex", "%s"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//externalApps.setApplication(ExternalApps.MK4HT, "mk4ht", "%c %s");
|
||||
externalApps.setUseDefaultApplication(ExternalApps.DVIVIEWER, true);
|
||||
}
|
||||
externalApps.setUseDefaultApplication(ExternalApps.PDFVIEWER, !bFoundTexworks);
|
||||
info.append("\n"); //$NON-NLS-1$
|
||||
|
||||
// Configure gsview (PostScript viewer and fall back viewer for PDF)
|
||||
String sGsview = getGsviewPath();
|
||||
if (sGsview!=null) {
|
||||
info.append(Messages.getString("ApplicationsDialog.foundgsview")+" - "+Messages.getString("ApplicationsDialog.ok")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
externalApps.setApplication(ExternalApps.POSTSCRIPTVIEWER, sGsview, "-e \"%s\""); //$NON-NLS-1$
|
||||
if (!bFoundTexworks) {
|
||||
externalApps.setApplication(ExternalApps.PDFVIEWER, sGsview, "-e \"%s\""); //$NON-NLS-1$
|
||||
externalApps.setUseDefaultApplication(ExternalApps.PDFVIEWER, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!bFoundTexworks) {
|
||||
info.append(Messages.getString("ApplicationsDialog.pdfdefaultviewer")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
info.append(Messages.getString("ApplicationsDialog.psdefaultviewer")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
externalApps.setUseDefaultApplication(ExternalApps.POSTSCRIPTVIEWER, sGsview!=null);
|
||||
}
|
||||
|
||||
// Windows: Get the path to the MikTeX bin directory
|
||||
private String getMikTeXPath() {
|
||||
String[] sPaths = System.getenv("PATH").split(";"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
for (String s : sPaths) {
|
||||
if (s.toLowerCase().indexOf("miktex")>-1 && containsExecutable(s,"latex.exe")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return s;
|
||||
}
|
||||
}
|
||||
for (String s : sPaths) {
|
||||
if (containsExecutable(s,"latex.exe")) { //$NON-NLS-1$
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Windows: Get the path to the gsview executable
|
||||
private String getGsviewPath() {
|
||||
String sProgramFiles = System.getenv("ProgramFiles"); //$NON-NLS-1$
|
||||
if (sProgramFiles!=null) {
|
||||
if (containsExecutable(sProgramFiles+"\\ghostgum\\gsview","gsview32.exe")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return sProgramFiles+"\\ghostgum\\gsview\\gsview32.exe"; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Windows: Test that the given path contains a given executable
|
||||
private boolean containsExecutable(String sPath,String sExecutable) {
|
||||
File dir = new File(sPath);
|
||||
if (dir.exists() && dir.canRead()) {
|
||||
File exe = new File(dir,sExecutable);
|
||||
return exe.exists();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Windows: Configure a certain MikTeX application
|
||||
private boolean configureMikTeX(String sPath, String sName, String sAppName, String sArguments, StringBuilder info, boolean bRequired) {
|
||||
File app = new File(new File(sPath),sAppName+".exe"); //$NON-NLS-1$
|
||||
if (app.exists()) {
|
||||
externalApps.setApplication(sName, sAppName, sArguments);
|
||||
info.append(" "+Messages.getString("ApplicationsDialog.found")+" "+sName+": "+sAppName+" - "+Messages.getString("ApplicationsDialog.ok")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
|
||||
return true;
|
||||
}
|
||||
else if (bRequired) {
|
||||
externalApps.setApplication(sName, "???", "???"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
info.append(" "+Messages.getString("ApplicationsDialog.failedtofind")+" "+sName+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// **** Automatic configuration of applications for other systems (assuming unix-like systems)
|
||||
|
||||
private void autoConfigureUnix(DialogAccess dlg, StringBuilder info) {
|
||||
// Assume that the "which" command is supported
|
||||
configureApp(ExternalApps.LATEX, "latex", "--interaction=batchmode %s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureApp(ExternalApps.PDFLATEX, "pdflatex", "--interaction=batchmode %s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureApp(ExternalApps.XELATEX, "xelatex", "--interaction=batchmode %s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureApp(ExternalApps.DVIPS, "dvips", "%s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureApp(ExternalApps.BIBTEX, "bibtex", "%s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
configureApp(ExternalApps.MAKEINDEX, "makeindex", "%s",info); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//configureApp(ExternalApps.MK4HT, "mk4ht", "%c %s",info);
|
||||
// We have several possible viewers
|
||||
String[] sDviViewers = {"evince", "okular", "xdvi"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
configureViewer(ExternalApps.DVIVIEWER, sDviViewers, "%s",info); //$NON-NLS-1$
|
||||
String[] sPdfViewers = {"evince", "okular", "xpdf"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
configureViewer(ExternalApps.PDFVIEWER, sPdfViewers, "%s",info); //$NON-NLS-1$
|
||||
String[] sPsViewers = {"evince", "okular", "ghostview"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
configureViewer(ExternalApps.POSTSCRIPTVIEWER, sPsViewers, "%s",info); //$NON-NLS-1$
|
||||
|
||||
// Maybe add some info for Debian/Ubuntu users, e.g.
|
||||
// sudo apt-get install texlive
|
||||
// sudo apt-get install texlive-xetex
|
||||
// sudo apt-get install texlive-latex-extra
|
||||
// sudo apt-get install tex4ht
|
||||
}
|
||||
|
||||
// Unix: Test to determine whether a certain application is available in the OS
|
||||
// Requires "which", hence Unix only
|
||||
private boolean hasApp(String sAppName) {
|
||||
try {
|
||||
Vector<String> command = new Vector<String>();
|
||||
command.add("which"); //$NON-NLS-1$
|
||||
command.add(sAppName);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(command);
|
||||
Process proc = pb.start();
|
||||
|
||||
// Gobble the error stream of the application
|
||||
StreamGobbler errorGobbler = new
|
||||
StreamGobbler(proc.getErrorStream(), "ERROR"); //$NON-NLS-1$
|
||||
|
||||
// Gobble the output stream of the application
|
||||
StreamGobbler outputGobbler = new
|
||||
StreamGobbler(proc.getInputStream(), "OUTPUT"); //$NON-NLS-1$
|
||||
|
||||
errorGobbler.start();
|
||||
outputGobbler.start();
|
||||
|
||||
// The application exists if the process exits with 0
|
||||
return proc.waitFor()==0;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unix: Configure a certain application, testing and reporting the availability
|
||||
private boolean configureApp(String sName, String sAppName, String sArguments, StringBuilder info) {
|
||||
if (hasApp(sAppName)) {
|
||||
externalApps.setApplication(sName, sAppName, sArguments);
|
||||
externalApps.setUseDefaultApplication(sName, false);
|
||||
if (info!=null) {
|
||||
info.append(Messages.getString("ApplicationsDialog.found")+" "+sAppName+" - "+Messages.getString("ApplicationsDialog.ok")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
externalApps.setApplication(sName, "???", "???"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
externalApps.setUseDefaultApplication(sName, false);
|
||||
if (info!=null) {
|
||||
info.append(Messages.getString("ApplicationsDialog.failedtofind")+" "+sAppName+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unix: Configure a certain application, testing and reporting the availability
|
||||
// This variant uses an array of potential apps
|
||||
private boolean configureViewer(String sName, String[] sAppNames, String sArguments, StringBuilder info) {
|
||||
for (String sAppName : sAppNames) {
|
||||
if (configureApp(sName, sAppName, sArguments, null)) {
|
||||
info.append(Messages.getString("ApplicationsDialog.found")+" "+ExternalApps.getUIAppName(sName)+": "+sAppName+" - "+Messages.getString("ApplicationsDialog.ok")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
|
||||
return true;
|
||||
}
|
||||
}
|
||||
externalApps.setUseDefaultApplication(sName, true);
|
||||
info.append(Messages.getString("ApplicationsDialog.usingdefaultapp")+" "+ExternalApps.getUIAppName(sName)+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,758 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BibTeXDialog.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-28)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sun.star.awt.XDialog;
|
||||
import com.sun.star.awt.XDialogProvider2;
|
||||
import com.sun.star.beans.PropertyValue;
|
||||
import com.sun.star.beans.PropertyVetoException;
|
||||
import com.sun.star.beans.UnknownPropertyException;
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.container.NoSuchElementException;
|
||||
import com.sun.star.container.XEnumeration;
|
||||
import com.sun.star.container.XEnumerationAccess;
|
||||
import com.sun.star.container.XIndexAccess;
|
||||
import com.sun.star.frame.XFrame;
|
||||
import com.sun.star.lang.IllegalArgumentException;
|
||||
import com.sun.star.lang.IndexOutOfBoundsException;
|
||||
import com.sun.star.lang.WrappedTargetException;
|
||||
import com.sun.star.lang.XMultiComponentFactory;
|
||||
import com.sun.star.lang.XMultiServiceFactory;
|
||||
import com.sun.star.lang.XServiceInfo;
|
||||
import com.sun.star.text.XDependentTextField;
|
||||
import com.sun.star.text.XDocumentIndex;
|
||||
import com.sun.star.text.XDocumentIndexesSupplier;
|
||||
import com.sun.star.text.XText;
|
||||
import com.sun.star.text.XTextDocument;
|
||||
import com.sun.star.text.XTextField;
|
||||
import com.sun.star.text.XTextFieldsSupplier;
|
||||
import com.sun.star.text.XTextViewCursor;
|
||||
import com.sun.star.text.XTextViewCursorSupplier;
|
||||
import com.sun.star.ui.dialogs.ExecutableDialogResults;
|
||||
import com.sun.star.uno.AnyConverter;
|
||||
import com.sun.star.uno.Exception;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
import org.jbibtex.ParseException;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogAccess;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogBase;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.MessageBox;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
import writer2latex.latex.i18n.ClassicI18n;
|
||||
import writer2latex.office.BibMark;
|
||||
import writer2latex.office.BibMark.EntryType;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/** This class provides a UNO dialog to insert a BibTeX bibliographic reference
|
||||
*/
|
||||
public class BibTeXDialog extends DialogBase implements com.sun.star.lang.XInitialization {
|
||||
|
||||
// **** Data used for component registration
|
||||
|
||||
/** The component will be registered under this service name
|
||||
*/
|
||||
public static String __serviceName = "org.openoffice.da.writer2latex.BibTeXDialog"; //$NON-NLS-1$
|
||||
|
||||
/** The implementation name of the component
|
||||
*/
|
||||
public static String __implementationName = "org.openoffice.da.comp.writer2latex.BibTeXDialog"; //$NON-NLS-1$
|
||||
|
||||
// **** Member variables
|
||||
|
||||
// The current frame (passed at initialization)
|
||||
XFrame xFrame = null;
|
||||
|
||||
// The BibTeX directory (passed at initialization)
|
||||
File bibTeXDirectory = null;
|
||||
|
||||
// The encoding for BibTeX files (set in constructor from the registry)
|
||||
String sBibTeXJavaEncoding = null;
|
||||
|
||||
// Cache of BibTeX files in the BibTeX directory
|
||||
File[] files = null;
|
||||
|
||||
// Cache of the current BibTeX file
|
||||
BibTeXReader currentFile = null;
|
||||
|
||||
// **** Implement com.sun.star.lang.XInitialization
|
||||
|
||||
// We expect to get the current frame and a comma separated list of BibTeX files to use
|
||||
public void initialize( Object[] objects )
|
||||
throws com.sun.star.uno.Exception {
|
||||
for (Object object : objects) {
|
||||
if (object instanceof XFrame) {
|
||||
xFrame = UnoRuntime.queryInterface(XFrame.class, object);
|
||||
}
|
||||
if (object instanceof String) {
|
||||
bibTeXDirectory = new File((String) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **** Extend DialogBase
|
||||
|
||||
/** Create a new BibTeXDialog */
|
||||
public BibTeXDialog(XComponentContext xContext) {
|
||||
super(xContext);
|
||||
sBibTeXJavaEncoding = getBibTeXJavaEncoding();
|
||||
}
|
||||
|
||||
private String getBibTeXJavaEncoding() {
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
try {
|
||||
Object view = registry.getRegistryView(BibliographyDialog.REGISTRY_PATH, false);
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
int nBibTeXEncoding = XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXEncoding"); //$NON-NLS-1$
|
||||
registry.disposeRegistryView(view);
|
||||
return ClassicI18n.writeJavaEncoding(nBibTeXEncoding);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Failed to get registry view
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Return the name of the library containing the dialog
|
||||
*/
|
||||
@Override public String getDialogLibraryName() {
|
||||
return "W2LDialogs2"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Return the name of the dialog within the library
|
||||
*/
|
||||
@Override public String getDialogName() {
|
||||
return "BibTeXEntry"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override public void initialize() {
|
||||
reload(null);
|
||||
}
|
||||
|
||||
@Override public void endDialog() {
|
||||
}
|
||||
|
||||
// **** Implement XDialogEventHandler
|
||||
|
||||
@Override public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
|
||||
clearUpdateLabel();
|
||||
if (sMethod.equals("FileChange")) { //$NON-NLS-1$
|
||||
// The user has selected another BibTeX file
|
||||
fileChange();
|
||||
}
|
||||
else if (sMethod.equals("EntryChange")) { //$NON-NLS-1$
|
||||
// The user has selected another BibTeX entry
|
||||
entryChange();
|
||||
}
|
||||
else if (sMethod.equals("New")) { //$NON-NLS-1$
|
||||
// Create a new BibTeX file
|
||||
newFile();
|
||||
}
|
||||
else if (sMethod.equals("Edit")) { //$NON-NLS-1$
|
||||
// Edit the current BibTeX file
|
||||
edit();
|
||||
}
|
||||
else if (sMethod.equals("Reload")) { //$NON-NLS-1$
|
||||
// Reload the BibTeX files in the dialog
|
||||
reload(null);
|
||||
}
|
||||
else if (sMethod.equals("InsertReference")) { //$NON-NLS-1$
|
||||
// Insert a reference to the current BibTeX entry
|
||||
insertReference();
|
||||
}
|
||||
else if (sMethod.equals("Update")) { //$NON-NLS-1$
|
||||
// Update all reference in the document
|
||||
update();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public String[] getSupportedMethodNames() {
|
||||
String[] sNames = { "FileChange", "EntryChange", "New", "Edit", "Reload", "InsertReference", "Update" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
|
||||
return sNames;
|
||||
}
|
||||
|
||||
// **** Implement the UI functions
|
||||
|
||||
// Clear the contents of the update info label
|
||||
private void clearUpdateLabel() {
|
||||
setLabelText("UpdateLabel","");
|
||||
}
|
||||
|
||||
// (Re)load the list of BibTeX files
|
||||
private void reload(String sSelectedFileName) {
|
||||
String sFile = null;
|
||||
if (sSelectedFileName!=null) {
|
||||
// Select a new file name
|
||||
sFile = sSelectedFileName;
|
||||
}
|
||||
else {
|
||||
// Remember the previous selection, if any
|
||||
short nSelectedFile = getListBoxSelectedItem("File"); //$NON-NLS-1$
|
||||
if (nSelectedFile>=0 && files[nSelectedFile]!=null) {
|
||||
sFile = getListBoxStringItemList("File")[nSelectedFile]; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
if (bibTeXDirectory!=null && bibTeXDirectory.isDirectory()) {
|
||||
// Populate the file list based on the BibTeX directory
|
||||
files = bibTeXDirectory.listFiles(
|
||||
new FilenameFilter() {
|
||||
public boolean accept(File file, String sName) { return sName!=null && sName.endsWith(".bib"); } //$NON-NLS-1$
|
||||
}
|
||||
);
|
||||
int nFileCount = files.length;
|
||||
String[] sFileNames = new String[nFileCount];
|
||||
|
||||
// Select either the first or the previous item
|
||||
short nFile = 0;
|
||||
for (short i=0; i<nFileCount; i++) {
|
||||
sFileNames[i] = files[i].getName();
|
||||
if (sFileNames[i].equals(sFile)) { nFile = i; }
|
||||
}
|
||||
|
||||
setListBoxStringItemList("File", sFileNames); //$NON-NLS-1$
|
||||
setListBoxSelectedItem("File",(short)nFile); //$NON-NLS-1$
|
||||
|
||||
if (nFileCount>0) {
|
||||
setControlEnabled("FileLabel",true); //$NON-NLS-1$
|
||||
setControlEnabled("File",true); //$NON-NLS-1$
|
||||
setControlEnabled("EntryLabel",true); //$NON-NLS-1$
|
||||
setControlEnabled("Entry",true); //$NON-NLS-1$
|
||||
setControlEnabled("Edit",true); //$NON-NLS-1$
|
||||
setControlEnabled("Insert",true); //$NON-NLS-1$
|
||||
setControlEnabled("Update",true); //$NON-NLS-1$
|
||||
|
||||
fileChange();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The directory did not contain any BibTeX files
|
||||
setControlEnabled("FileLabel",false); //$NON-NLS-1$
|
||||
setControlEnabled("File",false); //$NON-NLS-1$
|
||||
setControlEnabled("EntryLabel",false); //$NON-NLS-1$
|
||||
setControlEnabled("Entry",false); //$NON-NLS-1$
|
||||
setControlEnabled("Edit",false); //$NON-NLS-1$
|
||||
setControlEnabled("Insert",false); //$NON-NLS-1$
|
||||
setControlEnabled("Update",false); //$NON-NLS-1$
|
||||
setLabelText("EntryInformation",Messages.getString("BibTeXDialog.nobibtexfiles")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
// Update the list of entries based on the current selection in the file list
|
||||
private void fileChange() {
|
||||
// Remember current entry selection, if any
|
||||
String sEntry = null;
|
||||
short nEntry = getListBoxSelectedItem("Entry"); //$NON-NLS-1$
|
||||
if (nEntry>=0) {
|
||||
sEntry = getListBoxStringItemList("Entry")[nEntry]; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// Parse the selected file
|
||||
int nFile = getListBoxSelectedItem("File"); //$NON-NLS-1$
|
||||
if (nFile>=0) {
|
||||
try {
|
||||
currentFile = new BibTeXReader(files[nFile],sBibTeXJavaEncoding);
|
||||
} catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
currentFile = null;
|
||||
} catch (ParseException e) {
|
||||
System.err.println(e.getMessage());
|
||||
currentFile = null;
|
||||
}
|
||||
|
||||
if (currentFile!=null) {
|
||||
// Populate the entry list with the keys from the current file, if any
|
||||
String[] sCurrentKeys = currentFile.getEntries().keySet().toArray(new String[0]);
|
||||
setListBoxStringItemList("Entry", sCurrentKeys); //$NON-NLS-1$
|
||||
if (sCurrentKeys.length>0) {
|
||||
// Select either the first or the previous entry
|
||||
nEntry = 0;
|
||||
if (sEntry!=null) {
|
||||
int nEntryCount = sCurrentKeys.length;
|
||||
for (short i=0; i<nEntryCount; i++) {
|
||||
if (sEntry.equals(sCurrentKeys[i])) {
|
||||
nEntry = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
setListBoxSelectedItem("Entry",nEntry); //$NON-NLS-1$
|
||||
setControlEnabled("EntryLabel",true); //$NON-NLS-1$
|
||||
setControlEnabled("Entry",true); //$NON-NLS-1$
|
||||
setControlEnabled("Insert",true); //$NON-NLS-1$
|
||||
entryChange();
|
||||
}
|
||||
else { // No entries, disable controls
|
||||
setControlEnabled("EntryLabel",false); //$NON-NLS-1$
|
||||
setControlEnabled("Entry",false); //$NON-NLS-1$
|
||||
setControlEnabled("Insert",false); //$NON-NLS-1$
|
||||
setLabelText("EntryInformation",Messages.getString("BibTeXDialog.noentries")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
setControlEnabled("Edit",true); //$NON-NLS-1$
|
||||
}
|
||||
else { // Failed to parse, disable controls
|
||||
setListBoxStringItemList("Entry", new String[0]); //$NON-NLS-1$
|
||||
setControlEnabled("EntryLabel",false); //$NON-NLS-1$
|
||||
setControlEnabled("Entry",false); //$NON-NLS-1$
|
||||
setControlEnabled("Edit",false); //$NON-NLS-1$
|
||||
setControlEnabled("Insert",false); //$NON-NLS-1$
|
||||
setLabelText("EntryInformation",Messages.getString("BibTeXDialog.errorreadingfile")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the entry information based on the current selection in the entry list
|
||||
private void entryChange() {
|
||||
BibMark bibMark = getCurrentEntry();
|
||||
if (bibMark!=null) {
|
||||
String sAuthor = bibMark.getField(EntryType.author);
|
||||
if (sAuthor==null) { sAuthor = ""; } //$NON-NLS-1$
|
||||
String sTitle = bibMark.getField(EntryType.title);
|
||||
if (sTitle==null) { sTitle = ""; } //$NON-NLS-1$
|
||||
String sPublisher = bibMark.getField(EntryType.publisher);
|
||||
if (sPublisher==null) { sPublisher = ""; } //$NON-NLS-1$
|
||||
String sYear = bibMark.getField(EntryType.year);
|
||||
if (sYear==null) { sYear = ""; } //$NON-NLS-1$
|
||||
setLabelText("EntryInformation", sAuthor+"\n"+sTitle+"\n"+sPublisher+"\n"+sYear); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
}
|
||||
else {
|
||||
setLabelText("EntryInformation", Messages.getString("BibTeXDialog.noinformation")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the currently selected entry as a reference in the text document
|
||||
private void insertReference() {
|
||||
insertReference(getCurrentEntry());
|
||||
}
|
||||
|
||||
// Create a new BibTeX file
|
||||
private void newFile() {
|
||||
String sFileName = getFileName();
|
||||
if (sFileName!=null) {
|
||||
if (!sFileName.equals(".bib")) { //$NON-NLS-1$
|
||||
File file = new File(bibTeXDirectory,sFileName);
|
||||
try {
|
||||
if (!file.createNewFile() && xFrame!=null) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.thefile")+" "+sFileName+" "+Messages.getString("BibTeXDialog.alreadyexists")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
reload(sFileName);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
else if (xFrame!=null) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.filenameempty")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a BibTeX file name from the user (possibly modified to a TeX friendly name)
|
||||
private String getFileName() {
|
||||
XDialog xDialog=getNewDialog();
|
||||
if (xDialog!=null) {
|
||||
DialogAccess ndlg = new DialogAccess(xDialog);
|
||||
ndlg.setListBoxStringItemList("Name", new String[0]); //$NON-NLS-1$
|
||||
String sResult = null;
|
||||
if (xDialog.execute()==ExecutableDialogResults.OK) {
|
||||
DialogAccess dlg = new DialogAccess(xDialog);
|
||||
sResult = dlg.getTextFieldText("Name"); //$NON-NLS-1$
|
||||
}
|
||||
xDialog.endExecute();
|
||||
if (sResult!=null && !sResult.toLowerCase().endsWith(".bib")) { //$NON-NLS-1$
|
||||
sResult = sResult+".bib"; //$NON-NLS-1$
|
||||
}
|
||||
return Misc.makeTeXFriendly(sResult,"bibliography"); //$NON-NLS-1$
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the new dialog (reused from the configuration dialog)
|
||||
protected XDialog getNewDialog() {
|
||||
XMultiComponentFactory xMCF = xContext.getServiceManager();
|
||||
try {
|
||||
Object provider = xMCF.createInstanceWithContext("com.sun.star.awt.DialogProvider2", xContext); //$NON-NLS-1$
|
||||
XDialogProvider2 xDialogProvider = (XDialogProvider2)
|
||||
UnoRuntime.queryInterface(XDialogProvider2.class, provider);
|
||||
String sDialogUrl = "vnd.sun.star.script:"+getDialogLibraryName()+".NewDialog?location=application"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return xDialogProvider.createDialog(sDialogUrl);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Edit the currently selected BibTeX file, if any
|
||||
private void edit() {
|
||||
int nFile = getListBoxSelectedItem("File"); //$NON-NLS-1$
|
||||
if (nFile>=0) {
|
||||
if (files[nFile].exists()) {
|
||||
edit(files[nFile]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function: Get the currently selected entry, or null if none is selected
|
||||
private BibMark getCurrentEntry() {
|
||||
BibMark bibMark = null;
|
||||
int nEntry = getListBoxSelectedItem("Entry"); //$NON-NLS-1$
|
||||
if (nEntry>=0) {
|
||||
String[] sCurrentKeys = getListBoxStringItemList("Entry"); //$NON-NLS-1$
|
||||
String sKey = sCurrentKeys[nEntry];
|
||||
bibMark = currentFile.getEntries().get(sKey);
|
||||
}
|
||||
return bibMark;
|
||||
}
|
||||
|
||||
// **** Implement core functions
|
||||
|
||||
// Edit a BibTeX files using the systems default application, if any
|
||||
private void edit(File file) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
Desktop desktop = Desktop.getDesktop();
|
||||
try {
|
||||
desktop.open(file);
|
||||
} catch (IOException e) {
|
||||
if (xFrame!=null) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.failedbibtexeditor")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (xFrame!=null) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.nobibtexeditor")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
|
||||
// Update all bibliographic fields in the document
|
||||
private void update() {
|
||||
if (xFrame!=null) {
|
||||
BibTeXReader[] readers = parseAllBibTeXFiles();
|
||||
|
||||
// Collect identifiers of fields that were not updated (to inform the user)
|
||||
Set<String> notUpdated = new HashSet<String>();
|
||||
|
||||
// Traverse all text fields and update all bibliography fields
|
||||
XTextFieldsSupplier xSupplier = (XTextFieldsSupplier) UnoRuntime.queryInterface(
|
||||
XTextFieldsSupplier.class, xFrame.getController().getModel());
|
||||
XEnumerationAccess fields = xSupplier.getTextFields();
|
||||
XEnumeration enumeration = fields.createEnumeration();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
try {
|
||||
Object elm = enumeration.nextElement();
|
||||
if (AnyConverter.isObject(elm)) {
|
||||
XTextField xTextField = (XTextField) AnyConverter.toObject(XTextField.class, elm);
|
||||
if (xTextField!=null) {
|
||||
XServiceInfo xInfo = UnoRuntime.queryInterface(XServiceInfo.class, xTextField);
|
||||
if (xInfo.supportsService("com.sun.star.text.TextField.Bibliography")) { //$NON-NLS-1$
|
||||
String sId = updateBibField(xTextField, readers);
|
||||
if (sId!=null) {
|
||||
notUpdated.add(sId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
} catch (WrappedTargetException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all indexes and update bibliographies
|
||||
XDocumentIndexesSupplier xIndexSupplier = (XDocumentIndexesSupplier) UnoRuntime.queryInterface(
|
||||
XDocumentIndexesSupplier.class, xFrame.getController().getModel());
|
||||
XIndexAccess xIndexAccess = xIndexSupplier.getDocumentIndexes();
|
||||
|
||||
int nIndexCount = xIndexAccess.getCount();
|
||||
for (int i=0; i<nIndexCount; i++) {
|
||||
try {
|
||||
Object indexElm = xIndexAccess.getByIndex(i);
|
||||
if (AnyConverter.isObject(indexElm)) {
|
||||
XDocumentIndex xDocumentIndex = (XDocumentIndex) AnyConverter.toObject(XDocumentIndex.class, indexElm);
|
||||
if (xDocumentIndex!=null) {
|
||||
if ("com.sun.star.text.Bibliography".equals(xDocumentIndex.getServiceName())) { //$NON-NLS-1$
|
||||
xDocumentIndex.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
} catch (WrappedTargetException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the user about the result
|
||||
//MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
if (notUpdated.isEmpty()) {
|
||||
setLabelText("UpdateLabel",Messages.getString("BibTeXDialog.allbibfieldsupdated")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.allbibfieldsupdated")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
else {
|
||||
setLabelText("UpdateLabel",Messages.getString("BibTeXDialog.bibfieldsnotupdated")+":\n"+notUpdated.toString()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//msgBox.showMessage("Writer2LaTeX",Messages.getString("BibTeXDialog.bibfieldsnotupdated")+":\n"+notUpdated.toString()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BibTeXReader[] parseAllBibTeXFiles() {
|
||||
int nFiles = files.length;
|
||||
BibTeXReader[] readers = new BibTeXReader[nFiles];
|
||||
for (int i=0; i<nFiles; i++) {
|
||||
try {
|
||||
readers[i] = new BibTeXReader(files[i],sBibTeXJavaEncoding);
|
||||
} catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
readers[i] = null;
|
||||
} catch (ParseException e) {
|
||||
System.err.println(e.getMessage());
|
||||
readers[i] = null;
|
||||
}
|
||||
}
|
||||
return readers;
|
||||
}
|
||||
|
||||
// Update a bibliography field, returning the identifier on failure and null on success(!)
|
||||
private String updateBibField(XTextField xTextField, BibTeXReader[] readers) {
|
||||
XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, xTextField);
|
||||
if (xPropSet!=null) {
|
||||
try {
|
||||
Object fieldsObj = xPropSet.getPropertyValue("Fields");
|
||||
if (fieldsObj!=null && fieldsObj instanceof PropertyValue[]) {
|
||||
PropertyValue[] props = (PropertyValue[]) fieldsObj;
|
||||
for (PropertyValue prop : props) {
|
||||
if ("Identifier".equals(prop.Name)) {
|
||||
if (prop.Value instanceof String) {
|
||||
String sIdentifier = (String)prop.Value;
|
||||
for (BibTeXReader reader : readers) {
|
||||
if (reader.getEntries().keySet().contains(sIdentifier)) {
|
||||
BibMark bibMark = reader.getEntries().get(sIdentifier);
|
||||
try {
|
||||
xPropSet.setPropertyValue("Fields", createBibliographyFields(bibMark));
|
||||
return null;
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (PropertyVetoException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (UnknownPropertyException e) {
|
||||
System.out.println(e.getMessage());
|
||||
} catch (WrappedTargetException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Insert a bibliographic reference from a BibMark
|
||||
private void insertReference(BibMark bibMark) {
|
||||
if (xFrame!=null) {
|
||||
try {
|
||||
// To be able to manipulate the text we need to get the XText interface of the model
|
||||
XTextDocument xTextDoc = UnoRuntime.queryInterface(
|
||||
XTextDocument.class, xFrame.getController().getModel());
|
||||
XText xText = xTextDoc.getText();
|
||||
|
||||
// To locate the current position, we need to get the XTextViewCursor from the controller
|
||||
XTextViewCursorSupplier xViewCursorSupplier = UnoRuntime.queryInterface(
|
||||
XTextViewCursorSupplier.class, xFrame.getController());
|
||||
XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor();
|
||||
|
||||
// To create a new bibliographic field, we need to get the document service factory
|
||||
XMultiServiceFactory xDocFactory = UnoRuntime.queryInterface(
|
||||
XMultiServiceFactory.class, xFrame.getController().getModel());
|
||||
|
||||
// Use the service factory to create a bibliography field
|
||||
XDependentTextField xBibField = UnoRuntime.queryInterface (
|
||||
XDependentTextField.class, xDocFactory.createInstance("com.sun.star.text.textfield.Bibliography"));
|
||||
|
||||
// Create a field master for the field
|
||||
XPropertySet xMasterPropSet = UnoRuntime.queryInterface(
|
||||
XPropertySet.class, xDocFactory.createInstance("com.sun.star.text.fieldmaster.Bibliography"));
|
||||
|
||||
// Populate the bibliography field
|
||||
XPropertySet xPropSet = UnoRuntime.queryInterface(
|
||||
XPropertySet.class, xBibField);
|
||||
PropertyValue[] fields = createBibliographyFields(bibMark);
|
||||
xPropSet.setPropertyValue("Fields", fields);
|
||||
|
||||
// Attach the field master to the bibliography field
|
||||
xBibField.attachTextFieldMaster(xMasterPropSet);
|
||||
|
||||
// Finally, insert the field at the end of the cursor
|
||||
xText.insertTextContent(xViewCursor.getEnd(), xBibField, false);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create fields from a BibMark
|
||||
private PropertyValue[] createBibliographyFields(BibMark bibMark) {
|
||||
EntryType[] entryTypes = EntryType.values();
|
||||
PropertyValue[] fields = new PropertyValue[entryTypes.length+2];
|
||||
|
||||
fields[0] = new PropertyValue();
|
||||
fields[0].Name="Identifier";
|
||||
fields[0].Value=bibMark.getIdentifier();
|
||||
fields[1] = new PropertyValue();
|
||||
fields[1].Name="BibiliographicType"; // sic! (API typo)
|
||||
fields[1].Value=new Short(getBibliographicType(bibMark.getEntryType()));
|
||||
|
||||
int i=1;
|
||||
for (EntryType entryType : entryTypes) {
|
||||
fields[++i] = new PropertyValue();
|
||||
fields[i].Name = getFieldName(entryType);
|
||||
String sValue = bibMark.getField(entryType);
|
||||
fields[i].Value = sValue!=null ? bibMark.getField(entryType) : "";
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
// Translate entry type to field name
|
||||
private String getFieldName(EntryType entryType) {
|
||||
switch(entryType) {
|
||||
case address: return "Address";
|
||||
case annote: return "Annote";
|
||||
case author: return "Author";
|
||||
case booktitle: return "Booktitle";
|
||||
case chapter : return "Chapter";
|
||||
case edition: return "Edition";
|
||||
case editor: return "Editor";
|
||||
case howpublished: return "Howpublished";
|
||||
case institution: return "Institution";
|
||||
case journal: return "Journal";
|
||||
case month: return "Month";
|
||||
case note: return "Note";
|
||||
case number: return "Number";
|
||||
case organizations: return "Organizations";
|
||||
case pages: return "Pages";
|
||||
case publisher: return "Publisher";
|
||||
case school: return "School";
|
||||
case series: return "Series";
|
||||
case title: return "Title";
|
||||
case report_type: return "Report_Type";
|
||||
case volume: return "Volume";
|
||||
case year: return "Year";
|
||||
case url: return "URL";
|
||||
case custom1: return "Custom1";
|
||||
case custom2: return "Custom2";
|
||||
case custom3: return "Custom3";
|
||||
case custom4: return "Custom4";
|
||||
case custom5: return "Custom5";
|
||||
case isbn: return "ISBN";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Translate bibliographic type to internal code
|
||||
private short getBibliographicType(String sBibType) {
|
||||
String s = sBibType.toUpperCase();
|
||||
if ("ARTICLE".equals(s)) {
|
||||
return (short)0;
|
||||
}
|
||||
else if ("BOOK".equals(s)) {
|
||||
return (short)1;
|
||||
}
|
||||
else if ("BOOKLET".equals(s)) {
|
||||
return (short)2;
|
||||
}
|
||||
else if ("CONFERENCE".equals(s)) {
|
||||
return (short)3;
|
||||
}
|
||||
else if ("INBOOK".equals(s)) {
|
||||
return (short)4;
|
||||
}
|
||||
else if ("INCOLLECTION".equals(s)) {
|
||||
return (short)5;
|
||||
}
|
||||
else if ("INPROCEEDINGS".equals(s)) {
|
||||
return (short)6;
|
||||
}
|
||||
else if ("JOURNAL".equals(s)) {
|
||||
return (short)7;
|
||||
}
|
||||
else if ("MANUAL".equals(s)) {
|
||||
return (short)8;
|
||||
}
|
||||
else if ("MASTERSTHESIS".equals(s)) {
|
||||
return (short)9;
|
||||
}
|
||||
else if ("MISC".equals(s)) {
|
||||
return (short)10;
|
||||
}
|
||||
else if ("PHDTHESIS".equals(s)) {
|
||||
return (short)11;
|
||||
}
|
||||
else if ("PROCEEDINGS".equals(s)) {
|
||||
return (short)12;
|
||||
}
|
||||
else if ("TECHREPORT".equals(s)) {
|
||||
return (short)13;
|
||||
}
|
||||
else if ("UNPUBLISHED".equals(s)) {
|
||||
return (short)14;
|
||||
}
|
||||
else if ("EMAIL".equals(s)) {
|
||||
return (short)15;
|
||||
}
|
||||
else if ("WWW".equals(s)) {
|
||||
return (short)16;
|
||||
}
|
||||
else if ("CUSTOM1".equals(s)) {
|
||||
return (short)17;
|
||||
}
|
||||
else if ("CUSTOM2".equals(s)) {
|
||||
return (short)18;
|
||||
}
|
||||
else if ("CUSTOM3".equals(s)) {
|
||||
return (short)19;
|
||||
}
|
||||
else if ("CUSTOM4".equals(s)) {
|
||||
return (short)20;
|
||||
}
|
||||
else if ("CUSTOM5".equals(s)) {
|
||||
return (short)21;
|
||||
}
|
||||
else {
|
||||
return (short)10; // Use misc for unknown types
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BibTeXReader.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jbibtex.BibTeXDatabase;
|
||||
import org.jbibtex.BibTeXEntry;
|
||||
import org.jbibtex.BibTeXParser;
|
||||
import org.jbibtex.BibTeXString;
|
||||
import org.jbibtex.Key;
|
||||
import org.jbibtex.LaTeXParser;
|
||||
import org.jbibtex.LaTeXPrinter;
|
||||
import org.jbibtex.ParseException;
|
||||
import org.jbibtex.TokenMgrException;
|
||||
import org.jbibtex.Value;
|
||||
|
||||
import writer2latex.bibtex.BibTeXEntryMap;
|
||||
import writer2latex.office.BibMark;
|
||||
import writer2latex.office.BibMark.EntryType;
|
||||
|
||||
/**
|
||||
* The class reads the contents of a BibTeX file and makes it available as a map
|
||||
* of ODF <code>BibMark</code> objects
|
||||
*/
|
||||
public class BibTeXReader {
|
||||
|
||||
private File file;
|
||||
private String sEncoding;
|
||||
private Map<String, BibMark> entries;
|
||||
|
||||
/** Construct a new <code>BibTeXReader</code> based on a file
|
||||
*
|
||||
* @param file the file to read
|
||||
* @param sEncoding the character encoding of the file
|
||||
* @throws IOException if any error occurs reading the file
|
||||
* @throws ParseException if any error occurs interpreting the contents of the file
|
||||
*/
|
||||
public BibTeXReader(File file, String sEncoding) throws IOException, ParseException {
|
||||
this.file = file;
|
||||
this.sEncoding = sEncoding;
|
||||
reload();
|
||||
}
|
||||
|
||||
/** Parse the contents of the file, replacing any previous entries in this <code>BibTeXReader</code>
|
||||
*/
|
||||
public void reload() throws IOException, ParseException {
|
||||
entries = new HashMap<String, BibMark>();
|
||||
BibTeXDatabase database = parseBibTeX(file,sEncoding);
|
||||
readEntries(database);
|
||||
}
|
||||
|
||||
/** Get the file associated with this <code>BibTeXReader</code>
|
||||
*
|
||||
* @return the file
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/** Get the entries of this BibTeX file
|
||||
*
|
||||
* @return the entries
|
||||
*/
|
||||
public Map<String, BibMark> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static BibTeXDatabase parseBibTeX(File file, String sEncoding) throws ParseException, IOException {
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
Reader reader = new InputStreamReader(is,sEncoding);
|
||||
try {
|
||||
BibTeXParser parser = new BibTeXParser() {
|
||||
@Override
|
||||
public void checkStringResolution(Key key, BibTeXString string) {
|
||||
if (string == null) {
|
||||
System.err.println("Unresolved string: \"" + key.getValue() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCrossReferenceResolution(Key key,
|
||||
BibTeXEntry entry) {
|
||||
if (entry == null) {
|
||||
System.err.println("Unresolved cross-reference: \"" + key.getValue() + "\"");
|
||||
}
|
||||
}
|
||||
};
|
||||
return parser.parse(reader);
|
||||
} finally {
|
||||
if (reader!=null) { reader.close(); }
|
||||
if (is!=null) { is.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
private void readEntries(BibTeXDatabase database) {
|
||||
Map<Key, BibTeXEntry> entryMap = database.getEntries();
|
||||
|
||||
Collection<BibTeXEntry> bibentries = entryMap.values();
|
||||
for (BibTeXEntry bibentry : bibentries) {
|
||||
String sKey = bibentry.getKey().toString();
|
||||
String sType = bibentry.getType().toString();
|
||||
BibMark entry = new BibMark(sKey,sType);
|
||||
entries.put(sKey, entry);
|
||||
|
||||
Map<Key,Value> fields = bibentry.getFields();
|
||||
for (Key key : fields.keySet()) {
|
||||
Value value = fields.get(key);
|
||||
EntryType entryType = BibTeXEntryMap.getEntryType(key.getValue());
|
||||
if (entryType!=null) {
|
||||
entry.setField(entryType, parseLaTeX(value.toUserString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseLaTeX(String string) {
|
||||
Reader reader = new StringReader(string);
|
||||
try {
|
||||
LaTeXParser parser = new LaTeXParser();
|
||||
LaTeXPrinter printer = new LaTeXPrinter();
|
||||
return printer.print(parser.parse(reader));
|
||||
} catch (ParseException e) {
|
||||
// If parsing fails, return the original string
|
||||
return string;
|
||||
} catch (TokenMgrException e) {
|
||||
// If the string contains invalid characters, return the original string
|
||||
return string;
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
// Reading from a String will not fail :-)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BibliographyDialog.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-23)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import com.sun.star.awt.XContainerWindowEventHandler;
|
||||
import com.sun.star.awt.XDialog;
|
||||
import com.sun.star.awt.XWindow;
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.frame.XDesktop;
|
||||
import com.sun.star.frame.XModel;
|
||||
import com.sun.star.lang.XComponent;
|
||||
import com.sun.star.lang.XServiceInfo;
|
||||
import com.sun.star.uno.AnyConverter;
|
||||
import com.sun.star.uno.Exception;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
import com.sun.star.util.XChangesBatch;
|
||||
|
||||
import com.sun.star.lib.uno.helper.WeakBase;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogAccess;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.FolderPicker;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.MessageBox;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
/** This class provides a uno component which implements the configuration
|
||||
* of the bibliography for the Writer2LaTeX toolbar
|
||||
*/
|
||||
public final class BibliographyDialog
|
||||
extends WeakBase
|
||||
implements XServiceInfo, XContainerWindowEventHandler {
|
||||
|
||||
public static final String REGISTRY_PATH = "/org.openoffice.da.Writer2LaTeX.toolbar.ToolbarOptions/BibliographyOptions"; //$NON-NLS-1$
|
||||
|
||||
private XComponentContext xContext;
|
||||
private FolderPicker folderPicker;
|
||||
|
||||
/** The component will be registered under this name.
|
||||
*/
|
||||
public static String __serviceName = "org.openoffice.da.writer2latex.BibliographyDialog"; //$NON-NLS-1$
|
||||
|
||||
/** The component should also have an implementation name.
|
||||
*/
|
||||
public static String __implementationName = "org.openoffice.da.comp.writer2latex.BibliographyDialog"; //$NON-NLS-1$
|
||||
|
||||
/** Create a new ConfigurationDialog */
|
||||
public BibliographyDialog(XComponentContext xContext) {
|
||||
this.xContext = xContext;
|
||||
folderPicker = new FolderPicker(xContext);
|
||||
}
|
||||
|
||||
|
||||
// Implement XContainerWindowEventHandler
|
||||
public boolean callHandlerMethod(XWindow xWindow, Object event, String sMethod)
|
||||
throws com.sun.star.lang.WrappedTargetException {
|
||||
XDialog xDialog = (XDialog)UnoRuntime.queryInterface(XDialog.class, xWindow);
|
||||
DialogAccess dlg = new DialogAccess(xDialog);
|
||||
|
||||
try {
|
||||
if (sMethod.equals("external_event") ){ //$NON-NLS-1$
|
||||
return handleExternalEvent(dlg, event);
|
||||
}
|
||||
else if (sMethod.equals("ConvertZoteroCitationsChange")) { //$NON-NLS-1$
|
||||
return convertZoteroCitationsChange(dlg);
|
||||
}
|
||||
else if (sMethod.equals("ConvertJabRefCitationsChange")) { //$NON-NLS-1$
|
||||
return convertJabRefCitationsChange(dlg);
|
||||
}
|
||||
else if (sMethod.equals("UseExternalBibTeXFilesChange")) { //$NON-NLS-1$
|
||||
return useExternalBibTeXFilesChange(dlg);
|
||||
}
|
||||
else if (sMethod.equals("UseNatbibChange")) { //$NON-NLS-1$
|
||||
return useNatbibChange(dlg);
|
||||
}
|
||||
else if (sMethod.equals("BibTeXLocationChange")) { //$NON-NLS-1$
|
||||
return bibTeXLocationChange(dlg);
|
||||
}
|
||||
else if (sMethod.equals("BibTeXDirClick")) { //$NON-NLS-1$
|
||||
return bibTeXDirClick(dlg);
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.uno.RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
throw new com.sun.star.lang.WrappedTargetException(sMethod, this, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedMethodNames() {
|
||||
String[] sNames = { "external_event", "UseExternalBibTeXFilesChange", "ConvertZoteroCitationsChange", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
"ConvertJabRefCitationsChange", "UseNatbibChange", "BibTeXLocationChange", "ExternalBibTeXDirClick" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
return sNames;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Private stuff
|
||||
|
||||
private boolean handleExternalEvent(DialogAccess dlg, Object aEventObject)
|
||||
throws com.sun.star.uno.Exception {
|
||||
try {
|
||||
String sMethod = AnyConverter.toString(aEventObject);
|
||||
if (sMethod.equals("ok")) { //$NON-NLS-1$
|
||||
saveConfiguration(dlg);
|
||||
return true;
|
||||
} else if (sMethod.equals("back") || sMethod.equals("initialize")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
loadConfiguration(dlg);
|
||||
enableBibTeXSettings(dlg);
|
||||
useNatbibChange(dlg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.lang.IllegalArgumentException e) {
|
||||
throw new com.sun.star.lang.IllegalArgumentException(
|
||||
"Method external_event requires a string in the event object argument.", this,(short) -1); //$NON-NLS-1$
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load settings from the registry into the dialog
|
||||
private void loadConfiguration(DialogAccess dlg) {
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
try {
|
||||
Object view = registry.getRegistryView(REGISTRY_PATH, false);
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
dlg.setCheckBoxStateAsBoolean("UseExternalBibTeXFiles", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsBoolean(xProps, "UseExternalBibTeXFiles")); //$NON-NLS-1$
|
||||
dlg.setCheckBoxStateAsBoolean("ConvertZoteroCitations", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsBoolean(xProps, "ConvertZoteroCitations")); //$NON-NLS-1$
|
||||
dlg.setCheckBoxStateAsBoolean("ConvertJabRefCitations", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsBoolean(xProps, "ConvertJabRefCitations")); //$NON-NLS-1$
|
||||
dlg.setCheckBoxStateAsBoolean("IncludeOriginalCitations", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsBoolean(xProps, "IncludeOriginalCitations")); //$NON-NLS-1$
|
||||
dlg.setListBoxSelectedItem("BibTeXLocation", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXLocation")); //$NON-NLS-1$
|
||||
dlg.setTextFieldText("BibTeXDir", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsString(xProps, "BibTeXDir")); //$NON-NLS-1$
|
||||
dlg.setListBoxSelectedItem("BibTeXEncoding", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXEncoding")); //$NON-NLS-1$
|
||||
dlg.setCheckBoxStateAsBoolean("UseNatbib", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsBoolean(xProps, "UseNatbib")); //$NON-NLS-1$
|
||||
dlg.setTextFieldText("NatbibOptions", //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsString(xProps, "NatbibOptions")); //$NON-NLS-1$
|
||||
registry.disposeRegistryView(view);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Failed to get registry view
|
||||
}
|
||||
|
||||
// Update dialog according to the settings
|
||||
convertZoteroCitationsChange(dlg);
|
||||
useExternalBibTeXFilesChange(dlg);
|
||||
}
|
||||
|
||||
// Save settings from the dialog to the registry
|
||||
private void saveConfiguration(DialogAccess dlg) {
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
try {
|
||||
Object view = registry.getRegistryView(REGISTRY_PATH, true);
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
XPropertySetHelper.setPropertyValue(xProps, "UseExternalBibTeXFiles", dlg.getCheckBoxStateAsBoolean("UseExternalBibTeXFiles")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "ConvertZoteroCitations", dlg.getCheckBoxStateAsBoolean("ConvertZoteroCitations")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "ConvertJabRefCitations", dlg.getCheckBoxStateAsBoolean("ConvertJabRefCitations")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "IncludeOriginalCitations", dlg.getCheckBoxStateAsBoolean("IncludeOriginalCitations")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "BibTeXLocation", dlg.getListBoxSelectedItem("BibTeXLocation")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "BibTeXDir", dlg.getTextFieldText("BibTeXDir")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "BibTeXEncoding", dlg.getListBoxSelectedItem("BibTeXEncoding")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "UseNatbib", dlg.getCheckBoxStateAsBoolean("UseNatbib")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
XPropertySetHelper.setPropertyValue(xProps, "NatbibOptions", dlg.getTextFieldText("NatbibOptions")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// Commit registry changes
|
||||
XChangesBatch xUpdateContext = (XChangesBatch)
|
||||
UnoRuntime.queryInterface(XChangesBatch.class,view);
|
||||
try {
|
||||
xUpdateContext.commitChanges();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
registry.disposeRegistryView(view);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Failed to get registry view
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useExternalBibTeXFilesChange(DialogAccess dlg) {
|
||||
enableBibTeXSettings(dlg);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean convertZoteroCitationsChange(DialogAccess dlg) {
|
||||
enableBibTeXSettings(dlg);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean convertJabRefCitationsChange(DialogAccess dlg) {
|
||||
enableBibTeXSettings(dlg);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useNatbibChange(DialogAccess dlg) {
|
||||
boolean bUseNatbib = dlg.getCheckBoxStateAsBoolean("UseNatbib"); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("NatbibOptionsLabel", bUseNatbib); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("NatbibOptions", bUseNatbib); //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean bibTeXLocationChange(DialogAccess dlg) {
|
||||
enableBibTeXSettings(dlg);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enableBibTeXSettings(DialogAccess dlg) {
|
||||
boolean bEnableSettings = dlg.getCheckBoxStateAsBoolean("UseExternalBibTeXFiles"); //$NON-NLS-1$
|
||||
boolean bEnableOriginalCitations = dlg.getCheckBoxStateAsBoolean("ConvertZoteroCitations") //$NON-NLS-1$
|
||||
|| dlg.getCheckBoxStateAsBoolean("ConvertJabRefCitations"); //$NON-NLS-1$
|
||||
boolean bEnableDir = dlg.getListBoxSelectedItem("BibTeXLocation")<2; //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXLocationLabel", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXLocation", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXDirLabel", bEnableSettings && bEnableDir); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXDir", bEnableSettings && bEnableDir); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXDirButton", bEnableSettings && bEnableDir); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXEncodingLabel", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("BibTeXEncoding", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("ConvertZoteroCitations", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("ConvertJabRefCitations", bEnableSettings); //$NON-NLS-1$
|
||||
dlg.setControlEnabled("IncludeOriginalCitations", bEnableSettings && bEnableOriginalCitations); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private String getDocumentDirURL() {
|
||||
// Get the desktop from the service manager
|
||||
Object desktop=null;
|
||||
try {
|
||||
desktop = xContext.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", xContext); //$NON-NLS-1$
|
||||
} catch (Exception e) {
|
||||
// Failed to get the desktop service
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class, desktop);
|
||||
|
||||
// Get the current component and verify that it really is a text document
|
||||
if (xDesktop!=null) {
|
||||
XComponent xComponent = xDesktop.getCurrentComponent();
|
||||
XServiceInfo xInfo = (XServiceInfo)UnoRuntime.queryInterface(XServiceInfo.class, xComponent);
|
||||
if (xInfo!=null && xInfo.supportsService("com.sun.star.text.TextDocument")) { //$NON-NLS-1$
|
||||
// Get the model, which provides the URL
|
||||
XModel xModel = (XModel) UnoRuntime.queryInterface(XModel.class, xComponent);
|
||||
if (xModel!=null) {
|
||||
String sURL = xModel.getURL();
|
||||
int nSlash = sURL.lastIndexOf('/');
|
||||
return nSlash>-1 ? sURL.substring(0, nSlash) : ""; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private boolean hasBibTeXFiles(File dir) {
|
||||
if (dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (file.isFile() && file.getName().endsWith(".bib")) { //$NON-NLS-1$
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean bibTeXDirClick(DialogAccess dlg) {
|
||||
String sPath = folderPicker.getPath();
|
||||
if (sPath!=null) {
|
||||
try {
|
||||
File bibDir = new File(new URI(sPath));
|
||||
String sBibPath = bibDir.getCanonicalPath();
|
||||
if (dlg.getListBoxSelectedItem("BibTeXLocation")==1) { //$NON-NLS-1$
|
||||
// Path relative to document directory, remove the document directory part
|
||||
String sDocumentDirURL = getDocumentDirURL();
|
||||
if (sDocumentDirURL.length()>0) {
|
||||
String sDocumentDirPath = new File(new URI(sDocumentDirURL)).getCanonicalPath();
|
||||
if (sBibPath.startsWith(sDocumentDirPath)) {
|
||||
if (sBibPath.length()>sDocumentDirPath.length()) {
|
||||
sBibPath = sBibPath.substring(sDocumentDirPath.length()+1);
|
||||
}
|
||||
else { // Same as document directory
|
||||
sBibPath = ""; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else { // not a subdirectory
|
||||
sBibPath = ""; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
dlg.setTextFieldText("BibTeXDir", sBibPath); //$NON-NLS-1$
|
||||
if (!hasBibTeXFiles(bibDir)) {
|
||||
MessageBox msgBox = new MessageBox(xContext);
|
||||
msgBox.showMessage("Writer2LaTeX", Messages.getString("BibliographyDialog.nobibtexfiles")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,85 +0,0 @@
|
|||
/**
|
||||
* CustomSymbolNameProvider.java
|
||||
*
|
||||
* Copyright: 2002-2009 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2009-11-09)
|
||||
*
|
||||
*/
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.container.XNameAccess;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** This class provides access to the names of all user defined symbols in math
|
||||
*
|
||||
*/
|
||||
public class CustomSymbolNameProvider {
|
||||
Set<String> names;
|
||||
|
||||
/** Construct a new <code>CustomSymbolNameProvider</code>
|
||||
*
|
||||
* @param xContext the component context providing access to the api
|
||||
*/
|
||||
public CustomSymbolNameProvider(XComponentContext xContext) {
|
||||
names = new HashSet<String>();
|
||||
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
try {
|
||||
// Prepare registry view
|
||||
Object view = registry.getRegistryView("/org.openoffice.Office.Math/",false);
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
|
||||
// Get the list of symbols
|
||||
Object symbols = XPropertySetHelper.getPropertyValue(xProps,"SymbolList");
|
||||
XNameAccess xSymbols = (XNameAccess) UnoRuntime.queryInterface(XNameAccess.class,symbols);
|
||||
String[] sNames = xSymbols.getElementNames();
|
||||
int nCount = sNames.length;
|
||||
for (int i=0; i<nCount; i++) {
|
||||
Object config = xSymbols.getByName(sNames[i]);
|
||||
XPropertySet xSymbolProps = (XPropertySet)
|
||||
UnoRuntime.queryInterface(XPropertySet.class,config);
|
||||
if (!XPropertySetHelper.getPropertyValueAsBoolean(xSymbolProps,"Predefined")) {
|
||||
names.add(sNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
// failed to get registry view, ignore
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the names of all user defined symbols (excluding the predefined symbols such as ALPHA etc)
|
||||
*
|
||||
* @return a read only string set of symbols names
|
||||
*/
|
||||
public Set<String> getNames() {
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* DeTeXtive.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.tex.tokenizer.Mouth;
|
||||
import org.openoffice.da.comp.w2lcommon.tex.tokenizer.Token;
|
||||
import org.openoffice.da.comp.w2lcommon.tex.tokenizer.TokenType;
|
||||
|
||||
/** This class analyzes a stream and detects if it is a TeX stream.
|
||||
* Currently it is able to identify LaTeX and XeLaTeX (ConTeXt and plain TeX may be
|
||||
* added later).
|
||||
*/
|
||||
public class DeTeXtive {
|
||||
private Mouth mouth;
|
||||
private Token token;
|
||||
|
||||
private HashSet<String> packages;
|
||||
|
||||
/** Construct a new DeTeXtive
|
||||
*/
|
||||
public DeTeXtive() {
|
||||
}
|
||||
|
||||
/** Detect the format of a given stream
|
||||
*
|
||||
* @param is the input stream
|
||||
* @return a string representing the detected format; null if the format is unknown.
|
||||
* Currently the values "LaTeX", "XeLaTeX" are supported.
|
||||
* @throws IOException if we fail to read the stream
|
||||
*/
|
||||
public String deTeXt(InputStream is) throws IOException {
|
||||
// It makes no harm to assume that the stream uses ISO Latin1 - we only consider ASCII characters
|
||||
mouth = new Mouth(new InputStreamReader(is,"ISO8859_1"));
|
||||
token = mouth.getTokenObject();
|
||||
|
||||
packages = new HashSet<String>();
|
||||
|
||||
mouth.getToken();
|
||||
|
||||
if (parseHeader() && parsePreamble()) {
|
||||
if (packages.contains("xunicode")) {
|
||||
return "XeLaTeX";
|
||||
}
|
||||
else {
|
||||
return "LaTeX";
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown format
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// The parser!
|
||||
|
||||
// Parse a LaTeX header such as \documentclass[a4paper]{article}
|
||||
// Return true in case of success
|
||||
private boolean parseHeader() throws IOException {
|
||||
skipBlanks();
|
||||
if (token.isCS("documentclass") || token.isCS("documentstyle")) {
|
||||
// The first non-blank token is \documentclass or \documentstyle => could be a LaTeX document
|
||||
//System.out.println("** Found "+token.toString());
|
||||
mouth.getToken();
|
||||
skipSpaces();
|
||||
// Skip options, if any
|
||||
if (token.is('[',TokenType.OTHER)) {
|
||||
skipOptional();
|
||||
skipSpaces();
|
||||
}
|
||||
if (token.getType()==TokenType.BEGIN_GROUP) {
|
||||
// Get class name
|
||||
String sClassName = parseArgumentAsString();
|
||||
//System.out.println("** Found the class name "+sClassName);
|
||||
// Accept any class name of one or more characters
|
||||
if (sClassName.length()>0) { return true; }
|
||||
}
|
||||
}
|
||||
//System.out.println("** Doesn't look like LaTeX; failed to get class name");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse a LaTeX preamble
|
||||
// Return true in case of success (that is, \begin{document} was found)
|
||||
private boolean parsePreamble() throws IOException {
|
||||
while (token.getType()!=TokenType.ENDINPUT) {
|
||||
if (token.isCS("usepackage")) {
|
||||
// We collect the names of all used packages, but discard their options
|
||||
// (Recall that this is only relevant for LaTeX 2e)
|
||||
mouth.getToken();
|
||||
skipSpaces();
|
||||
if (token.is('[',TokenType.OTHER)) {
|
||||
skipOptional();
|
||||
skipSpaces();
|
||||
}
|
||||
String sName = parseArgumentAsString();
|
||||
//System.out.println("** Found package "+sName);
|
||||
packages.add(sName);
|
||||
}
|
||||
else if (token.getType()==TokenType.BEGIN_GROUP) {
|
||||
// We ignore anything inside a group
|
||||
skipGroup();
|
||||
}
|
||||
else if (token.isCS("begin")) {
|
||||
// This would usually indicate the end of the preamble
|
||||
mouth.getToken();
|
||||
skipSpaces();
|
||||
if ("document".equals(parseArgumentAsString())) {
|
||||
//System.out.println("Found \\begin{document}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Any other content in the preamble is simply ignored
|
||||
mouth.getToken();
|
||||
}
|
||||
}
|
||||
//System.out.println("** Doesn't look like LaTeX; failed to find \\begin{document}");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void skipBlanks() throws IOException {
|
||||
while (token.getType()==TokenType.SPACE || token.isCS("par")) {
|
||||
mouth.getToken();
|
||||
}
|
||||
}
|
||||
|
||||
private void skipSpaces() throws IOException {
|
||||
// Actually, we will never get two space tokens in a row
|
||||
while (token.getType()==TokenType.SPACE) {
|
||||
mouth.getToken();
|
||||
}
|
||||
}
|
||||
|
||||
private void skipOptional() throws IOException {
|
||||
assert token.is('[', TokenType.OTHER);
|
||||
|
||||
mouth.getToken(); // skip the [
|
||||
while (!token.is(']',TokenType.OTHER) && token.getType()!=TokenType.ENDINPUT) {
|
||||
if (token.getType()==TokenType.BEGIN_GROUP) {
|
||||
skipGroup();
|
||||
}
|
||||
else {
|
||||
mouth.getToken(); // skip this token
|
||||
}
|
||||
}
|
||||
mouth.getToken(); // skip the ]
|
||||
}
|
||||
|
||||
private void skipGroup() throws IOException {
|
||||
assert token.getType()==TokenType.BEGIN_GROUP;
|
||||
|
||||
mouth.getToken(); // skip the {
|
||||
while (token.getType()!=TokenType.END_GROUP && token.getType()!=TokenType.ENDINPUT) {
|
||||
if (token.getType()==TokenType.BEGIN_GROUP) {
|
||||
skipGroup();
|
||||
}
|
||||
else {
|
||||
mouth.getToken(); // skip this token
|
||||
}
|
||||
}
|
||||
mouth.getToken(); // skip the }
|
||||
}
|
||||
|
||||
private String parseArgumentAsString() throws IOException {
|
||||
if (token.getType()==TokenType.BEGIN_GROUP) {
|
||||
// Argument is contained in a group
|
||||
mouth.getToken(); // skip the {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (token.getType()!=TokenType.END_GROUP && token.getType()!=TokenType.ENDINPUT) {
|
||||
if (token.getType()!=TokenType.COMMAND_SEQUENCE) {
|
||||
// should not include cs, ignore if it happens
|
||||
sb.append(token.getChar());
|
||||
}
|
||||
mouth.getToken();
|
||||
}
|
||||
mouth.getToken(); // skip the }
|
||||
return sb.toString();
|
||||
}
|
||||
else {
|
||||
// Argument is a single token
|
||||
String s = "";
|
||||
if (token.getType()!=TokenType.COMMAND_SEQUENCE) {
|
||||
// should not include cs, ignore if it happens
|
||||
s = token.getString();
|
||||
}
|
||||
mouth.getToken();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,341 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ExternalApps.java
|
||||
*
|
||||
* Copyright: 2002-2018 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2018-03-06)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.Process;
|
||||
import java.lang.ProcessBuilder;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.StreamGobbler;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
import com.sun.star.beans.XMultiHierarchicalPropertySet;
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
import com.sun.star.util.XChangesBatch;
|
||||
|
||||
|
||||
/** This class manages and executes external applications used by the Writer2LaTeX toolbar.
|
||||
* These include TeX and friends as well as viewers for the various backend formats.
|
||||
* The registry is used for persistent storage of the settings.
|
||||
*/
|
||||
public class ExternalApps {
|
||||
|
||||
public final static short EXPORT = (short)0;
|
||||
public final static short BUILD = (short)1;
|
||||
public final static short PREVIEW = (short)2;
|
||||
|
||||
public final static String LATEX = "LaTeX"; //$NON-NLS-1$
|
||||
public final static String PDFLATEX = "PdfLaTeX"; //$NON-NLS-1$
|
||||
public final static String XELATEX = "XeLaTeX"; //$NON-NLS-1$
|
||||
public final static String BIBTEX = "BibTeX"; //$NON-NLS-1$
|
||||
public final static String MAKEINDEX = "Makeindex"; //$NON-NLS-1$
|
||||
public final static String MK4HT = "Mk4ht"; //$NON-NLS-1$
|
||||
public final static String DVIPS = "Dvips"; //$NON-NLS-1$
|
||||
public final static String DVIVIEWER = "DVIViewer"; //$NON-NLS-1$
|
||||
public final static String POSTSCRIPTVIEWER = "PostscriptViewer"; //$NON-NLS-1$
|
||||
public final static String PDFVIEWER = "PdfViewer"; //$NON-NLS-1$
|
||||
|
||||
private final static String[] sApps = { LATEX, PDFLATEX, XELATEX, BIBTEX, MAKEINDEX, MK4HT, DVIPS, DVIVIEWER, POSTSCRIPTVIEWER, PDFVIEWER };
|
||||
|
||||
private XComponentContext xContext;
|
||||
|
||||
private short nLevel = (short)2;
|
||||
|
||||
private Map<String,String[]> apps;
|
||||
private Set<String> defaultApps;
|
||||
|
||||
/** Construct a new ExternalApps object with empty content */
|
||||
public ExternalApps(XComponentContext xContext) {
|
||||
this.xContext = xContext;
|
||||
apps = new HashMap<String,String[]>();
|
||||
defaultApps = new HashSet<String>();
|
||||
for (int i=0; i<sApps.length; i++) {
|
||||
setApplication(sApps[i], "", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
setUseDefaultApplication(sApps[i],true);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the localized name for an external app to use in the UI (only the viewers has a separate UI name)
|
||||
*
|
||||
* @param sName the app name
|
||||
* @return the UI name
|
||||
*/
|
||||
public static String getUIAppName(String sName) {
|
||||
if (DVIVIEWER.equals(sName)) {
|
||||
return Messages.getString("ExternalApps.dviviewer"); //$NON-NLS-1$
|
||||
}
|
||||
else if (PDFVIEWER.equals(sName)) {
|
||||
return Messages.getString("ExternalApps.pdfviewer"); //$NON-NLS-1$
|
||||
}
|
||||
else if (POSTSCRIPTVIEWER.equals(sName)) {
|
||||
return Messages.getString("ExternalApps.psviewer"); //$NON-NLS-1$
|
||||
}
|
||||
return sName;
|
||||
}
|
||||
|
||||
/** Set the desired processing level (0: export only, 1: export and build, 2: export, build and preview)
|
||||
*
|
||||
* @param nLevel the desired level
|
||||
*/
|
||||
public void setProcessingLevel(short nLevel) {
|
||||
this.nLevel = nLevel;
|
||||
}
|
||||
|
||||
/** Get the desired processing level (0: export only, 1: export and build, 2: export, build and preview)
|
||||
*
|
||||
* @return the level
|
||||
*/
|
||||
public short getProcessingLevel() {
|
||||
return nLevel;
|
||||
}
|
||||
|
||||
public boolean isViewer(String sAppName) {
|
||||
return sAppName!=null && sAppName.endsWith("Viewer"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Define an external application
|
||||
* @param sAppName the name of the application to define
|
||||
* @param sExecutable the system dependent path to the executable file
|
||||
* @param sOptions the options to the external application; %s will be
|
||||
* replaced by the filename on execution
|
||||
*/
|
||||
public void setApplication(String sAppName, String sExecutable, String sOptions) {
|
||||
String[] sValue = { sExecutable, sOptions };
|
||||
apps.put(sAppName, sValue);
|
||||
}
|
||||
|
||||
/** Get the definition for an external application
|
||||
* @param sAppName the name of the application to get
|
||||
* @return a String array containing the system dependent path to the
|
||||
* executable file as entry 0 and the parameters as entry 1
|
||||
* returns null if the application is unknown
|
||||
*/
|
||||
public String[] getApplication(String sAppName) {
|
||||
return apps.get(sAppName);
|
||||
}
|
||||
|
||||
/** Define to use the system's default for an external application. This is only possible if the application is a viewer,
|
||||
* otherwise setting the value to true will be ignored
|
||||
* @param sAppName the name of the application
|
||||
* @param bUseDefault flag defining whether or not to use the default
|
||||
*/
|
||||
public void setUseDefaultApplication(String sAppName, boolean bUseDefault) {
|
||||
if (bUseDefault && isViewer(sAppName)) {
|
||||
defaultApps.add(sAppName);
|
||||
}
|
||||
else if (defaultApps.contains(sAppName)) {
|
||||
defaultApps.remove(sAppName);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the setting to use the system's default application
|
||||
*
|
||||
* @param sAppName the name of the application
|
||||
* @return true if the system's default should be used, false if not or if the application is unknown
|
||||
*/
|
||||
public boolean getUseDefaultApplication(String sAppName) {
|
||||
return defaultApps.contains(sAppName);
|
||||
}
|
||||
|
||||
/** Execute an external application
|
||||
* @param sAppName the name of the application to execute (ignored for default apps)
|
||||
* @param sFileName the file name to use
|
||||
* @param workDir the working directory to use
|
||||
* @param env map of environment variables to set (or null if no variables needs to be set, ignored for default apps)
|
||||
* @param bWaitFor true if the method should wait for the execution to finish (ignored for default apps)
|
||||
* @return error code
|
||||
*/
|
||||
public int execute(String sAppName, String sFileName, File workDir, Map<String,String> env, boolean bWaitFor) {
|
||||
if (defaultApps.contains(sAppName)) {
|
||||
return openWithDefaultApplication(new File(sFileName)) ? 0 : 1;
|
||||
}
|
||||
else {
|
||||
return execute(sAppName, "", sFileName, workDir, env, bWaitFor); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
// Open the file in the default application on this system (if any)
|
||||
private boolean openWithDefaultApplication(File file) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
Desktop desktop = Desktop.getDesktop();
|
||||
try {
|
||||
desktop.open(file);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Execute an external application
|
||||
* @param sAppName the name of the application to execute
|
||||
* @param sCommand subcommand/option to pass to the command
|
||||
* @param sFileName the file name to use
|
||||
* @param workDir the working directory to use
|
||||
* @param env map of environment variables to set (or null if no variables needs to be set)
|
||||
* @param bWaitFor true if the method should wait for the execution to finish
|
||||
* @return error code
|
||||
*/
|
||||
public int execute(String sAppName, String sCommand, String sFileName, File workDir, Map<String,String> env, boolean bWaitFor) {
|
||||
// Assemble the command
|
||||
String[] sApp = getApplication(sAppName);
|
||||
if (sApp==null) { return 1; }
|
||||
|
||||
try {
|
||||
Vector<String> command = new Vector<String>();
|
||||
command.add(sApp[0]);
|
||||
String[] sArguments = sApp[1].split(" "); //$NON-NLS-1$
|
||||
for (String s : sArguments) {
|
||||
command.add(s.replace("%c",sCommand).replace("%s",sFileName)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(command);
|
||||
pb.directory(workDir);
|
||||
if (env!=null) {
|
||||
pb.environment().putAll(env);
|
||||
}
|
||||
Process proc = pb.start();
|
||||
|
||||
// Gobble the error stream of the application
|
||||
StreamGobbler errorGobbler = new
|
||||
StreamGobbler(proc.getErrorStream(), "ERROR"); //$NON-NLS-1$
|
||||
|
||||
// Gobble the output stream of the application
|
||||
StreamGobbler outputGobbler = new
|
||||
StreamGobbler(proc.getInputStream(), "OUTPUT"); //$NON-NLS-1$
|
||||
|
||||
// Kick them off
|
||||
errorGobbler.start();
|
||||
outputGobbler.start();
|
||||
|
||||
// Any error?
|
||||
return bWaitFor ? proc.waitFor() : 0;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
return 1;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Load the external applications from the registry
|
||||
*/
|
||||
public void load() {
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
Object view;
|
||||
try {
|
||||
// Prepare registry view
|
||||
view = registry.getRegistryView("/org.openoffice.da.Writer2LaTeX.toolbar.ToolbarOptions/Applications",false); //$NON-NLS-1$
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// Give up...
|
||||
return;
|
||||
}
|
||||
|
||||
XPropertySet xSimpleProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
nLevel = XPropertySetHelper.getPropertyValueAsShort(xSimpleProps,"AfterExport"); //$NON-NLS-1$
|
||||
|
||||
XMultiHierarchicalPropertySet xProps = (XMultiHierarchicalPropertySet)
|
||||
UnoRuntime.queryInterface(XMultiHierarchicalPropertySet.class, view);
|
||||
for (int i=0; i<sApps.length; i++) {
|
||||
String[] sNames = new String[3];
|
||||
sNames[0] = sApps[i]+"/Executable"; //$NON-NLS-1$
|
||||
sNames[1] = sApps[i]+"/Options"; //$NON-NLS-1$
|
||||
sNames[2] = sApps[i]+"/UseDefault"; //$NON-NLS-1$
|
||||
try {
|
||||
Object[] values = xProps.getHierarchicalPropertyValues(sNames);
|
||||
setApplication(sApps[i], (String) values[0], (String) values[1]);
|
||||
setUseDefaultApplication(sApps[i], ((Boolean) values[2]).booleanValue());
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// Ignore...
|
||||
}
|
||||
}
|
||||
|
||||
registry.disposeRegistryView(view);
|
||||
}
|
||||
|
||||
/** Save the external applications to the registry
|
||||
*/
|
||||
public void save() {
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
Object view;
|
||||
try {
|
||||
view = registry.getRegistryView("/org.openoffice.da.Writer2LaTeX.toolbar.ToolbarOptions/Applications",true); //$NON-NLS-1$
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// Give up...
|
||||
return;
|
||||
}
|
||||
|
||||
XPropertySet xSimpleProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
XPropertySetHelper.setPropertyValue(xSimpleProps, "AfterExport", nLevel); //$NON-NLS-1$
|
||||
|
||||
XMultiHierarchicalPropertySet xProps = (XMultiHierarchicalPropertySet)
|
||||
UnoRuntime.queryInterface(XMultiHierarchicalPropertySet.class, view);
|
||||
for (int i=0; i<sApps.length; i++) {
|
||||
String[] sNames = new String[3];
|
||||
sNames[0] = sApps[i]+"/Executable"; //$NON-NLS-1$
|
||||
sNames[1] = sApps[i]+"/Options"; //$NON-NLS-1$
|
||||
sNames[2] = sApps[i]+"/UseDefault"; //$NON-NLS-1$
|
||||
String[] sApp = getApplication(sApps[i]);
|
||||
boolean bUseDefault = getUseDefaultApplication(sApps[i]);
|
||||
Object[] values = { sApp[0], sApp[1], new Boolean(bUseDefault) };
|
||||
try {
|
||||
xProps.setHierarchicalPropertyValues(sNames, values);
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// Ignore...
|
||||
}
|
||||
}
|
||||
|
||||
// Commit registry changes
|
||||
XChangesBatch xUpdateContext = (XChangesBatch)
|
||||
UnoRuntime.queryInterface(XChangesBatch.class, view);
|
||||
try {
|
||||
xUpdateContext.commitChanges();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
registry.disposeRegistryView(view);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,385 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LaTeXOptionsDialog.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-12)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
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
|
||||
* LaTeX export
|
||||
*/
|
||||
public class LaTeXOptionsDialog extends OptionsDialogBase {
|
||||
|
||||
// Translate list box items to configuration option values
|
||||
private static final String[] BACKEND_VALUES =
|
||||
{ "generic", "pdftex", "dvips", "xetex", "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" };
|
||||
|
||||
// UI names and configuration option values for fonts
|
||||
private static final String[] FONT_VALUES =
|
||||
{ "default", "cmbright", "ccfonts", "ccfonts-euler",
|
||||
"iwona", "kurier", "anttor", "kmath-kerkis",
|
||||
"fouriernc",
|
||||
"pxfonts", "mathpazo", "mathpple",
|
||||
"txfonts", "mathptmx",
|
||||
"arev",
|
||||
"charter-mathdesign", "utopia-mathdesign", "fourier" };
|
||||
private static final String[] FONT_NAMES =
|
||||
{ "Default (Computer Modern)", "CM Bright", "Concrete", "Concrete + Euler Math",
|
||||
"Iwona", "Kurier", "Antykwa Toru\u0144ska", "Kerkis",
|
||||
"New Century Schoolbook + Fourier Math",
|
||||
"Palatino + PXfonts Math", "Palatino + Pazo Math", "Palatino + Euler Math",
|
||||
"Times + TXfonts Math", "Times + Symbol",
|
||||
"Arev Sans + Arev Math",
|
||||
"Bitstream Charter + Math Design", "Utopia + Math Design", "Utopia + Fourier Math" };
|
||||
|
||||
/** 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");
|
||||
setListBoxStringItemList("Font", FONT_NAMES);
|
||||
loadListBoxOption(xProps,"Font");
|
||||
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");
|
||||
loadCheckBoxOption(xProps,"DisplayHiddenText");
|
||||
|
||||
// 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");
|
||||
saveListBoxOption(xProps, filterData, "Font", "font", FONT_VALUES);
|
||||
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");
|
||||
saveCheckBoxOption(xProps, filterData, "DisplayHiddenText", "display_hidden_text");
|
||||
|
||||
// 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") || sMethod.equals("BackendChange")) {
|
||||
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 ("inputencoding".equals(sOptionName)) {
|
||||
// backend=xetex locks the encoding to utf8
|
||||
return getListBoxSelectedItem("Backend")==3 || super.isLocked(sOptionName);
|
||||
}
|
||||
else if ("font".equals(sOptionName)) {
|
||||
// backend=xetex does not (currently) use the font option
|
||||
return getListBoxSelectedItem("Backend")==3 || super.isLocked(sOptionName);
|
||||
}
|
||||
else if ("greek_math".equals(sOptionName)) {
|
||||
// this option has no effect if backend=xetex
|
||||
return getListBoxSelectedItem("Backend")==3 || 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)
|
||||
// it is also disabled for backend=xetex
|
||||
return getListBoxSelectedItem("Backend")==3 || 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("FontLabel",!isLocked("font"));
|
||||
setControlEnabled("Font",!isLocked("font"));
|
||||
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"));
|
||||
setControlEnabled("DisplayHiddenText",!isLocked("display_hidden_text"));
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LaTeXUNOPublisher.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-23)
|
||||
*
|
||||
*/
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.filter.UNOPublisher;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.MessageBox;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
import writer2latex.latex.i18n.ClassicI18n;
|
||||
import writer2latex.util.CSVList;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
import com.sun.star.beans.PropertyValue;
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.frame.XFrame;
|
||||
import com.sun.star.uno.Exception;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
public class LaTeXUNOPublisher extends UNOPublisher {
|
||||
|
||||
// The TeXifier and associated data
|
||||
private TeXify texify = null;
|
||||
private String sBibinputs=null;
|
||||
private String sBackend = "generic"; //$NON-NLS-1$
|
||||
|
||||
public LaTeXUNOPublisher(XComponentContext xContext, XFrame xFrame, String sAppName) {
|
||||
super(xContext, xFrame, sAppName);
|
||||
}
|
||||
|
||||
/** Get the directory containing the BibTeX files (as defined in the registry)
|
||||
*
|
||||
* @return the directory
|
||||
*/
|
||||
public File getBibTeXDirectory() {
|
||||
// Get the BibTeX settings from the registry
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
Object view;
|
||||
try {
|
||||
view = registry.getRegistryView(BibliographyDialog.REGISTRY_PATH, false);
|
||||
} catch (Exception e) {
|
||||
// Failed to get registry settings
|
||||
return null;
|
||||
}
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
return getDirectory(XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXLocation"), //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsString(xProps, "BibTeXDir")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Make a file name LaTeX friendly
|
||||
*/
|
||||
@Override protected String filterFileName(String sFileName) {
|
||||
return Misc.makeTeXFriendly(sFileName,"writer2latex"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/** Post process the filter data: Set bibliography options and
|
||||
* determine the backend and the BIBINPUTS directory
|
||||
*/
|
||||
@Override protected PropertyValue[] postProcessMediaProps(PropertyValue[] mediaProps) {
|
||||
sBackend = "generic"; //$NON-NLS-1$
|
||||
sBibinputs = null;
|
||||
|
||||
PropertyHelper mediaHelper = new PropertyHelper(mediaProps);
|
||||
Object filterData = mediaHelper.get("FilterData"); //$NON-NLS-1$
|
||||
if (filterData instanceof PropertyValue[]) {
|
||||
PropertyHelper filterHelper = new PropertyHelper((PropertyValue[])filterData);
|
||||
|
||||
// Get the backend
|
||||
Object backend = filterHelper.get("backend"); //$NON-NLS-1$
|
||||
if (backend instanceof String) {
|
||||
sBackend = (String) backend;
|
||||
}
|
||||
|
||||
// Set the bibliography options according to the settings
|
||||
RegistryHelper registry = new RegistryHelper(xContext);
|
||||
try {
|
||||
Object view = registry.getRegistryView(BibliographyDialog.REGISTRY_PATH, false);
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
String sBibTeXFiles = getFileList(XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXLocation"), //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsString(xProps, "BibTeXDir")); //$NON-NLS-1$
|
||||
if (XPropertySetHelper.getPropertyValueAsBoolean(xProps, "UseExternalBibTeXFiles")) { //$NON-NLS-1$
|
||||
filterHelper.put("external_bibtex_files", sBibTeXFiles); //$NON-NLS-1$
|
||||
filterHelper.put("bibtex_encoding", ClassicI18n.writeInputenc( //$NON-NLS-1$
|
||||
XPropertySetHelper.getPropertyValueAsShort(xProps, "BibTeXEncoding"))); //$NON-NLS-1$
|
||||
if (XPropertySetHelper.getPropertyValueAsBoolean(xProps, "ConvertZoteroCitations")) { //$NON-NLS-1$
|
||||
filterHelper.put("zotero_bibtex_files", sBibTeXFiles); //$NON-NLS-1$
|
||||
}
|
||||
if (XPropertySetHelper.getPropertyValueAsBoolean(xProps, "ConvertJabRefCitations")) { //$NON-NLS-1$
|
||||
filterHelper.put("jabref_bibtex_files", sBibTeXFiles); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
filterHelper.put("include_original_citations", //$NON-NLS-1$
|
||||
Boolean.toString(XPropertySetHelper.getPropertyValueAsBoolean(xProps, "IncludeOriginalCitations"))); //$NON-NLS-1$
|
||||
String sBibTeXDir = XPropertySetHelper.getPropertyValueAsString(xProps, "BibTeXDir"); //$NON-NLS-1$
|
||||
if (sBibTeXDir.length()>0) {
|
||||
// The separator character in BIBINPUTS is OS specific
|
||||
sBibinputs = sBibTeXDir+File.pathSeparatorChar;
|
||||
}
|
||||
filterHelper.put("use_natbib", Boolean.toString(XPropertySetHelper.getPropertyValueAsBoolean(xProps, "UseNatbib"))); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
filterHelper.put("natbib_options", XPropertySetHelper.getPropertyValueAsString(xProps, "NatbibOptions")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
mediaHelper.put("FilterData",filterHelper.toArray()); //$NON-NLS-1$
|
||||
PropertyValue[] newMediaProps = mediaHelper.toArray();
|
||||
registry.disposeRegistryView(view);
|
||||
return newMediaProps;
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Failed to get registry view; return original media props
|
||||
return mediaProps;
|
||||
}
|
||||
}
|
||||
// No filter data; return original media props
|
||||
return mediaProps;
|
||||
}
|
||||
|
||||
/** Postprocess the converted document with LaTeX and display the result
|
||||
*/
|
||||
@Override protected void postProcess(String sURL, TargetFormat format) {
|
||||
if (texify==null) { texify = new TeXify(xContext); }
|
||||
File file = new File(Misc.urlToFile(getTargetPath()),getTargetFileName());
|
||||
|
||||
boolean bResult = true;
|
||||
|
||||
try {
|
||||
if (sBackend=="pdftex") { //$NON-NLS-1$
|
||||
bResult = texify.process(file, sBibinputs, TeXify.PDFTEX, true);
|
||||
}
|
||||
else if (sBackend=="dvips") { //$NON-NLS-1$
|
||||
bResult = texify.process(file, sBibinputs, TeXify.DVIPS, true);
|
||||
}
|
||||
else if (sBackend=="xetex") { //$NON-NLS-1$
|
||||
bResult = texify.process(file, sBibinputs, TeXify.XETEX, true);
|
||||
}
|
||||
else if (sBackend=="generic") { //$NON-NLS-1$
|
||||
bResult = texify.process(file, sBibinputs, TeXify.GENERIC, true);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("LaTeXUNOPublisher.error")+": "+e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
if (!bResult) {
|
||||
MessageBox msgBox = new MessageBox(xContext, xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("LaTeXUNOPublisher.error")+": "+Messages.getString("LaTeXUNOPublisher.failedlatex")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
|
||||
private File getDirectory(short nType, String sDirectory) {
|
||||
switch (nType) {
|
||||
case 0: // absolute path
|
||||
return new File(sDirectory);
|
||||
case 1: // relative path
|
||||
return new File(Misc.urlToFile(getTargetPath()),sDirectory);
|
||||
default: // document directory
|
||||
return Misc.urlToFile(getTargetPath());
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileList(short nType, String sDirectory) {
|
||||
File dir = getDirectory(nType,sDirectory);
|
||||
File[] files;
|
||||
if (dir.isDirectory()) {
|
||||
files = dir.listFiles();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
CSVList filelist = new CSVList(","); //$NON-NLS-1$
|
||||
if (files!=null) {
|
||||
for (File file : files) {
|
||||
if (file.isFile() && file.getName().endsWith(".bib")) { //$NON-NLS-1$
|
||||
filelist.addValue(Misc.removeExtension(file.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return filelist.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LogViewerDialog.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-02-10)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import com.sun.star.awt.XDialog;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogAccess;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.DialogBase;
|
||||
|
||||
/** This class provides a uno component which displays logfiles
|
||||
*/
|
||||
public class LogViewerDialog extends DialogBase
|
||||
implements com.sun.star.lang.XInitialization {
|
||||
|
||||
/** The component will be registered under this name.
|
||||
*/
|
||||
public static String __serviceName = "org.openoffice.da.writer2latex.LogViewerDialog";
|
||||
|
||||
/** The component should also have an implementation name.
|
||||
*/
|
||||
public static String __implementationName = "org.openoffice.da.comp.writer2latex.LogViewerDialog";
|
||||
|
||||
/** Return the name of the library containing the dialog
|
||||
*/
|
||||
public String getDialogLibraryName() {
|
||||
return "W2LDialogs2";
|
||||
}
|
||||
|
||||
private String sBaseUrl = null;
|
||||
private String sLaTeXLog = null;
|
||||
private String sLaTeXErrors = null;
|
||||
private String sBibTeXLog = null;
|
||||
private String sMakeindexLog = null;
|
||||
|
||||
/** Return the name of the dialog within the library
|
||||
*/
|
||||
public String getDialogName() {
|
||||
return "LogViewer";
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (sBaseUrl!=null) {
|
||||
sLaTeXLog = readTextFile(sBaseUrl+".log");
|
||||
sLaTeXErrors = errorFilter(sLaTeXLog);
|
||||
sBibTeXLog = readTextFile(sBaseUrl+".blg");
|
||||
sMakeindexLog = readTextFile(sBaseUrl+".ilg");
|
||||
setComboBoxText("LogContents",sLaTeXLog);
|
||||
}
|
||||
}
|
||||
|
||||
public void endDialog() {
|
||||
}
|
||||
|
||||
/** Create a new LogViewerDialog */
|
||||
public LogViewerDialog(XComponentContext xContext) {
|
||||
super(xContext);
|
||||
}
|
||||
|
||||
// Implement com.sun.star.lang.XInitialization
|
||||
public void initialize( Object[] object )
|
||||
throws com.sun.star.uno.Exception {
|
||||
if ( object.length > 0 ) {
|
||||
if (object[0] instanceof String) {
|
||||
sBaseUrl = (String) object[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implement XDialogEventHandler
|
||||
public boolean callHandlerMethod(XDialog xDialog, Object event, String sMethod) {
|
||||
if (sMethod.equals("ViewLaTeXLog")) {
|
||||
setComboBoxText("LogContents",
|
||||
getCheckBoxState("ErrorFilter")==DialogAccess.CHECKBOX_CHECKED ? sLaTeXErrors : sLaTeXLog);
|
||||
setControlEnabled("ErrorFilter",true);
|
||||
}
|
||||
else if (sMethod.equals("ViewBibTeXLog")) {
|
||||
setComboBoxText("LogContents", sBibTeXLog);
|
||||
setControlEnabled("ErrorFilter",false);
|
||||
}
|
||||
else if (sMethod.equals("ViewMakeindexLog")) {
|
||||
setComboBoxText("LogContents", sMakeindexLog);
|
||||
setControlEnabled("ErrorFilter",false);
|
||||
}
|
||||
else if (sMethod.equals("ErrorFilterChange")) {
|
||||
setComboBoxText("LogContents",
|
||||
getCheckBoxState("ErrorFilter")==DialogAccess.CHECKBOX_CHECKED ? sLaTeXErrors : sLaTeXLog);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String[] getSupportedMethodNames() {
|
||||
String[] sNames = { "ViewLaTeXLog", "ViewBibTeXLog", "ViewMakeindexLog", "ErrorFilterChange" };
|
||||
return sNames;
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
|
||||
private String readTextFile(String sUrl) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
File file = new File(new URI(sUrl));
|
||||
if (file.exists() && file.isFile()) {
|
||||
InputStreamReader isr = new InputStreamReader(new FileInputStream(file));
|
||||
int n;
|
||||
do {
|
||||
n = isr.read();
|
||||
if (n>-1) { buf.append((char)n); }
|
||||
}
|
||||
while (n>-1);
|
||||
isr.close();
|
||||
}
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
return "";
|
||||
}
|
||||
catch (IOException e) {
|
||||
return "";
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Extract errors from LaTeX log file only
|
||||
private String errorFilter(String log) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int nLen = log.length();
|
||||
int nIndex = 0;
|
||||
boolean bIncludeLines = false;
|
||||
while (nIndex<nLen) {
|
||||
int nNewline = log.indexOf('\n', nIndex);
|
||||
if (nNewline==-1) nNewline = nLen;
|
||||
if (nNewline-nIndex>1 && log.charAt(nIndex)=='!') {
|
||||
bIncludeLines = true;
|
||||
}
|
||||
else if (nNewline==nIndex) {
|
||||
if (bIncludeLines) {
|
||||
buf.append('\n');
|
||||
}
|
||||
bIncludeLines = false;
|
||||
}
|
||||
if (bIncludeLines) {
|
||||
buf.append(log.substring(nIndex,nNewline)).append('\n');
|
||||
}
|
||||
nIndex = nNewline+1;
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* Messages.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-29)
|
||||
*
|
||||
*/
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class Messages {
|
||||
private static final String BUNDLE_NAME = "org.openoffice.da.comp.writer2latex.messages"; //$NON-NLS-1$
|
||||
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
private Messages() {
|
||||
}
|
||||
|
||||
public static String getString(String key) {
|
||||
try {
|
||||
return RESOURCE_BUNDLE.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* TeXDetectService.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2014-10-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter;
|
||||
import com.sun.star.lib.uno.helper.WeakBase;
|
||||
|
||||
import com.sun.star.beans.PropertyValue;
|
||||
import com.sun.star.document.XExtendedFilterDetection;
|
||||
import com.sun.star.lang.XServiceInfo;
|
||||
import com.sun.star.io.XInputStream;
|
||||
import com.sun.star.ucb.XSimpleFileAccess2;
|
||||
import com.sun.star.uno.AnyConverter;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
|
||||
|
||||
/** This class provides detect services for TeX documents
|
||||
* It is thus an implementation of the service com.sun.star.document.ExtendedTypeDetection
|
||||
*/
|
||||
|
||||
public class TeXDetectService extends WeakBase implements XExtendedFilterDetection, XServiceInfo {
|
||||
|
||||
// Constants
|
||||
|
||||
// Identify this service
|
||||
public static final String __implementationName = TeXDetectService.class.getName();
|
||||
public static final String __serviceName = "com.sun.star.document.ExtendedTypeDetection";
|
||||
private static final String[] m_serviceNames = { __serviceName };
|
||||
|
||||
// The type names
|
||||
private static final String LATEX_FILE = "org.openoffice.da.writer2latex.LaTeX_File";
|
||||
private static final String XELATEX_FILE = "org.openoffice.da.writer2latex.XeLaTeX_File";
|
||||
|
||||
// From constructor+initialization
|
||||
private final XComponentContext m_xContext;
|
||||
|
||||
/** Construct a new <code>TeXDetectService</code>
|
||||
*
|
||||
* @param xContext The Component Context
|
||||
*/
|
||||
public TeXDetectService( XComponentContext xContext ) {
|
||||
m_xContext = xContext;
|
||||
}
|
||||
|
||||
// Implement com.sun.star.lang.XServiceInfo:
|
||||
public String getImplementationName() {
|
||||
return __implementationName;
|
||||
}
|
||||
|
||||
public boolean supportsService( String sService ) {
|
||||
int len = m_serviceNames.length;
|
||||
|
||||
for(int i=0; i < len; i++) {
|
||||
if (sService.equals(m_serviceNames[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedServiceNames() {
|
||||
return m_serviceNames;
|
||||
}
|
||||
|
||||
// Implement XExtendedFilterDetection
|
||||
public String detect(PropertyValue[][] mediaDescriptor) {
|
||||
// Read the media properties
|
||||
String sURL = null;
|
||||
String sTypeName = null;
|
||||
if (mediaDescriptor.length>0) {
|
||||
int nLength = mediaDescriptor[0].length;
|
||||
for (int i=0; i<nLength; i++) {
|
||||
try {
|
||||
if (mediaDescriptor[0][i].Name.equals("URL")) {
|
||||
sURL = AnyConverter.toString(mediaDescriptor[0][i].Value);
|
||||
}
|
||||
else if (mediaDescriptor[0][i].Name.equals("TypeName")) {
|
||||
sTypeName = AnyConverter.toString(mediaDescriptor[0][i].Value);
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.lang.IllegalArgumentException e) {
|
||||
// AnyConverter failed to convert; ignore this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no URL, we cannot verify the type (this should never happen on proper use of the service)
|
||||
if (sURL==null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Also, we can only verify LaTeX and XeLaTeX
|
||||
if (sTypeName==null || !(sTypeName.equals(LATEX_FILE) || sTypeName.equals(XELATEX_FILE))) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Initialise the file access
|
||||
XSimpleFileAccess2 sfa2 = null;
|
||||
try {
|
||||
Object sfaObject = m_xContext.getServiceManager().createInstanceWithContext(
|
||||
"com.sun.star.ucb.SimpleFileAccess", m_xContext);
|
||||
sfa2 = (XSimpleFileAccess2) UnoRuntime.queryInterface(XSimpleFileAccess2.class, sfaObject);
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// failed to get SimpleFileAccess service (should not happen)
|
||||
return "";
|
||||
}
|
||||
|
||||
// Get the input stream
|
||||
XInputStreamToInputStreamAdapter is = null;
|
||||
try {
|
||||
XInputStream xis = sfa2.openFileRead(sURL);
|
||||
is = new XInputStreamToInputStreamAdapter(xis);
|
||||
}
|
||||
catch (com.sun.star.ucb.CommandAbortedException e) {
|
||||
// Failed to create input stream, cannot verify the type
|
||||
return "";
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
// Failed to create input stream, cannot verify the type
|
||||
return "";
|
||||
}
|
||||
|
||||
// Ask the deTeXtive
|
||||
DeTeXtive deTeXtive = new DeTeXtive();
|
||||
try {
|
||||
String sType = deTeXtive.deTeXt(is);
|
||||
if ("LaTeX".equals(sType)) {
|
||||
return LATEX_FILE;
|
||||
}
|
||||
else if ("XeLaTeX".equals(sType)) {
|
||||
return XELATEX_FILE;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Failed to read the stream, cannot verify the type
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,339 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* TeXImportFilter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2014-10-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
//import com.sun.star.lib.uno.helper.Factory;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
import com.sun.star.lib.uno.helper.WeakBase;
|
||||
import com.sun.star.document.XDocumentInsertable;
|
||||
import com.sun.star.lang.XServiceInfo;
|
||||
import com.sun.star.task.XStatusIndicator;
|
||||
import com.sun.star.text.XTextCursor;
|
||||
import com.sun.star.text.XTextDocument;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.AnyConverter;
|
||||
|
||||
import com.sun.star.beans.PropertyValue;
|
||||
import com.sun.star.lang.XInitialization;
|
||||
import com.sun.star.container.XNamed;
|
||||
import com.sun.star.document.XImporter;
|
||||
import com.sun.star.document.XFilter;
|
||||
|
||||
/** This class implements an import filter for TeX documents using TeX4ht
|
||||
* It is thus an implementation of the service com.sun.star.document.ImportFilter
|
||||
*/
|
||||
public class TeXImportFilter extends WeakBase implements XInitialization, XNamed, XImporter, XFilter, XServiceInfo {
|
||||
|
||||
// Constants
|
||||
|
||||
// Identify this service
|
||||
public static final String __implementationName = TeXImportFilter.class.getName();
|
||||
public static final String __serviceName = "com.sun.star.document.ImportFilter";
|
||||
private static final String[] m_serviceNames = { __serviceName };
|
||||
|
||||
// Possible states of the filtering process
|
||||
public static final int FILTERPROC_RUNNING = 0;
|
||||
public static final int FILTERPROC_BREAKING = 1;
|
||||
public static final int FILTERPROC_STOPPED = 2;
|
||||
|
||||
// Global data
|
||||
|
||||
// From constructor
|
||||
private final XComponentContext m_xContext;
|
||||
|
||||
// The filter name
|
||||
private String m_sFilterName;
|
||||
|
||||
// The target document for the import
|
||||
private com.sun.star.text.XTextDocument m_xTargetDoc;
|
||||
|
||||
// The current state of the filtering process
|
||||
private int m_nState;
|
||||
|
||||
/** Construct a new <code>TeXImportFilter</code>
|
||||
*
|
||||
* @param xContext The Component Context
|
||||
*/
|
||||
public TeXImportFilter( XComponentContext xContext ) {
|
||||
m_xContext = xContext;
|
||||
m_sFilterName = "";
|
||||
m_xTargetDoc = null;
|
||||
m_nState = FILTERPROC_STOPPED;
|
||||
}
|
||||
|
||||
// Implement com.sun.star.lang.XServiceInfo:
|
||||
public String getImplementationName() {
|
||||
return __implementationName;
|
||||
}
|
||||
|
||||
public boolean supportsService( String sService ) {
|
||||
int len = m_serviceNames.length;
|
||||
|
||||
for(int i=0; i < len; i++) {
|
||||
if (sService.equals(m_serviceNames[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedServiceNames() {
|
||||
return m_serviceNames;
|
||||
}
|
||||
|
||||
// The following methods may be called from multiple threads (e.g. if someone wants to cancel the filtering),
|
||||
// thus all access to class members must be synchronized
|
||||
|
||||
// Implement XInitialization:
|
||||
public void initialize( Object[] arguments ) throws com.sun.star.uno.Exception {
|
||||
if (arguments.length>0) {
|
||||
// The first argument contains configuration data, from which we extract the filter name for further reference
|
||||
// We need this to know which flavour of TeX we're supposed to handle
|
||||
PropertyValue[] config = (PropertyValue[]) arguments[0];
|
||||
int nLen = config.length;
|
||||
for (int i=0; i<nLen; i++) {
|
||||
if (config[i].Name.equals("Name")) {
|
||||
synchronized(this) {
|
||||
try {
|
||||
m_sFilterName = AnyConverter.toString(config[i].Value);
|
||||
}
|
||||
catch(com.sun.star.lang.IllegalArgumentException exConvert) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implement XNamed
|
||||
public String getName() {
|
||||
synchronized(this) {
|
||||
return m_sFilterName;
|
||||
}
|
||||
}
|
||||
|
||||
public void setName( String sName ) {
|
||||
// must be ignored as we cannot change the filter name
|
||||
}
|
||||
|
||||
// Implement XImporter
|
||||
public void setTargetDocument( com.sun.star.lang.XComponent xDocument ) throws com.sun.star.lang.IllegalArgumentException {
|
||||
// If there's no target document we cannot import into it
|
||||
if (xDocument==null)
|
||||
throw new com.sun.star.lang.IllegalArgumentException("Null pointer");
|
||||
|
||||
// And if it's not a text document we're out of luck too
|
||||
com.sun.star.lang.XServiceInfo xInfo = (com.sun.star.lang.XServiceInfo)UnoRuntime.queryInterface(
|
||||
com.sun.star.lang.XServiceInfo.class, xDocument);
|
||||
if (!xInfo.supportsService("com.sun.star.text.TextDocument"))
|
||||
throw new com.sun.star.lang.IllegalArgumentException("Wrong document type");
|
||||
|
||||
// Otherwise set the target document
|
||||
synchronized(this) {
|
||||
m_xTargetDoc = (com.sun.star.text.XTextDocument)UnoRuntime.queryInterface(
|
||||
com.sun.star.text.XTextDocument.class, xDocument);
|
||||
}
|
||||
}
|
||||
|
||||
// Implement XFilter:
|
||||
|
||||
/** Filter (import only) the document given by the media descriptor
|
||||
* According to the service contract, we should understand either of
|
||||
* the properties URL or InputStream, but currently we only use the former.
|
||||
* We also use the property StatusIndicator: OOo internally uses this to
|
||||
* pass around an XStatusIndicator instance, and if it's available we
|
||||
* use it to display a progress bar
|
||||
*
|
||||
* @param mediaDescriptor the Media Descriptor
|
||||
*/
|
||||
public boolean filter(com.sun.star.beans.PropertyValue[] mediaDescriptor) {
|
||||
// Extract values from the MediaDescriptor
|
||||
String sURL = null;
|
||||
XStatusIndicator xStatusIndicator = null;
|
||||
int nLength = mediaDescriptor.length;
|
||||
for (int i=0; i<nLength; i++) {
|
||||
try {
|
||||
if (mediaDescriptor[i].Name.equals("URL")) {
|
||||
sURL = AnyConverter.toString(mediaDescriptor[i].Value);
|
||||
}
|
||||
else if (mediaDescriptor[i].Name.equals("InputStream")) {
|
||||
// Ignore this currently
|
||||
}
|
||||
else if (mediaDescriptor[i].Name.equals("StatusIndicator")) {
|
||||
xStatusIndicator = (XStatusIndicator) AnyConverter.toObject(XStatusIndicator.class, mediaDescriptor[i].Value);
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.lang.IllegalArgumentException e) {
|
||||
// AnyConverter failed to convert; ignore this
|
||||
}
|
||||
}
|
||||
|
||||
if (sURL==null) {
|
||||
// Currently we need and URL to import
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the current value of the target document and mark the filtering process as running
|
||||
XTextDocument xText = null;
|
||||
synchronized(this) {
|
||||
if (m_nState!=FILTERPROC_STOPPED) {
|
||||
return false;
|
||||
}
|
||||
xText = m_xTargetDoc;
|
||||
m_nState = FILTERPROC_RUNNING;
|
||||
}
|
||||
|
||||
// Do the import
|
||||
boolean bResult = importTeX(xText,sURL,xStatusIndicator);
|
||||
m_nState = FILTERPROC_STOPPED;
|
||||
return bResult;
|
||||
}
|
||||
|
||||
/** Cancel the filtering process. This will not only trigger cancellation, but also wait until it's finished
|
||||
*/
|
||||
public void cancel() {
|
||||
// Change state to "breaking"
|
||||
synchronized(this) {
|
||||
if (m_nState==FILTERPROC_RUNNING) m_nState=FILTERPROC_BREAKING;
|
||||
}
|
||||
|
||||
// And wait until state has changed to "stopped"
|
||||
while (true) {
|
||||
synchronized(this) {
|
||||
if (m_nState==FILTERPROC_STOPPED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Private helper methods
|
||||
/** Import a TeX document with TeX4ht
|
||||
* @param xText into this document
|
||||
* @param sURL from the TeX document given by this URL
|
||||
*/
|
||||
public boolean importTeX(XTextDocument xText, String sURL, XStatusIndicator xStatus) {
|
||||
int nStep = 0;
|
||||
if (xStatus!=null) {
|
||||
xStatus.start("Writer2LaTeX",10);
|
||||
xStatus.setValue(++nStep);
|
||||
}
|
||||
|
||||
// Get the LaTeX file
|
||||
File file = null;
|
||||
try {
|
||||
file = new File(new URI(sURL));
|
||||
}
|
||||
catch (java.net.URISyntaxException e) {
|
||||
// Could not use the URL provided
|
||||
if (xStatus!=null) xStatus.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xStatus!=null) { xStatus.setValue(++nStep); }
|
||||
|
||||
// Protect the ODT file if it already exists
|
||||
String sBaseName = file.getName();
|
||||
if (sBaseName.endsWith(".tex")) { sBaseName = sBaseName.substring(0, sBaseName.length()-4); }
|
||||
File odtFile = new File(file.getParentFile(),sBaseName+".odt");
|
||||
File tempFile = null;
|
||||
if (odtFile.exists()) {
|
||||
try {
|
||||
tempFile = File.createTempFile("w2l", ".tmp", file.getParentFile());
|
||||
}
|
||||
catch (java.io.IOException e) {
|
||||
// Failed to protect the ODT file, give up
|
||||
if (xStatus!=null) xStatus.end();
|
||||
return false;
|
||||
}
|
||||
odtFile.renameTo(tempFile);
|
||||
}
|
||||
|
||||
if (xStatus!=null) { xStatus.setValue(++nStep); }
|
||||
|
||||
// Execute TeX4ht
|
||||
ExternalApps externalApps = new ExternalApps(m_xContext);
|
||||
externalApps.load();
|
||||
|
||||
if (xStatus!=null) { xStatus.setValue(++nStep); }
|
||||
|
||||
// Default is the filter org.openoffice.da.writer2latex.latex
|
||||
String sCommand = "oolatex";
|
||||
if ("org.openoffice.da.writer2latex.xelatex".equals(m_sFilterName)) {
|
||||
sCommand = "ooxelatex";
|
||||
}
|
||||
|
||||
externalApps.execute(ExternalApps.MK4HT, sCommand, file.getName(), file.getParentFile(), null, true);
|
||||
|
||||
if (xStatus!=null) { nStep+=5; xStatus.setValue(nStep); }
|
||||
|
||||
// Assemble the URL of the ODT file
|
||||
String sODTURL = sURL;
|
||||
if (sODTURL.endsWith(".tex")) { sODTURL = sODTURL.substring(0, sODTURL.length()-4); }
|
||||
sODTURL += ".odt";
|
||||
|
||||
// This is the only good time to test if we should cancel the import
|
||||
boolean bSuccess = true;
|
||||
synchronized(this) {
|
||||
if (m_nState==FILTERPROC_BREAKING) bSuccess = false;
|
||||
}
|
||||
|
||||
if (xStatus!=null) {
|
||||
xStatus.end();
|
||||
}
|
||||
|
||||
if (bSuccess) {
|
||||
// Load ODT file into the text document
|
||||
XTextCursor xTextCursor = xText.getText().createTextCursor();
|
||||
XDocumentInsertable xDocInsert = (XDocumentInsertable)
|
||||
UnoRuntime.queryInterface(XDocumentInsertable.class, xTextCursor);
|
||||
try {
|
||||
PropertyValue[] props = new PropertyValue[0];
|
||||
xDocInsert.insertDocumentFromURL(sODTURL, props);
|
||||
}
|
||||
catch (com.sun.star.lang.IllegalArgumentException e) {
|
||||
bSuccess = false;
|
||||
}
|
||||
catch (com.sun.star.io.IOException e) {
|
||||
bSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
odtFile.delete();
|
||||
// Restore origninal ODT file, if any
|
||||
if (tempFile!=null) {
|
||||
tempFile.renameTo(odtFile);
|
||||
}
|
||||
|
||||
return bSuccess;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* TeXify.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
/** This class builds LaTeX documents into DVI, Postscript or PDF and displays
|
||||
* the result.
|
||||
*/
|
||||
public final class TeXify {
|
||||
|
||||
/** Backend format generic (dvi) */
|
||||
public static final short GENERIC = 1;
|
||||
|
||||
/** Backend format dvips (postscript) */
|
||||
public static final short DVIPS = 2;
|
||||
|
||||
/** Backend format pdfTeX (pdf) */
|
||||
public static final short PDFTEX = 3;
|
||||
|
||||
/** Backend format XeTeX (also pdf, usually) */
|
||||
public static final short XETEX = 4;
|
||||
|
||||
// Define the applications to run for each backend
|
||||
private static final String[] genericTexify = {
|
||||
ExternalApps.LATEX, ExternalApps.BIBTEX, ExternalApps.MAKEINDEX,
|
||||
ExternalApps.LATEX, ExternalApps.MAKEINDEX, ExternalApps.LATEX };
|
||||
private static final String[] pdfTexify = {
|
||||
ExternalApps.PDFLATEX, ExternalApps.BIBTEX, ExternalApps.MAKEINDEX,
|
||||
ExternalApps.PDFLATEX, ExternalApps.MAKEINDEX, ExternalApps.PDFLATEX };
|
||||
private static final String[] dvipsTexify = {
|
||||
ExternalApps.LATEX, ExternalApps.BIBTEX, ExternalApps.MAKEINDEX,
|
||||
ExternalApps.LATEX, ExternalApps.MAKEINDEX, ExternalApps.LATEX,
|
||||
ExternalApps.DVIPS };
|
||||
private static final String[] xeTexify = {
|
||||
ExternalApps.XELATEX, ExternalApps.BIBTEX, ExternalApps.MAKEINDEX,
|
||||
ExternalApps.XELATEX, ExternalApps.MAKEINDEX, ExternalApps.XELATEX };
|
||||
|
||||
// Global objects
|
||||
private ExternalApps externalApps;
|
||||
|
||||
public TeXify(XComponentContext xContext) {
|
||||
externalApps = new ExternalApps(xContext);
|
||||
}
|
||||
|
||||
/** Process a document. This will either (depending on the registry settings) do nothing, build with LaTeX
|
||||
* or build with LaTeX and preview
|
||||
*
|
||||
* @param file the LaTeX file to process
|
||||
* @param sBibinputs value for the BIBINPUTS environment variable (or null if it should not be extended)
|
||||
* @param nBackend the desired backend format (generic, dvips, pdftex)
|
||||
* @param bView set the true if the result should be displayed in the viewer
|
||||
* @throws IOException if the document cannot be read
|
||||
* @return true if the first LaTeX run was successful
|
||||
*/
|
||||
public boolean process(File file, String sBibinputs, short nBackend, boolean bView) throws IOException {
|
||||
// Remove extension from file
|
||||
if (file.getName().endsWith(".tex")) { //$NON-NLS-1$
|
||||
file = new File(file.getParentFile(),
|
||||
file.getName().substring(0,file.getName().length()-4));
|
||||
}
|
||||
|
||||
// Update external apps from registry
|
||||
externalApps.load();
|
||||
|
||||
// Process LaTeX document
|
||||
if (externalApps.getProcessingLevel()>=ExternalApps.BUILD) {
|
||||
boolean bPreview = externalApps.getProcessingLevel()>=ExternalApps.PREVIEW;
|
||||
boolean bResult = false;
|
||||
if (nBackend==GENERIC) {
|
||||
bResult = doTeXify(genericTexify, file, sBibinputs);
|
||||
if (!bResult) return false;
|
||||
if (bPreview && externalApps.execute(ExternalApps.DVIVIEWER,
|
||||
new File(file.getParentFile(),file.getName()+".dvi").getPath(), //$NON-NLS-1$
|
||||
file.getParentFile(), null, false)>0) {
|
||||
throw new IOException(Messages.getString("TeXify.dviviewerror")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else if (nBackend==PDFTEX) {
|
||||
bResult = doTeXify(pdfTexify, file, sBibinputs);
|
||||
if (!bResult) return false;
|
||||
if (bPreview && externalApps.execute(ExternalApps.PDFVIEWER,
|
||||
new File(file.getParentFile(),file.getName()+".pdf").getPath(), //$NON-NLS-1$
|
||||
file.getParentFile(), null, false)>0) {
|
||||
throw new IOException(Messages.getString("TeXify.pdfviewerror")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else if (nBackend==DVIPS) {
|
||||
bResult = doTeXify(dvipsTexify, file, sBibinputs);
|
||||
if (!bResult) return false;
|
||||
if (bPreview && externalApps.execute(ExternalApps.POSTSCRIPTVIEWER,
|
||||
new File(file.getParentFile(),file.getName()+".ps").getPath(), //$NON-NLS-1$
|
||||
file.getParentFile(), null, false)>0) {
|
||||
throw new IOException(Messages.getString("TeXify.psviewerror")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
else if (nBackend==XETEX) {
|
||||
bResult = doTeXify(xeTexify, file, sBibinputs);
|
||||
if (!bResult) return false;
|
||||
if (bPreview && externalApps.execute(ExternalApps.PDFVIEWER,
|
||||
new File(file.getParentFile(),file.getName()+".pdf").getPath(), //$NON-NLS-1$
|
||||
file.getParentFile(), null, false)>0) {
|
||||
throw new IOException(Messages.getString("TeXify.pdfviewerror")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean doTeXify(String[] sAppList, File file, String sBibinputs) throws IOException {
|
||||
// Remove the .aux file first (to avoid potential error messages)
|
||||
File aux = new File(file.getParentFile(), file.getName()+".aux"); //$NON-NLS-1$
|
||||
aux.delete();
|
||||
for (int i=0; i<sAppList.length; i++) {
|
||||
// Execute external application
|
||||
Map<String,String> env =null;
|
||||
if (ExternalApps.BIBTEX.equals(sAppList[i]) && sBibinputs!=null) {
|
||||
env = new HashMap<String,String>();
|
||||
env.put("BIBINPUTS", sBibinputs); //$NON-NLS-1$
|
||||
}
|
||||
int nReturnCode = externalApps.execute(
|
||||
sAppList[i], file.getName(), file.getParentFile(), env, true);
|
||||
if (i==0 && nReturnCode>0) {
|
||||
return false;
|
||||
//throw new IOException("Error executing "+sAppList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* W2LExportFilter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2014-10-06)
|
||||
*
|
||||
*/
|
||||
|
||||
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 final String __displayName = "Writer2LaTeX";
|
||||
|
||||
public W2LExportFilter(XComponentContext xComponentContext1) {
|
||||
super(xComponentContext1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* W2LRegistration.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2014-12-11)
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
else if (implName.equals(ConfigurationDialog.__implementationName)) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(ConfigurationDialog.class,
|
||||
ConfigurationDialog.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(Writer2LaTeX.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(Writer2LaTeX.class,
|
||||
Writer2LaTeX.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(TeXImportFilter.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(TeXImportFilter.class,
|
||||
TeXImportFilter.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(TeXDetectService.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(TeXDetectService.class,
|
||||
TeXDetectService.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(ApplicationsDialog.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(ApplicationsDialog.class,
|
||||
ApplicationsDialog.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(BibliographyDialog.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(BibliographyDialog.class,
|
||||
BibliographyDialog.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(LogViewerDialog.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(LogViewerDialog.class,
|
||||
LogViewerDialog.__serviceName,
|
||||
multiFactory,
|
||||
regKey);
|
||||
}
|
||||
else if (implName.equals(BibTeXDialog.__implementationName) ) {
|
||||
xSingleServiceFactory = FactoryHelper.getServiceFactory(BibTeXDialog.class,
|
||||
BibTeXDialog.__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) &
|
||||
FactoryHelper.writeRegistryServiceInfo(ConfigurationDialog.__implementationName,
|
||||
ConfigurationDialog.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(Writer2LaTeX.__implementationName,
|
||||
Writer2LaTeX.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(TeXImportFilter.__implementationName,
|
||||
TeXImportFilter.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(TeXDetectService.__implementationName,
|
||||
TeXDetectService.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(ApplicationsDialog.__implementationName,
|
||||
ApplicationsDialog.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(BibliographyDialog.__implementationName,
|
||||
BibliographyDialog.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(LogViewerDialog.__implementationName,
|
||||
LogViewerDialog.__serviceName, regKey) &
|
||||
FactoryHelper.writeRegistryServiceInfo(BibTeXDialog.__implementationName,
|
||||
BibTeXDialog.__serviceName, regKey);
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* W2LStarMathConverter.java
|
||||
*
|
||||
* Copyright: 2002-2008 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* Writer2LaTeX.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package org.openoffice.da.comp.writer2latex;
|
||||
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.frame.XFrame;
|
||||
import com.sun.star.lib.uno.helper.WeakBase;
|
||||
import com.sun.star.ui.dialogs.ExecutableDialogResults;
|
||||
import com.sun.star.ui.dialogs.XExecutableDialog;
|
||||
import com.sun.star.uno.Exception;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
import org.openoffice.da.comp.w2lcommon.filter.UNOPublisher.TargetFormat;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.MessageBox;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.RegistryHelper;
|
||||
import org.openoffice.da.comp.w2lcommon.helper.XPropertySetHelper;
|
||||
|
||||
/** This class implements the ui (dispatch) commands provided by the Writer2LaTeX toolbar.
|
||||
* The actual processing is done by the core classes <code>UNOPublisher</code>,
|
||||
* <code>LaTeXImporter</code> and the dialogs
|
||||
*/
|
||||
public final class Writer2LaTeX extends WeakBase
|
||||
implements com.sun.star.lang.XServiceInfo,
|
||||
com.sun.star.frame.XDispatchProvider,
|
||||
com.sun.star.lang.XInitialization,
|
||||
com.sun.star.frame.XDispatch {
|
||||
|
||||
private static final String PROTOCOL = "org.openoffice.da.writer2latex:"; //$NON-NLS-1$
|
||||
|
||||
// From constructor+initialization
|
||||
private final XComponentContext m_xContext;
|
||||
private XFrame m_xFrame;
|
||||
private LaTeXUNOPublisher unoPublisher = null;
|
||||
|
||||
public static final String __implementationName = Writer2LaTeX.class.getName();
|
||||
public static final String __serviceName = "com.sun.star.frame.ProtocolHandler"; //$NON-NLS-1$
|
||||
private static final String[] m_serviceNames = { __serviceName };
|
||||
|
||||
public Writer2LaTeX( XComponentContext xContext ) {
|
||||
m_xContext = xContext;
|
||||
}
|
||||
|
||||
// com.sun.star.lang.XInitialization:
|
||||
public void initialize( Object[] object )
|
||||
throws com.sun.star.uno.Exception {
|
||||
if ( object.length > 0 ) {
|
||||
// The first item is the current frame
|
||||
m_xFrame = (com.sun.star.frame.XFrame) UnoRuntime.queryInterface(
|
||||
com.sun.star.frame.XFrame.class, object[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// com.sun.star.lang.XServiceInfo:
|
||||
public String getImplementationName() {
|
||||
return __implementationName;
|
||||
}
|
||||
|
||||
public boolean supportsService( String sService ) {
|
||||
int len = m_serviceNames.length;
|
||||
|
||||
for( int i=0; i < len; i++) {
|
||||
if (sService.equals(m_serviceNames[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedServiceNames() {
|
||||
return m_serviceNames;
|
||||
}
|
||||
|
||||
|
||||
// com.sun.star.frame.XDispatchProvider:
|
||||
public com.sun.star.frame.XDispatch queryDispatch( com.sun.star.util.URL aURL,
|
||||
String sTargetFrameName, int iSearchFlags ) {
|
||||
if ( aURL.Protocol.compareTo(PROTOCOL) == 0 ) {
|
||||
if ( aURL.Path.compareTo("ProcessDocument") == 0 ) //$NON-NLS-1$
|
||||
return this;
|
||||
else if ( aURL.Path.compareTo("ViewLog") == 0 ) //$NON-NLS-1$
|
||||
return this;
|
||||
else if ( aURL.Path.compareTo("InsertBibTeX") == 0 ) //$NON-NLS-1$
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public com.sun.star.frame.XDispatch[] queryDispatches(
|
||||
com.sun.star.frame.DispatchDescriptor[] seqDescriptors ) {
|
||||
int nCount = seqDescriptors.length;
|
||||
com.sun.star.frame.XDispatch[] seqDispatcher =
|
||||
new com.sun.star.frame.XDispatch[seqDescriptors.length];
|
||||
|
||||
for( int i=0; i < nCount; ++i ) {
|
||||
seqDispatcher[i] = queryDispatch(seqDescriptors[i].FeatureURL,
|
||||
seqDescriptors[i].FrameName,
|
||||
seqDescriptors[i].SearchFlags );
|
||||
}
|
||||
return seqDispatcher;
|
||||
}
|
||||
|
||||
|
||||
// com.sun.star.frame.XDispatch:
|
||||
public void dispatch( com.sun.star.util.URL aURL,
|
||||
com.sun.star.beans.PropertyValue[] aArguments ) {
|
||||
if ( aURL.Protocol.compareTo(PROTOCOL) == 0 ) {
|
||||
if ( aURL.Path.compareTo("ProcessDocument") == 0 ) { //$NON-NLS-1$
|
||||
process();
|
||||
return;
|
||||
}
|
||||
else if ( aURL.Path.compareTo("ViewLog") == 0 ) { //$NON-NLS-1$
|
||||
viewLog();
|
||||
return;
|
||||
}
|
||||
else if ( aURL.Path.compareTo("InsertBibTeX") == 0 ) { //$NON-NLS-1$
|
||||
insertBibTeX();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addStatusListener( com.sun.star.frame.XStatusListener xControl,
|
||||
com.sun.star.util.URL aURL ) {
|
||||
}
|
||||
|
||||
public void removeStatusListener( com.sun.star.frame.XStatusListener xControl,
|
||||
com.sun.star.util.URL aURL ) {
|
||||
}
|
||||
|
||||
// The actual commands...
|
||||
|
||||
private void process() {
|
||||
createUNOPublisher();
|
||||
unoPublisher.publish(TargetFormat.latex);
|
||||
}
|
||||
|
||||
private void viewLog() {
|
||||
createUNOPublisher();
|
||||
if (unoPublisher.documentSaved()) {
|
||||
// Execute the log viewer dialog
|
||||
try {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = unoPublisher.getTargetPath()+unoPublisher.getTargetFileName();
|
||||
Object dialog = m_xContext.getServiceManager()
|
||||
.createInstanceWithArgumentsAndContext(
|
||||
"org.openoffice.da.writer2latex.LogViewerDialog", args, m_xContext); //$NON-NLS-1$
|
||||
XExecutableDialog xDialog = (XExecutableDialog)
|
||||
UnoRuntime.queryInterface(XExecutableDialog.class, dialog);
|
||||
if (xDialog.execute()==ExecutableDialogResults.OK) {
|
||||
// Closed with the close button
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void insertBibTeX() {
|
||||
if (useExternalBibTeXFiles()) {
|
||||
createUNOPublisher();
|
||||
if (unoPublisher.documentSaved()) {
|
||||
// Execute the BibTeX dialog
|
||||
try {
|
||||
// The dialog needs the current frame and the path to the BibTeX directory
|
||||
Object[] args = new Object[2];
|
||||
args[0] = m_xFrame;
|
||||
args[1] = unoPublisher.getBibTeXDirectory().getPath();
|
||||
Object dialog = m_xContext.getServiceManager()
|
||||
.createInstanceWithArgumentsAndContext(
|
||||
"org.openoffice.da.writer2latex.BibTeXDialog", args, m_xContext); //$NON-NLS-1$
|
||||
XExecutableDialog xDialog = (XExecutableDialog)
|
||||
UnoRuntime.queryInterface(XExecutableDialog.class, dialog);
|
||||
if (xDialog.execute()==ExecutableDialogResults.OK) {
|
||||
// Closed with the close button
|
||||
}
|
||||
}
|
||||
catch (com.sun.star.uno.Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
MessageBox msgBox = new MessageBox(m_xContext, m_xFrame);
|
||||
msgBox.showMessage("Writer2LaTeX",Messages.getString("Writer2LaTeX.bibtexnotenabled")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useExternalBibTeXFiles() {
|
||||
// Get the BibTeX settings from the registry
|
||||
RegistryHelper registry = new RegistryHelper(m_xContext);
|
||||
Object view;
|
||||
try {
|
||||
view = registry.getRegistryView(BibliographyDialog.REGISTRY_PATH, false);
|
||||
} catch (Exception e) {
|
||||
// Failed to get registry settings
|
||||
return false;
|
||||
}
|
||||
XPropertySet xProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,view);
|
||||
return XPropertySetHelper.getPropertyValueAsBoolean(xProps, "UseExternalBibTeXFiles"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private void createUNOPublisher() {
|
||||
if (unoPublisher==null) {
|
||||
unoPublisher = new LaTeXUNOPublisher(m_xContext,m_xFrame,"Writer2LaTeX"); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
ApplicationsDialog.configresults=Results of configuration
|
||||
ApplicationsDialog.failedtofind=Failed to find
|
||||
ApplicationsDialog.failedtofindmiktex=Failed to find MikTeX
|
||||
ApplicationsDialog.found=Found
|
||||
ApplicationsDialog.foundgsview=Found gsview
|
||||
ApplicationsDialog.foundmiktex=Found MikTeX
|
||||
ApplicationsDialog.miktexdefaultconfig=Writer2LaTeX has been configured to work if MikTeX is added to your path
|
||||
ApplicationsDialog.ok=OK
|
||||
ApplicationsDialog.pdfdefaultviewer=Using default application for PDF
|
||||
ApplicationsDialog.psdefaultviewer=Using default application for PostScript
|
||||
ApplicationsDialog.systemident=Your system identifies itself as
|
||||
ApplicationsDialog.usingdefaultapp=Using default application as
|
||||
ApplicationsDialog.version=version
|
||||
BibliographyDialog.nobibtexfiles=Warning: The selected directory does not contain any BibTeX files
|
||||
BibTeXDialog.allbibfieldsupdated=All bibliography fields were updated
|
||||
BibTeXDialog.alreadyexists=already exists
|
||||
BibTeXDialog.bibfieldsnotupdated=The following bibliography fields were not updated
|
||||
BibTeXDialog.errorreadingfile=There was an error reading this file
|
||||
BibTeXDialog.failedbibtexeditor=Error: Failed to open file with BibTeX editor
|
||||
BibTeXDialog.filenameempty=The file name is empty
|
||||
BibTeXDialog.nobibtexeditor=Error: No BibTeX editor was found
|
||||
BibTeXDialog.nobibtexfiles=No BibTeX files were found
|
||||
BibTeXDialog.noentries=This file does not contain any entries
|
||||
BibTeXDialog.noinformation=No information
|
||||
BibTeXDialog.thefile=The file
|
||||
ExternalApps.dviviewer=DVI Viewer
|
||||
ExternalApps.pdfviewer=PDF Viewer
|
||||
ExternalApps.psviewer=PostScript Viewer
|
||||
LaTeXUNOPublisher.error=Error
|
||||
LaTeXUNOPublisher.failedlatex=Failed to execute LaTeX - see log for details
|
||||
TeXify.dviviewerror=Error executing DVI viewer
|
||||
TeXify.pdfviewerror=Error executing PDF viewer
|
||||
TeXify.psviewerror=Error executing PostScript viewer
|
||||
Writer2LaTeX.bibtexnotenabled=Writer2LaTeX is not configured to use external BibTeX files for citations
|
|
@ -1,34 +0,0 @@
|
|||
ApplicationsDialog.configresults=Resultat af konfigurationen
|
||||
ApplicationsDialog.failedtofind=Fandt ikke
|
||||
ApplicationsDialog.failedtofindmiktex=Fandt ikke MikTeX
|
||||
ApplicationsDialog.found=Fandt
|
||||
ApplicationsDialog.foundgsview=Fandt gsview
|
||||
ApplicationsDialog.foundmiktex=Fandt MikTeX
|
||||
ApplicationsDialog.miktexdefaultconfig=Writer2LaTeX er blevet konfigureret så det virker hvis MikTeX tilføjes til din PATH
|
||||
ApplicationsDialog.ok=o.k.
|
||||
ApplicationsDialog.pdfdefaultviewer=Bruger standardprogram til PDF
|
||||
ApplicationsDialog.psdefaultviewer=Bruger standardprogram til PostScript
|
||||
ApplicationsDialog.systemident=Dit system identificerer sig som
|
||||
ApplicationsDialog.usingdefaultapp=Bruger standardprogram som
|
||||
ApplicationsDialog.version=version
|
||||
BibliographyDialog.nobibtexfiles=Advarsel: Den valgte mappe indeholder ingen BibTeX filer
|
||||
BibTeXDialog.allbibfieldsupdated=Alle litteraturlisteelementer blev opdateret
|
||||
BibTeXDialog.alreadyexists=findes allerede
|
||||
BibTeXDialog.bibfieldsnotupdated=Følgende litteraturlisteelementer blev ikke opdateret
|
||||
BibTeXDialog.errorreadingfile=Der skete en fejl ved læsning af denne fil
|
||||
BibTeXDialog.failedbibtexeditor=Fejl: Kunne ikke åbne filen med BibTeX-redigeringsprogrammet
|
||||
BibTeXDialog.filenameempty=Filnavnet er tomt
|
||||
BibTeXDialog.nobibtexeditor=Fejl: Kunne ikke finde et BibTeX-redigeringsprogram
|
||||
BibTeXDialog.nobibtexfiles=Fandt ingen BibTeX filer
|
||||
BibTeXDialog.noentries=Filen indeholder ingen elementer
|
||||
BibTeXDialog.noinformation=Ingen information
|
||||
BibTeXDialog.thefile=Filen
|
||||
ExternalApps.dviviewer=DVI-fremviser
|
||||
ExternalApps.pdfviewer=PDF-fremviser
|
||||
ExternalApps.psviewer=PostScript-fremviser
|
||||
LaTeXUNOPublisher.error=Fejl
|
||||
LaTeXUNOPublisher.failedlatex=Kunne ikke køre LaTeX - se loggen for detaljer
|
||||
TeXify.dviviewerror=Fejl ved åbning af DVI-fremviser
|
||||
TeXify.pdfviewerror=Fejl ved åbning af PDF-fremviser
|
||||
TeXify.psviewerror=Fejl ved åbning af PostScript-fremviser
|
||||
Writer2LaTeX.bibtexnotenabled=Writer2LaTeX er ikke sat op til at bruge eksterne BibTeX-filer til litteraturhenvisninger
|
|
@ -1,167 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BibTeXDocument.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-01)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.bibtex;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.api.ConverterFactory;
|
||||
import writer2latex.api.MIMETypes;
|
||||
import writer2latex.api.OutputFile;
|
||||
import writer2latex.latex.LaTeXConfig;
|
||||
import writer2latex.latex.i18n.ClassicI18n;
|
||||
import writer2latex.latex.i18n.I18n;
|
||||
import writer2latex.util.ExportNameCollection;
|
||||
import writer2latex.office.BibMark;
|
||||
import writer2latex.office.BibMark.EntryType;
|
||||
import writer2latex.office.OfficeReader;
|
||||
|
||||
/** Class representing a BibTeX document
|
||||
*/
|
||||
public class BibTeXDocument implements OutputFile {
|
||||
private static final String FILE_EXTENSION = ".bib";
|
||||
|
||||
private String sName;
|
||||
private Hashtable<String, BibMark> entries = new Hashtable<String, BibMark>();
|
||||
private ExportNameCollection exportNames = new ExportNameCollection("",true,"_-:");
|
||||
private I18n i18n;
|
||||
|
||||
private boolean bIsMaster;
|
||||
|
||||
/** Constructs a new BibTeX Document based on an office document
|
||||
*
|
||||
* @param sName The name of the document
|
||||
* @param bIsMaster is this a master document?
|
||||
* @param ofr the office document
|
||||
*/
|
||||
public BibTeXDocument(String sName, boolean bIsMaster, OfficeReader ofr) {
|
||||
this.sName = sName;
|
||||
this.bIsMaster = bIsMaster;
|
||||
loadEntries(ofr);
|
||||
// Use default config (only ascii, no extra font packages)
|
||||
i18n = new ClassicI18n(new LaTeXConfig());
|
||||
}
|
||||
|
||||
private void loadEntries(OfficeReader ofr) {
|
||||
List<Element> bibMarks = ofr.getBibliographyMarks();
|
||||
for (Element bibMark : bibMarks) {
|
||||
BibMark entry = new BibMark(bibMark);
|
||||
entries.put(entry.getIdentifier(),entry);
|
||||
exportNames.addName(entry.getIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
// Methods to query the content
|
||||
|
||||
/** Test whether or not this BibTeX document contains any entries
|
||||
*
|
||||
* @return true if there is one or more entries in the document
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return entries.size()==0;
|
||||
}
|
||||
|
||||
/** Get export name for an identifier
|
||||
*
|
||||
* @param sIdentifier the identifier
|
||||
* @return the export name
|
||||
*/
|
||||
public String getExportName(String sIdentifier) {
|
||||
return exportNames.addToExport(sIdentifier);
|
||||
}
|
||||
|
||||
/** Returns the document name without file extension
|
||||
*
|
||||
* @return the document name without file extension
|
||||
*/
|
||||
public String getName() {
|
||||
return sName;
|
||||
}
|
||||
|
||||
// Implement writer2latex.api.OutputFile
|
||||
|
||||
public String getFileName() {
|
||||
return new String(sName + FILE_EXTENSION);
|
||||
}
|
||||
|
||||
public String getMIMEType() {
|
||||
return MIMETypes.BIBTEX;
|
||||
}
|
||||
|
||||
public boolean isMasterDocument() {
|
||||
return bIsMaster;
|
||||
}
|
||||
|
||||
public boolean containsMath() {
|
||||
return false;
|
||||
}
|
||||
|
||||
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://writer2latex.sourceforge.net for more info.\n");
|
||||
osw.write("\n");
|
||||
Enumeration<BibMark> enumeration = entries.elements();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
BibMark entry = enumeration.nextElement();
|
||||
osw.write("@");
|
||||
osw.write(entry.getEntryType().toUpperCase());
|
||||
osw.write("{");
|
||||
osw.write(exportNames.addToExport(entry.getIdentifier()));
|
||||
osw.write(",\n");
|
||||
for (EntryType entryType : EntryType.values()) {
|
||||
String sValue = entry.getField(entryType);
|
||||
if (sValue!=null) {
|
||||
if (entryType==EntryType.author || entryType==EntryType.editor) {
|
||||
// OOo uses ; to separate authors and editors - BibTeX uses and
|
||||
sValue = sValue.replaceAll(";" , " and ");
|
||||
}
|
||||
osw.write(" ");
|
||||
osw.write(BibTeXEntryMap.getFieldName(entryType).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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* Converter.java
|
||||
*
|
||||
* Copyright: 2001-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-22)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.bibtex;
|
||||
|
||||
import writer2latex.api.Config;
|
||||
import writer2latex.base.ConverterBase;
|
||||
import writer2latex.latex.LaTeXConfig;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/** This class exports bibliographic information from an OpenDocument text file to a BibTeX data file
|
||||
*/
|
||||
public final class Converter extends ConverterBase {
|
||||
|
||||
// Implement converter API
|
||||
|
||||
// TODO: Doesn't really use the configuration - should use some fake config
|
||||
private LaTeXConfig config;
|
||||
|
||||
public Converter() {
|
||||
super();
|
||||
config = new LaTeXConfig();
|
||||
}
|
||||
|
||||
public Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
// Extend converter base
|
||||
|
||||
/** Convert the document into BibTeX format.</p>
|
||||
*
|
||||
* @throws IOException If any I/O error occurs.
|
||||
*/
|
||||
@Override public void convertInner() throws IOException {
|
||||
sTargetFileName = Misc.trimDocumentName(sTargetFileName,".bib");
|
||||
|
||||
BibTeXDocument bibDoc = new BibTeXDocument(sTargetFileName,true,ofr);
|
||||
|
||||
converterResult.addDocument(bibDoc);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BibConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-27)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.base.BibliographyGenerator;
|
||||
import writer2latex.bibtex.BibTeXDocument;
|
||||
|
||||
import writer2latex.latex.i18n.ClassicI18n;
|
||||
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 handles bibliographic citations and the bibliography. The result depends on these
|
||||
* configuration options:
|
||||
* <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
|
||||
* a thebibliography environment
|
||||
* <li><code>bibtex_style</code> If BibTeX is used, this style will be applied
|
||||
* </ul>
|
||||
* The citations will always be exported as \cite commands.
|
||||
*/
|
||||
class BibConverter extends ConverterHelper {
|
||||
|
||||
private BibTeXDocument bibDoc = null;
|
||||
private boolean bUseBibTeX;
|
||||
private String sBibTeXEncoding = null;
|
||||
private String sDocumentEncoding = null;
|
||||
|
||||
/** Construct a new BibConverter.
|
||||
*
|
||||
* @param config the configuration to use
|
||||
* @param palette the ConverterPalette to use
|
||||
*/
|
||||
BibConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
|
||||
// We need to create a BibTeX document except if we are using external BibTeX files
|
||||
if (!(config.useBibtex() && config.externalBibtexFiles().length()>0)) {
|
||||
bibDoc = new BibTeXDocument(palette.getOutFileName(),false,ofr);
|
||||
}
|
||||
|
||||
// We need to use a different encoding for the BibTeX files
|
||||
if (config.externalBibtexFiles().length()>0) {
|
||||
int nBibTeXEncoding = config.getBibtexEncoding();
|
||||
int nDocumentEncoding = config.getInputencoding();
|
||||
if (config.getBackend()!=LaTeXConfig.XETEX && nBibTeXEncoding>-1 && nBibTeXEncoding!=nDocumentEncoding) {
|
||||
sBibTeXEncoding = ClassicI18n.writeInputenc(nBibTeXEncoding);
|
||||
sDocumentEncoding = ClassicI18n.writeInputenc(nDocumentEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to export it
|
||||
bUseBibTeX = config.useBibtex();
|
||||
}
|
||||
|
||||
/** Export the bibliography directly as a thebibliography environment (as an alternative to using BibTeX)
|
||||
*/
|
||||
private class ThebibliographyGenerator extends BibliographyGenerator {
|
||||
// The bibliography is the be inserted in this LaTeX document portion with that context
|
||||
private LaTeXDocumentPortion ldp;
|
||||
private Context context;
|
||||
|
||||
// The current bibliography item is to formatted with this before/after pair with that context
|
||||
private BeforeAfter itemBa = null;
|
||||
private Context itemContext = null;
|
||||
|
||||
ThebibliographyGenerator(OfficeReader ofr) {
|
||||
super(ofr,true);
|
||||
}
|
||||
|
||||
void handleBibliography(Element bibliography, LaTeXDocumentPortion ldp, Context context) {
|
||||
this.ldp = ldp;
|
||||
this.context = context;
|
||||
|
||||
String sWidestLabel = "";
|
||||
Collection<String> labels = getLabels();
|
||||
for (String sLabel : labels) {
|
||||
if (sLabel.length()>=sWidestLabel.length()) {
|
||||
sWidestLabel = sLabel;
|
||||
}
|
||||
}
|
||||
|
||||
ldp.append("\\begin{thebibliography}{").append(sWidestLabel).append("}\n");
|
||||
generateBibliography(bibliography);
|
||||
endBibliographyItem();
|
||||
ldp.append("\\end{thebibliography}\n");
|
||||
}
|
||||
|
||||
@Override protected void insertBibliographyItem(String sStyleName, String sKey) {
|
||||
endBibliographyItem();
|
||||
|
||||
itemBa = new BeforeAfter();
|
||||
itemContext = (Context) context.clone();
|
||||
|
||||
// Apply paragraph style (character formatting only)
|
||||
StyleWithProperties style = ofr.getParStyle(sStyleName);
|
||||
if (style!=null) {
|
||||
palette.getI18n().applyLanguage(style,true,true,itemBa);
|
||||
palette.getCharSc().applyFont(style,true,true,itemBa,itemContext);
|
||||
if (itemBa.getBefore().length()>0) {
|
||||
itemBa.add(" ","");
|
||||
itemBa.enclose("{", "}");
|
||||
}
|
||||
}
|
||||
|
||||
// Convert item
|
||||
ldp.append(itemBa.getBefore());
|
||||
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(style));
|
||||
|
||||
ldp.append("\\bibitem");
|
||||
if (!isNumberedEntries()) {
|
||||
ldp.append("[").append(bibDoc.getExportName(sKey)).append("]");
|
||||
}
|
||||
ldp.append("{").append(bibDoc.getExportName(sKey)).append("} ");
|
||||
}
|
||||
|
||||
private void endBibliographyItem() {
|
||||
if (itemBa!=null) {
|
||||
palette.getI18n().popSpecialTable();
|
||||
ldp.append(itemBa.getAfter()).append("\n");
|
||||
itemBa = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void insertBibliographyItemElement(String sStyleName, String sText) {
|
||||
BeforeAfter ba = new BeforeAfter();
|
||||
Context elementContext = (Context) itemContext.clone();
|
||||
|
||||
// Apply character style
|
||||
StyleWithProperties style = ofr.getTextStyle(sStyleName);
|
||||
palette.getCharSc().applyTextStyle(sStyleName,ba,elementContext);
|
||||
|
||||
// Convert text
|
||||
ldp.append(ba.getBefore());
|
||||
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(style));
|
||||
ldp.append(palette.getI18n().convert(sText, false, elementContext.getLang()));
|
||||
palette.getI18n().popSpecialTable();
|
||||
ldp.append(ba.getAfter());
|
||||
}
|
||||
}
|
||||
|
||||
/** Append declarations needed by the <code>BibConverter</code> to the preamble.
|
||||
*
|
||||
* @param pack the LaTeXDocumentPortion to which declarations of packages (\\usepackage) should be added.
|
||||
* @param decl the LaTeXDocumentPortion to which other declarations should be added.
|
||||
*/
|
||||
void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
// Currently nothing
|
||||
}
|
||||
|
||||
/** Process a bibliography
|
||||
*
|
||||
* @param node A text:bibliography element
|
||||
* @param ldp the LaTeXDocumentPortion to which LaTeX code should be added
|
||||
* @param oc the current context
|
||||
*/
|
||||
void handleBibliography(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
if (!config.noIndex()) {
|
||||
if (config.useBibtex()) { // Export using BibTeX
|
||||
handleBibliographyAsBibTeX(ldp);
|
||||
}
|
||||
else { // Export as thebibliography environment
|
||||
ThebibliographyGenerator bibCv = new ThebibliographyGenerator(ofr);
|
||||
Element source = Misc.getChildByTagName(node,XMLString.TEXT_BIBLIOGRAPHY_SOURCE);
|
||||
bibCv.handleBibliography(source, ldp, oc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBibliographyAsBibTeX(LaTeXDocumentPortion ldp) {
|
||||
// Use the style given in the configuration
|
||||
ldp.append("\\bibliographystyle{")
|
||||
.append(config.bibtexStyle())
|
||||
.append("}").nl();
|
||||
|
||||
// Use BibTeX file from configuration, or exported BibTeX file
|
||||
// TODO: For XeTeX, probably use \XeTeXdefaultencoding?
|
||||
if (config.externalBibtexFiles().length()>0) {
|
||||
if (sBibTeXEncoding!=null) {
|
||||
ldp.append("\\inputencoding{").append(sBibTeXEncoding).append("}").nl();
|
||||
}
|
||||
ldp.append("\\bibliography{")
|
||||
.append(config.externalBibtexFiles())
|
||||
.append("}").nl();
|
||||
if (sBibTeXEncoding!=null) {
|
||||
ldp.append("\\inputencoding{").append(sDocumentEncoding).append("}").nl();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ldp.append("\\bibliography{")
|
||||
.append(bibDoc.getName())
|
||||
.append("}").nl();
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a Bibliography Mark
|
||||
* @param node a text:bibliography-mark element
|
||||
* @param ldp the LaTeXDocumentPortion to which LaTeX code should be added
|
||||
* @param oc the current context
|
||||
*/
|
||||
void handleBibliographyMark(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
String sIdentifier = node.getAttribute(XMLString.TEXT_IDENTIFIER);
|
||||
if (sIdentifier!=null) {
|
||||
// Use original citation if using external files; stripped if exporting BibTeX
|
||||
ldp.append("\\cite{")
|
||||
.append(config.externalBibtexFiles().length()==0 ? bibDoc.getExportName(sIdentifier) : sIdentifier)
|
||||
.append("}");
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the BibTeX document, if any (that is if the document contains bibliographic data <em>and</em>
|
||||
* the configuration does not specify external BibTeX files)
|
||||
*
|
||||
* @return the BiBTeXDocument, or null if no BibTeX file is needed
|
||||
*/
|
||||
BibTeXDocument getBibTeXDocument() {
|
||||
if (bUseBibTeX && bibDoc!=null && !bibDoc.isEmpty()) {
|
||||
return bibDoc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BlockConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-15)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import writer2latex.latex.util.Context;
|
||||
import writer2latex.latex.util.StyleMap;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/**
|
||||
* This class handles basic block content, such as 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
|
||||
palette.getListCv().handleList(child,ldp,ic);
|
||||
}
|
||||
|
||||
else if (sTagName.equals(XMLString.TEXT_UNORDERED_LIST)) {
|
||||
palette.getListCv().handleList(child,ldp,ic);
|
||||
}
|
||||
|
||||
else if (sTagName.equals(XMLString.TEXT_ORDERED_LIST)) {
|
||||
palette.getListCv().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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* CaptionConverter.java
|
||||
*
|
||||
* Copyright: 2002-2008 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,508 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* CharStyleConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-30)
|
||||
*
|
||||
*/
|
||||
|
||||
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<String, String> fontDecls = new Hashtable<String, String>();
|
||||
|
||||
// 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("\\providecommand\\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));
|
||||
context.setVerbatim(sm.getVerbatim(sDisplayName));
|
||||
context.setNoLineBreaks(sm.getVerbatim(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.addToExport(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 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+"}{"+Calc.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ColorConverter.java
|
||||
*
|
||||
* Copyright: 2002-2008 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ContentHandlingOption.java
|
||||
*
|
||||
* Copyright: 2002-2008 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ConverterHelper.java
|
||||
*
|
||||
* Copyright: 2002-2016 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-20)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import writer2latex.office.OfficeReader;
|
||||
|
||||
/**
|
||||
* <p>This is an abstract superclass for converter helpers.</p>
|
||||
*/
|
||||
abstract class ConverterHelper {
|
||||
|
||||
OfficeReader ofr;
|
||||
LaTeXConfig config;
|
||||
ConverterPalette palette;
|
||||
|
||||
ConverterHelper(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
this.ofr = ofr;
|
||||
this.config = config;
|
||||
this.palette = palette;
|
||||
}
|
||||
|
||||
abstract void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl);
|
||||
|
||||
}
|
|
@ -1,298 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ConverterPalette.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-14)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import writer2latex.api.Config;
|
||||
import writer2latex.api.ConverterFactory;
|
||||
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.util.CSVList;
|
||||
import writer2latex.util.ExportNameCollection;
|
||||
import writer2latex.util.Misc;
|
||||
import writer2latex.office.MIMETypes;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
|
||||
/** This class converts a Writer XML file to a LaTeX file
|
||||
*/
|
||||
public final class ConverterPalette extends ConverterBase {
|
||||
|
||||
// Configuration
|
||||
private LaTeXConfig config;
|
||||
|
||||
public Config getConfig() { return config; }
|
||||
|
||||
// The main outfile
|
||||
private LaTeXDocument texDoc;
|
||||
|
||||
// Various data used in conversion
|
||||
private Context mainContext; // main context
|
||||
private CSVList globalOptions; // global options
|
||||
|
||||
// The helpers (the "colors" of the palette)
|
||||
private I18n i18n;
|
||||
private ColorConverter colorCv;
|
||||
private CharStyleConverter charSc;
|
||||
private PageStyleConverter pageSc;
|
||||
private BlockConverter blockCv;
|
||||
private ParConverter parCv;
|
||||
private HeadingConverter headingCv;
|
||||
private IndexConverter indexCv;
|
||||
private BibConverter bibCv;
|
||||
private SectionConverter sectionCv;
|
||||
private TableConverter tableCv;
|
||||
private ListConverter listCv;
|
||||
private NoteConverter noteCv;
|
||||
private CaptionConverter captionCv;
|
||||
private InlineConverter inlineCv;
|
||||
private FieldConverter fieldCv;
|
||||
private DrawConverter drawCv;
|
||||
private MathConverter mathCv;
|
||||
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 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 ListConverter getListCv() { return listCv; }
|
||||
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 MathConverter getMathCv() { return mathCv; }
|
||||
public Info getInfo() { return info; }
|
||||
|
||||
|
||||
// fill out inner converter method
|
||||
public void convertInner() throws IOException {
|
||||
sTargetFileName = Misc.trimDocumentName(sTargetFileName,".tex");
|
||||
String sSafeTargetFileName = new ExportNameCollection(true).addToExport(sTargetFileName);
|
||||
imageConverter.setBaseFileName(sSafeTargetFileName+"-img");
|
||||
if (config.saveImagesInSubdir()) {
|
||||
imageConverter.setUseSubdir(sSafeTargetFileName+"-img");
|
||||
}
|
||||
|
||||
// Set graphics formats depending on backend
|
||||
if (config.getBackend()==LaTeXConfig.PDFTEX || config.getBackend()==LaTeXConfig.XETEX) {
|
||||
imageConverter.setDefaultFormat(MIMETypes.PNG);
|
||||
imageConverter.setDefaultVectorFormat(MIMETypes.PDF);
|
||||
imageConverter.addAcceptedFormat(MIMETypes.JPEG);
|
||||
}
|
||||
else if (config.getBackend()==LaTeXConfig.DVIPS) {
|
||||
imageConverter.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);
|
||||
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);
|
||||
listCv = new ListConverter(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);
|
||||
mathCv = new MathConverter(ofr,config,this);
|
||||
info = new Info(ofr,config,this);
|
||||
|
||||
// Create master document and add this
|
||||
this.texDoc = new LaTeXDocument(sTargetFileName,config.getWrapLinesAfter(),true);
|
||||
if (config.getBackend()!=LaTeXConfig.XETEX) {
|
||||
texDoc.setEncoding(ClassicI18n.writeJavaEncoding(config.getInputencoding()));
|
||||
}
|
||||
else {
|
||||
texDoc.setEncoding("UTF-8");
|
||||
|
||||
}
|
||||
converterResult.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);
|
||||
noteCv.appendDeclarations(packages,declarations);
|
||||
charSc.appendDeclarations(packages,declarations);
|
||||
headingCv.appendDeclarations(packages,declarations);
|
||||
parCv.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);
|
||||
listCv.appendDeclarations(packages,declarations);
|
||||
captionCv.appendDeclarations(packages,declarations);
|
||||
inlineCv.appendDeclarations(packages,declarations);
|
||||
fieldCv.appendDeclarations(packages,declarations);
|
||||
drawCv.appendDeclarations(packages,declarations);
|
||||
mathCv.appendDeclarations(packages,declarations);
|
||||
|
||||
// Add custom preamble
|
||||
String sCustomPreamble = config.getCustomPreamble();
|
||||
if (sCustomPreamble.length()>0) {
|
||||
declarations.append(sCustomPreamble).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!=null) {
|
||||
createMeta("date",Misc.dateOnly(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://writer2latex.sourceforge.net 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) {
|
||||
converterResult.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();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,454 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* DrawConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-05)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.base.BinaryGraphicsDocument;
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
import writer2latex.latex.util.Context;
|
||||
import writer2latex.office.EmbeddedObject;
|
||||
import writer2latex.office.EmbeddedXMLObject;
|
||||
import writer2latex.office.MIMETypes;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.CSVList;
|
||||
import writer2latex.util.Calc;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/**
|
||||
* <p>This class handles draw elements.</p>
|
||||
*/
|
||||
public class DrawConverter extends ConverterHelper {
|
||||
|
||||
private boolean bNeedGraphicx = false;
|
||||
|
||||
// Keep track of floating frames (images, text boxes...)
|
||||
private Stack<LinkedList<Element>> floatingFramesStack = new Stack<LinkedList<Element>>();
|
||||
|
||||
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<Element>());
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Process the first child of a draw:frame
|
||||
public void handleDrawElement(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// node must be an element 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)) {
|
||||
if (!palette.getMathCv().handleTexMathsEquation(node,ldp)) {
|
||||
// OpenDocument: Get the actual draw element in the frame
|
||||
handleDrawElement(Misc.getFirstChildElement(node),ldp,oc);
|
||||
}
|
||||
}
|
||||
else if (sName.equals(XMLString.DRAW_G)) {
|
||||
if (!palette.getMathCv().handleTexMathsEquation(node,ldp)) {
|
||||
// Shapes are currently not supported
|
||||
ldp.append("[Warning: Draw object ignored]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Other drawing objects 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 formuladoc = ((EmbeddedXMLObject) object).getContentDOM();
|
||||
Element formula = Misc.getChildByTagName(formuladoc,XMLString.MATH); // Since OOo3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
|
||||
}
|
||||
String sLaTeX = palette.getMathCv().convert(formula);
|
||||
if (!" ".equals(sLaTeX)) { // ignore empty formulas
|
||||
ldp.append(" $")
|
||||
.append(sLaTeX)
|
||||
.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); // Since OOo 3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(node,XMLString.MATH_MATH);
|
||||
}
|
||||
if (formula!=null) {
|
||||
ldp.append(" $")
|
||||
.append(palette.getMathCv().convert(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
|
||||
if (config.floatFigures()) {
|
||||
// Inside floats we don't want the extra glue added by the center environment
|
||||
ba.add("\\centering\n","\n");
|
||||
}
|
||||
else {
|
||||
// Outside a float we certainly want it
|
||||
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(sName,"|graphic",ldp);
|
||||
String sAnchor = frame.getAttribute(XMLString.TEXT_ANCHOR_TYPE);
|
||||
|
||||
//if (oc.isInFrame() || "as-char".equals(sAnchor)) {
|
||||
if ("as-char".equals(sAnchor)) {
|
||||
handleDrawImageAsChar(node,ldp,oc);
|
||||
}
|
||||
else {
|
||||
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;
|
||||
|
||||
BinaryGraphicsDocument bgd = palette.getImageCv().getImage(node);
|
||||
if (bgd!=null) {
|
||||
if (!bgd.isLinked()) { // embedded image
|
||||
if (!bgd.isRecycled()) { palette.addDocument(bgd); }
|
||||
sFileName = bgd.getFileName();
|
||||
String sMIME = bgd.getMIMEType();
|
||||
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)));
|
||||
}
|
||||
else { // linked image
|
||||
sFileName = bgd.getFileName();
|
||||
String sExt = Misc.getFileExtension(sFileName).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 {
|
||||
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 = Calc.truncateLength(frame.getAttribute(XMLString.SVG_WIDTH));
|
||||
String sHeight = Calc.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(sName,"|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 {
|
||||
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 = Calc.truncateLength(getFrame(node).getAttribute(XMLString.SVG_WIDTH));
|
||||
if (!bIsCaption) {
|
||||
ldp.append("\\begin{minipage}{").append(sWidth).append("}").nl();
|
||||
}
|
||||
floatingFramesStack.push(new LinkedList<Element>());
|
||||
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<Element> floatingFrames = 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,986 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* FieldConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-23)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
//import java.io.UnsupportedEncodingException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import writer2latex.latex.util.Context;
|
||||
import writer2latex.latex.util.HeadingMap;
|
||||
import writer2latex.office.ListStyle;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.XMLString;
|
||||
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 (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 {
|
||||
|
||||
// Identify Zotero items
|
||||
private static final String ZOTERO_ITEM = "ZOTERO_ITEM";
|
||||
// Identify JabRef items
|
||||
private static final String JABREF_ITEM = "JR_cite";
|
||||
|
||||
// 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<String, Node> seqDecl = new Hashtable<String, Node>();
|
||||
// first usage of sequence (maps name->text:sequence element)
|
||||
private Hashtable<String, Element> seqFirst = new Hashtable<String, Element>();
|
||||
|
||||
private Vector<Element> postponedReferenceMarks = new Vector<Element>();
|
||||
private Vector<Element> postponedBookmarks = new Vector<Element>();
|
||||
|
||||
private boolean bUseHyperref = false;
|
||||
private boolean bUsesPageCount = false;
|
||||
private boolean bUsesTitleref = false;
|
||||
private boolean bConvertZotero = false;
|
||||
private boolean bConvertJabRef = false;
|
||||
private boolean bIncludeOriginalCitations = false;
|
||||
private boolean bUseNatbib = false;
|
||||
|
||||
public FieldConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
// hyperref.sty is not compatible with titleref.sty:
|
||||
bUseHyperref = config.useHyperref() && !config.useTitleref();
|
||||
bConvertZotero = config.useBibtex() && config.zoteroBibtexFiles().length()>0;
|
||||
bConvertJabRef = config.useBibtex() && config.jabrefBibtexFiles().length()>0;
|
||||
bIncludeOriginalCitations = config.includeOriginalCitations();
|
||||
bUseNatbib = config.useBibtex() && config.useNatbib();
|
||||
}
|
||||
|
||||
/** <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 natbib
|
||||
if (config.useBibtex() && config.useNatbib()) {
|
||||
pack.append("\\usepackage");
|
||||
if (config.getNatbibOptions().length()>0) {
|
||||
pack.append("[").append(config.getNatbibOptions()).append("]");
|
||||
}
|
||||
pack.append("{natbib}").nl();
|
||||
}
|
||||
// use lastpage.sty
|
||||
if (bUsesPageCount) {
|
||||
pack.append("\\usepackage{lastpage}").nl();
|
||||
}
|
||||
|
||||
// use titleref.sty
|
||||
if (bUsesTitleref) {
|
||||
pack.append("\\usepackage{titleref}").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<String> names = seqFirst.keys();
|
||||
while (names.hasMoreElements()) {
|
||||
// Get first text:sequence element
|
||||
String sName = names.nextElement();
|
||||
Element first = 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.addToExport(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.addToExport(sName))
|
||||
.append("{").append(sPrefix)
|
||||
.append(ListConverter.numFormat(sNumFormat))
|
||||
.append("{").append(seqnames.addToExport(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.addToExport(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.addToExport(sName))
|
||||
.append("\\label{seq:")
|
||||
.append(seqrefnames.addToExport(sRefName))
|
||||
.append("}}");
|
||||
}
|
||||
else {
|
||||
// Export as \stepcounter{name}{\thename}
|
||||
ldp.append(changeCounter(sName,sFormula,false))
|
||||
.append("{\\the")
|
||||
.append(seqnames.addToExport(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.addToExport(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.addToExport(sName) + "}";
|
||||
}
|
||||
else {
|
||||
return "\\stepcounter{" + seqnames.addToExport(sName) + "}";
|
||||
}
|
||||
}
|
||||
|
||||
private String addtoCounter(String sName, int nValue, boolean bRef) {
|
||||
if (nValue==1) {
|
||||
return stepCounter(sName, bRef);
|
||||
}
|
||||
else if (bRef) {
|
||||
return "\\addtocounter{" + seqnames.addToExport(sName) + "}"
|
||||
+ "{" + Integer.toString(nValue-1) + "}"
|
||||
+ "\\refstepcounter{" + seqnames.addToExport(sName) + "}";
|
||||
}
|
||||
else if (nValue!=0) {
|
||||
return "\\addtocounter{" + seqnames.addToExport(sName) + "}"
|
||||
+ "{" + Integer.toString(nValue) + "}";
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String setCounter(String sName, int nValue, boolean bRef) {
|
||||
if (bRef) {
|
||||
return "\\setcounter{" + seqnames.addToExport(sName) + "}"
|
||||
+ "{" + Integer.toString(nValue-1) + "}"
|
||||
+ "\\refstepcounter{" + seqnames.addToExport(sName) + "}";
|
||||
}
|
||||
else {
|
||||
return "\\setcounter{" + seqnames.addToExport(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.addToExport(sRefName))
|
||||
.append("}");
|
||||
}
|
||||
else if ("value".equals(sFormat)) {
|
||||
ldp.append("\\ref{seq:")
|
||||
.append(seqrefnames.addToExport(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.addToExport(sRefName))
|
||||
.append("}");
|
||||
}
|
||||
else if ("caption".equals(sFormat) && config.useTitleref() &&
|
||||
(ofr.isFigureSequenceName(sName) || ofr.isTableSequenceName(sName))) {
|
||||
ldp.append("\\titleref{seq:")
|
||||
.append(seqrefnames.addToExport(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.addToExport(sRefName))
|
||||
.append("}:~\\titleref{")
|
||||
.append(seqrefnames.addToExport(sRefName))
|
||||
.append("}");
|
||||
bUsesTitleref = true;
|
||||
}
|
||||
else { // use current value
|
||||
palette.getInlineCv().traversePCDATA(node,ldp,oc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to handle this reference name as a Zotero reference, return true on success
|
||||
private boolean handleZoteroReferenceName(String sName, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// First parse the reference name:
|
||||
// A Zotero reference name has the form ZOTERO_ITEM <json object> <identifier> with a single space separating the items
|
||||
// The identifier is a unique identifier for the reference and is not used here
|
||||
if (sName.startsWith(ZOTERO_ITEM)) {
|
||||
int nObjectStart = sName.indexOf('{');
|
||||
int nObjectEnd = sName.lastIndexOf('}');
|
||||
if (nObjectStart>-1 && nObjectEnd>-1 && nObjectStart<nObjectEnd) {
|
||||
String sJsonObject = sName.substring(nObjectStart, nObjectEnd+1);
|
||||
JSONObject jo = null;
|
||||
try {
|
||||
jo = new JSONObject(sJsonObject);
|
||||
} catch (JSONException e) {
|
||||
return false;
|
||||
}
|
||||
// Successfully parsed the reference, now generate the code
|
||||
// (we don't expect any errors and ignore them, if they happen anyway)
|
||||
|
||||
// Sort key (purpose? currently ignored)
|
||||
/*boolean bSort = true;
|
||||
try {
|
||||
bSort = jo.getBoolean("sort");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}*/
|
||||
|
||||
JSONArray citationItemsArray = null;
|
||||
try { // The value is an array of objects, one for each source in this citation
|
||||
citationItemsArray = jo.getJSONArray("citationItems");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
if (citationItemsArray!=null) {
|
||||
int nCitationCount = citationItemsArray.length();
|
||||
|
||||
if (bUseNatbib) {
|
||||
if (nCitationCount>1) {
|
||||
// For multiple citations, use \citetext, otherwise we cannot add individual prefixes and suffixes
|
||||
// TODO: If no prefixes or suffixes exist, it's safe to combine the citations
|
||||
ldp.append("\\citetext{");
|
||||
}
|
||||
|
||||
for (int nIndex=0; nIndex<nCitationCount; nIndex++) {
|
||||
|
||||
JSONObject citationItems = null;
|
||||
try { // Each citation is represented as an object
|
||||
citationItems = citationItemsArray.getJSONObject(nIndex);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
if (citationItems!=null) {
|
||||
if (nIndex>0) {
|
||||
ldp.append("; "); // Separate multiple citations in this reference
|
||||
}
|
||||
|
||||
// Citation items
|
||||
String sURI = "";
|
||||
boolean bSuppressAuthor = false;
|
||||
String sPrefix = "";
|
||||
String sSuffix = "";
|
||||
String sLocator = "";
|
||||
String sLocatorType = "";
|
||||
|
||||
try { // The URI seems to be an array with a single string value(?)
|
||||
sURI = citationItems.getJSONArray("uri").getString(0);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
try { // SuppressAuthor is a boolean value
|
||||
bSuppressAuthor = citationItems.getBoolean("suppressAuthor");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
try { // Prefix is a string value
|
||||
sPrefix = citationItems.getString("prefix");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
try { // Suffix is a string value
|
||||
sSuffix = citationItems.getString("suffix");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
try { // Locator is a string value, e.g. a page number
|
||||
sLocator = citationItems.getString("locator");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// LocatorType is a string value, e.g. book, verse, page (missing locatorType means page)
|
||||
sLocatorType = citationItems.getString("locatorType");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
// Adjust locator type (empty locator type means "page")
|
||||
// TODO: Handle other locator types (localize and abbreviate): Currently the internal name (e.g. book) is used.
|
||||
if (sLocator.length()>0 && sLocatorType.length()==0) {
|
||||
// A locator of the form <number><other characters><number> is interpreted as several pages
|
||||
if (Pattern.compile("[0-9]+[^0-9]+[0-9]+").matcher(sLocator).find()) {
|
||||
sLocatorType = "pp.";
|
||||
}
|
||||
else {
|
||||
sLocatorType = "p.";
|
||||
}
|
||||
}
|
||||
|
||||
// Insert command. TODO: Evaluate this
|
||||
if (nCitationCount>1) { // Use commands without parentheses
|
||||
if (bSuppressAuthor) { ldp.append("\\citeyear"); }
|
||||
else { ldp.append("\\citet"); }
|
||||
}
|
||||
else {
|
||||
if (bSuppressAuthor) { ldp.append("\\citeyearpar"); }
|
||||
else { ldp.append("\\citep"); }
|
||||
}
|
||||
|
||||
if (sPrefix.length()>0) {
|
||||
ldp.append("[").append(palette.getI18n().convert(sPrefix,true,oc.getLang())).append("]");
|
||||
}
|
||||
|
||||
if (sPrefix.length()>0 || sSuffix.length()>0 || sLocatorType.length()>0 || sLocator.length()>0) {
|
||||
// Note that we need to include an empty suffix if there's a prefix!
|
||||
ldp.append("[")
|
||||
.append(palette.getI18n().convert(sSuffix,true,oc.getLang()))
|
||||
.append(palette.getI18n().convert(sLocatorType,true,oc.getLang()));
|
||||
if (sLocatorType.length()>0 && sLocator.length()>0) {
|
||||
ldp.append("~");
|
||||
}
|
||||
ldp.append(palette.getI18n().convert(sLocator,true,oc.getLang()))
|
||||
.append("]");
|
||||
}
|
||||
|
||||
ldp.append("{");
|
||||
int nSlash = sURI.lastIndexOf('/');
|
||||
if (nSlash>0) {
|
||||
ldp.append(sURI.substring(nSlash+1));
|
||||
}
|
||||
else {
|
||||
ldp.append(sURI);
|
||||
}
|
||||
ldp.append("}");
|
||||
}
|
||||
}
|
||||
|
||||
if (nCitationCount>1) { // End the \citetext command
|
||||
ldp.append("}");
|
||||
}
|
||||
}
|
||||
else { // natbib is not available, use simple \cite command
|
||||
ldp.append("\\cite{");
|
||||
for (int nIndex=0; nIndex<nCitationCount; nIndex++) {
|
||||
JSONObject citationItems = null;
|
||||
try { // Each citation is represented as an object
|
||||
citationItems = citationItemsArray.getJSONObject(nIndex);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
if (citationItems!=null) {
|
||||
if (nIndex>0) {
|
||||
ldp.append(","); // Separate multiple citations in this reference
|
||||
}
|
||||
|
||||
// Citation items
|
||||
String sURI = "";
|
||||
|
||||
try { // The URI seems to be an array with a single string value(?)
|
||||
sURI = citationItems.getJSONArray("uri").getString(0);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
|
||||
int nSlash = sURI.lastIndexOf('/');
|
||||
if (nSlash>0) {
|
||||
ldp.append(sURI.substring(nSlash+1));
|
||||
}
|
||||
else {
|
||||
ldp.append(sURI);
|
||||
}
|
||||
}
|
||||
}
|
||||
ldp.append("}");
|
||||
}
|
||||
|
||||
oc.setInZoteroJabRefText(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to handle this reference name as a JabRef reference, return true on success
|
||||
private boolean handleJabRefReferenceName(String sName, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// First parse the reference name:
|
||||
// A JabRef reference name has the form JR_cite<m>_<n>_<identifiers> where
|
||||
// m is a sequence number to ensure unique citations (may be empty)
|
||||
// n=1 for (Author date) and n=2 for Author (date) citations
|
||||
// identifiers is a comma separated list of BibTeX keys
|
||||
if (sName.startsWith(JABREF_ITEM)) {
|
||||
String sRemains = sName.substring(JABREF_ITEM.length());
|
||||
int nUnderscore = sRemains.indexOf('_');
|
||||
if (nUnderscore>-1) {
|
||||
sRemains = sRemains.substring(nUnderscore+1);
|
||||
if (sRemains.length()>2) {
|
||||
String sCommand;
|
||||
if (bUseNatbib) {
|
||||
if (sRemains.charAt(0)=='1') {
|
||||
sCommand = "\\citep";
|
||||
}
|
||||
else {
|
||||
sCommand = "\\citet";
|
||||
}
|
||||
}
|
||||
else {
|
||||
sCommand = "\\cite";
|
||||
}
|
||||
ldp.append(sCommand).append("{").append(sRemains.substring(2)).append("}");
|
||||
}
|
||||
}
|
||||
oc.setInZoteroJabRefText(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String shortenRefname(String s) {
|
||||
// For Zotero items, use the trailing unique identifier
|
||||
if (s.startsWith(ZOTERO_ITEM)) {
|
||||
int nLast = s.lastIndexOf(' ');
|
||||
if (nLast>0) {
|
||||
return s.substring(nLast+1);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** <p>Process a reference mark end (text:reference-mark-end 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 handleReferenceMarkEnd(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// Nothing to do, except to mark that this ends any Zotero/JabRef citation
|
||||
oc.setInZoteroJabRefText(false);
|
||||
if (bIncludeOriginalCitations) { // Protect space after comment
|
||||
ldp.append("{}");
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>Process a reference mark (text:reference-mark or text:reference-mark-start 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()) {
|
||||
String sName = node.getAttribute(XMLString.TEXT_NAME);
|
||||
// Zotero and JabRef (mis)uses reference marks to store citations, so check this first
|
||||
if (sName!=null && (!bConvertZotero || !handleZoteroReferenceName(sName, ldp, oc))
|
||||
&& (!bConvertJabRef || !handleJabRefReferenceName(sName, ldp, oc))) {
|
||||
// Plain reference mark
|
||||
// Note: Always include \label here, even when it's not used
|
||||
ldp.append("\\label{ref:"+refnames.addToExport(shortenRefname(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.addToExport(shortenRefname(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.addToExport(shortenRefname(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.addToExport(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.addToExport(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.addToExport(sName)+"}");
|
||||
}
|
||||
else if (("number".equals(sFormat) || "number-no-superior".equals(sFormat) || "number-all-superior".equals(sFormat)) &&
|
||||
(ofr.bookmarkInHeading(sName) || ofr.bookmarkInList(sName))) {
|
||||
ListStyle style=null;
|
||||
int nLevel = 0;
|
||||
String sPrefix=null;
|
||||
String sSuffix=null;
|
||||
// Only convert the prefix and suffix if it is converted at the reference target
|
||||
if (ofr.bookmarkInHeading(sName)) {
|
||||
if (config.formatting()>=LaTeXConfig.CONVERT_MOST) {
|
||||
style = ofr.getOutlineStyle();
|
||||
}
|
||||
nLevel = ofr.getBookmarkHeadingLevel(sName);
|
||||
}
|
||||
else {
|
||||
if (config.formatting()>=LaTeXConfig.CONVERT_BASIC) {
|
||||
style = ofr.getListStyle(ofr.getBookmarkListStyle(sName));
|
||||
}
|
||||
nLevel = ofr.getBookmarkListLevel(sName);
|
||||
}
|
||||
if (style!=null) {
|
||||
sPrefix = style.getLevelProperty(nLevel, XMLString.STYLE_NUM_PREFIX);
|
||||
sSuffix = style.getLevelProperty(nLevel, XMLString.STYLE_NUM_SUFFIX);
|
||||
}
|
||||
if (sPrefix!=null) ldp.append(palette.getI18n().convert(sPrefix,false,oc.getLang()));
|
||||
ldp.append("\\ref{bkm:").append(bookmarknames.addToExport(sName)).append("}");
|
||||
if (sSuffix!=null) ldp.append(palette.getI18n().convert(sSuffix,false,oc.getLang()));
|
||||
}
|
||||
else { // use current value
|
||||
palette.getInlineCv().traversePCDATA(node,ldp,oc);
|
||||
}
|
||||
}
|
||||
|
||||
/** Do we have any pending reference marks or bookmarks, that may be inserted in this context?
|
||||
*
|
||||
* @param oc the context to verify against
|
||||
* @return true if there are pending marks
|
||||
*/
|
||||
public boolean hasPendingReferenceMarks(Context oc) {
|
||||
return !oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim() &&
|
||||
postponedReferenceMarks.size()+postponedBookmarks.size()>0;
|
||||
}
|
||||
|
||||
/** <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(postponedReferenceMarks.get(i),ldp,oc);
|
||||
}
|
||||
postponedReferenceMarks.clear();
|
||||
// Type out all postponed bookmarks
|
||||
n = postponedBookmarks.size();
|
||||
for (int i=0; i<n; i++) {
|
||||
handleBookmark(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.addToExport(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 (OfficeReader.getTextContent(node).trim().equals(sHref)) {
|
||||
// The link text equals the url
|
||||
ldp.append("\\url{")
|
||||
.append(escapeHref(sHref,oc.isInFootnote()))
|
||||
.append("}");
|
||||
}
|
||||
else {
|
||||
ldp.append("\\href{")
|
||||
.append(escapeHref(sHref,oc.isInFootnote()))
|
||||
.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.addToExport(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.addToExport(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 the argument to a href, we have to escape or encode certain characters
|
||||
private String escapeHref(String s, boolean bInFootnote) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i=0; i<s.length(); i++) {
|
||||
if (bInFootnote && s.charAt(i)=='#') { buf.append("\\#"); }
|
||||
else if (bInFootnote && s.charAt(i)=='%') { buf.append("\\%"); }
|
||||
// The following should not occur in an URL (see RFC1738), but just to be sure we encode them
|
||||
else if (s.charAt(i)=='\\') { buf.append("\\%5C"); }
|
||||
else if (s.charAt(i)=='{') { buf.append("\\%7B"); }
|
||||
else if (s.charAt(i)=='}') { buf.append("\\%7D"); }
|
||||
// hyperref.sty deals safely with other characters
|
||||
else { buf.append(s.charAt(i)); }
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,431 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* HeadingConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-14)
|
||||
*
|
||||
*/
|
||||
|
||||
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.office.ListStyle;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Calc;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/* 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];
|
||||
|
||||
// Display hidden text?
|
||||
private boolean bDisplayHiddenText = false;
|
||||
|
||||
/** Constructs a new <code>HeadingConverter</code>.
|
||||
*/
|
||||
public HeadingConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
this.bDisplayHiddenText = config.displayHiddenText();
|
||||
}
|
||||
|
||||
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 style
|
||||
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
|
||||
StyleWithProperties style = ofr.getParStyle(sStyleName);
|
||||
|
||||
// Check for hidden text
|
||||
if (!bDisplayHiddenText && style!=null && "none".equals(style.getProperty(XMLString.TEXT_DISPLAY))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the level
|
||||
int nLevel = ofr.isOpenDocument() ?
|
||||
Misc.getPosInteger(Misc.getAttribute(node, XMLString.TEXT_OUTLINE_LEVEL),1) :
|
||||
Misc.getPosInteger(Misc.getAttribute(node, XMLString.TEXT_LEVEL),1);
|
||||
boolean bUnNumbered = "true".equals(Misc.getAttribute(node,XMLString.TEXT_IS_LIST_HEADER));
|
||||
|
||||
// Get the heading map
|
||||
HeadingMap hm = config.getHeadingMap();
|
||||
|
||||
if (nLevel<=hm.getMaxLevel()) {
|
||||
// Always push the font used
|
||||
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(style));
|
||||
|
||||
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 (bUnNumbered) {
|
||||
ldp.append("*");
|
||||
}
|
||||
else if (baHardChar.getBefore().length()>0 || containsElements(node)) {
|
||||
// If this heading contains formatting, add optional argument:
|
||||
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);
|
||||
|
||||
// Get margin parameters (using first line indent as left margin)
|
||||
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 sTextIndent = style.getAbsoluteLength(XMLString.FO_TEXT_INDENT);
|
||||
|
||||
// Seems that we should *not* override the paragraph style
|
||||
/*ListStyle outline = ofr.getOutlineStyle();
|
||||
if (outline.isNewType(i)) {
|
||||
String sNumFormat = ListStyleConverter.numFormat(outline.getLevelProperty(i,XMLString.STYLE_NUM_FORMAT));
|
||||
if (sNumFormat!=null && !"".equals(sNumFormat)) {
|
||||
// It there's a numbering, override left margins with the value from the outline
|
||||
sMarginLeft = outline.getLevelStyleProperty(i, XMLString.FO_MARGIN_LEFT);
|
||||
if (sMarginLeft==null) { sMarginLeft = "0cm"; }
|
||||
sTextIndent = outline.getLevelStyleProperty(i, XMLString.FO_TEXT_INDENT);
|
||||
if (sTextIndent==null) { sTextIndent = "0cm"; }
|
||||
}
|
||||
}*/
|
||||
|
||||
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();
|
||||
}
|
||||
// Note: Use first line as left indent (cannot have separate first line indent)
|
||||
ldp.append("\\renewcommand\\").append(sSecName)
|
||||
.append("{\\@startsection{").append(sSecName).append("}{"+hm.getLevel(i))
|
||||
.append("}{"+Calc.add(sMarginLeft,sTextIndent)+"}{");
|
||||
// Suppress indentation after heading? currently not..
|
||||
// ldp.append("-");
|
||||
ldp.append(sMarginTop)
|
||||
.append("}{")
|
||||
.append(Calc.isZero(sMarginBottom) ? "0.1mm" : 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] = ListConverter.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 sSpaceChar="";
|
||||
String sDistance=null;
|
||||
if (outline.isNewType(i)) {
|
||||
String sFormat = outline.getLevelStyleProperty(i, XMLString.TEXT_LABEL_FOLLOWED_BY);
|
||||
if ("listtab".equals(sFormat)) {
|
||||
String sMarginLeft="0cm";
|
||||
String sTextIndent="0cm";
|
||||
if (sHeadingStyles[i]!=null) {
|
||||
StyleWithProperties style = ofr.getParStyle(sHeadingStyles[i]);
|
||||
if (style!=null) {
|
||||
sMarginLeft = style.getAbsoluteLength(XMLString.FO_MARGIN_LEFT);
|
||||
sTextIndent = style.getAbsoluteLength(XMLString.FO_TEXT_INDENT);
|
||||
}
|
||||
}
|
||||
// Seems that we should *not* override the paragraph style
|
||||
/*String sMarginLeft = outline.getLevelStyleProperty(i, XMLString.FO_MARGIN_LEFT);
|
||||
if (sMarginLeft==null) { sMarginLeft = "0cm"; }
|
||||
String sTextIndent = outline.getLevelStyleProperty(i, XMLString.FO_TEXT_INDENT);
|
||||
if (sTextIndent==null) { sTextIndent = "0cm"; }*/
|
||||
String sTabPos = outline.getLevelStyleProperty(i, XMLString.TEXT_LIST_TAB_STOP_POSITION);
|
||||
if (sTabPos==null) { sTabPos = "0cm"; }
|
||||
sDistance = Calc.sub(sTabPos, Calc.add(sMarginLeft, sTextIndent));
|
||||
}
|
||||
else if ("space".equals(sFormat)) {
|
||||
sSpaceChar="\\ ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
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 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"; }
|
||||
}
|
||||
String sLabelWidth = null;
|
||||
if (outline.isNewType(i)) {
|
||||
String sFormat = outline.getLevelStyleProperty(i, XMLString.TEXT_LABEL_FOLLOWED_BY);
|
||||
if ("listtab".equals(sFormat) || sAlignmentChar=="r") {
|
||||
sLabelWidth="0cm";
|
||||
}
|
||||
}
|
||||
else {
|
||||
sLabelWidth = outline.getLevelStyleProperty(i,XMLString.TEXT_MIN_LABEL_WIDTH);
|
||||
}
|
||||
// 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("\\protect\\makebox[").append(sLabelWidth).append("][").append(sAlignmentChar).append("]{");
|
||||
}
|
||||
ldp.append(baText.getBefore())
|
||||
.append(sPrefix!=null ? palette.getI18n().convert(sPrefix,false,"en") : "")
|
||||
.append("#1")
|
||||
.append(sSuffix!=null ? palette.getI18n().convert(sSuffix,false,"en") : "")
|
||||
.append(sSpaceChar)
|
||||
.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) ||
|
||||
child.getNodeName().startsWith(XMLString.TEXT_BOOKMARK))) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* IndexConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-18)
|
||||
*
|
||||
*/
|
||||
|
||||
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<Element> postponedIndexMarks = new Vector<Element>();
|
||||
|
||||
/** <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);
|
||||
}
|
||||
}
|
||||
|
||||
/** Do we have any pending index marks, that may be inserted in this context?
|
||||
*
|
||||
* @param oc the context to verify against
|
||||
* @return true if there are pending index marks
|
||||
*/
|
||||
public boolean hasPendingIndexMarks(Context oc) {
|
||||
return !oc.isInSection() && !oc.isInCaption() && !oc.isVerbatim() &&
|
||||
postponedIndexMarks.size()>0;
|
||||
}
|
||||
|
||||
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(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* Info.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-21)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.util.Misc;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
|
||||
|
||||
/** This class creates various information to the user about the conversion.
|
||||
*/
|
||||
class Info extends ConverterHelper {
|
||||
|
||||
@Override public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
// Currently nothing
|
||||
}
|
||||
|
||||
Info(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
}
|
||||
|
||||
void addDebugInfo(Element node, LaTeXDocumentPortion ldp) {
|
||||
if (config.debug()) {
|
||||
ldp.append("% ").append(node.getNodeName());
|
||||
addDebugInfo(node,ldp,XMLString.TEXT_ID);
|
||||
addDebugInfo(node,ldp,XMLString.TEXT_NAME);
|
||||
addDebugInfo(node,ldp,XMLString.TABLE_NAME);
|
||||
addDebugInfo(node,ldp,XMLString.TEXT_STYLE_NAME);
|
||||
if (node.getNodeName().equals(XMLString.TEXT_P) || node.getNodeName().equals(XMLString.TEXT_H)) {
|
||||
StyleWithProperties style = ofr.getParStyle(node.getAttribute(XMLString.TEXT_STYLE_NAME));
|
||||
if (style!=null && style.isAutomatic()) {
|
||||
ldp.append(" ("+style.getParentName()+")");
|
||||
}
|
||||
ldp.append(" ("+ofr.getParStyles().getDisplayName(node.getAttribute(XMLString.TEXT_STYLE_NAME))+")");
|
||||
}
|
||||
ldp.nl();
|
||||
}
|
||||
}
|
||||
|
||||
void addDebugInfo(Element node, LaTeXDocumentPortion ldp, String sAttribute) {
|
||||
String sValue = Misc.getAttribute(node,sAttribute);
|
||||
if (sValue!=null) {
|
||||
ldp.append(" ").append(sAttribute).append("=\"").append(sValue).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,740 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* InlineConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-19)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
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 {
|
||||
|
||||
// Display hidden text?
|
||||
private boolean bDisplayHiddenText = false;
|
||||
|
||||
private boolean bIncludeOriginalCitations = false;
|
||||
private String sTabstop = "\\ \\ ";
|
||||
private boolean bHasPdfannotation = false;
|
||||
|
||||
public InlineConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
bIncludeOriginalCitations = config.includeOriginalCitations();
|
||||
// Get custom code for tab stops
|
||||
if (config.getTabstop().length()>0) {
|
||||
sTabstop = config.getTabstop();
|
||||
}
|
||||
this.bDisplayHiddenText = config.displayHiddenText();
|
||||
}
|
||||
|
||||
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 several text:span elements
|
||||
*
|
||||
*/
|
||||
private void handleTextSpans(Element[] nodes, LaTeXDocumentPortion ldp, Context oc) {
|
||||
if (oc.isMathMode()) {
|
||||
for (Element node : nodes) {
|
||||
handleTextSpanMath(node, ldp, oc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
handleTextSpanText(ldp, oc, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle a text:span element
|
||||
*/
|
||||
public void handleTextSpan(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
if (oc.isMathMode()) { handleTextSpanMath(node, ldp, oc); }
|
||||
else { handleTextSpanText(ldp, oc, node); }
|
||||
}
|
||||
|
||||
private void handleTextSpanMath(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// TODO: Handle a selection of formatting attributes: color, superscript...
|
||||
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
|
||||
StyleWithProperties style = ofr.getTextStyle(sStyleName);
|
||||
|
||||
// Check for hidden text
|
||||
if (!bDisplayHiddenText && style!=null && "none".equals(style.getProperty(XMLString.TEXT_DISPLAY))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Handle several spans.
|
||||
// If the converted formatting happens to be identical (e.g. \textbf{...}), the spans will be merged.
|
||||
private void handleTextSpanText(LaTeXDocumentPortion ldp, Context oc, Element... nodes) {
|
||||
// The current formatting
|
||||
BeforeAfter baCurrent = new BeforeAfter();
|
||||
for (Element node : nodes) {
|
||||
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
|
||||
StyleWithProperties style = ofr.getTextStyle(sStyleName);
|
||||
|
||||
// First check for hidden text
|
||||
if (bDisplayHiddenText || style==null || !"none".equals(style.getProperty(XMLString.TEXT_DISPLAY))) {
|
||||
// Then check for strict handling of styles
|
||||
String sDisplayName = ofr.getTextStyles().getDisplayName(sStyleName);
|
||||
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();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We do want to convert this span :-)
|
||||
|
||||
// Always push the font used
|
||||
palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getTextStyle(sStyleName)));
|
||||
|
||||
// Apply the style
|
||||
BeforeAfter ba = new BeforeAfter();
|
||||
Context ic = (Context) oc.clone();
|
||||
// Don't style it if
|
||||
// - we're already within a verbatim environment
|
||||
// - a {foot|end}note is the only content
|
||||
// - there is no content
|
||||
// - this is an automatic style in header/footer (name clash problem, only in package format)
|
||||
if (!oc.isVerbatim() && !onlyNote(node) && OfficeReader.getCharacterCount(node)>0
|
||||
&& !(ofr.isPackageFormat() && (style!=null && style.isAutomatic()) && oc.isInHeaderFooter())) {
|
||||
palette.getCharSc().applyTextStyle(sStyleName,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 area for footnotes
|
||||
if ((ba.getBefore().length()>0 || ba.getAfter().length()>0) && !ic.isInFootnote()) {
|
||||
ic.setNoFootnotes(true);
|
||||
}
|
||||
|
||||
// Merge spans? If the formatting of this span differs from the previous span, we will close the
|
||||
// previous span and start a new one
|
||||
if (!ba.getBefore().equals(baCurrent.getBefore()) || !ba.getAfter().equals(baCurrent.getAfter())) {
|
||||
ldp.append(baCurrent.getAfter());
|
||||
ldp.append(ba.getBefore());
|
||||
baCurrent = ba;
|
||||
}
|
||||
|
||||
traverseInlineText(node,ldp,ic);
|
||||
|
||||
// In the special case of pending footnotes, index marks and reference marks, we will close the span now.
|
||||
// Otherwise we will wait and see
|
||||
if (palette.getNoteCv().hasPendingFootnotes(oc)
|
||||
|| palette.getIndexCv().hasPendingIndexMarks(oc)
|
||||
|| palette.getFieldCv().hasPendingReferenceMarks(oc)) {
|
||||
ldp.append(baCurrent.getAfter());
|
||||
baCurrent = new BeforeAfter();
|
||||
}
|
||||
|
||||
// Flush any pending footnotes, index marks and reference marks
|
||||
if (!ic.isInFootnote()) { palette.getNoteCv().flushFootnotes(ldp,oc); }
|
||||
palette.getFieldCv().flushReferenceMarks(ldp,oc);
|
||||
palette.getIndexCv().flushIndexMarks(ldp,oc);
|
||||
|
||||
// finally pop the special table
|
||||
palette.getI18n().popSpecialTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
ldp.append(baCurrent.getAfter());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (oc.isInZoteroJabRefText()) {
|
||||
if (bIncludeOriginalCitations) { // Include original citation as a comment
|
||||
ldp.append("%")
|
||||
.append(palette.getI18n().convert(s, false, oc.getLang()))
|
||||
.nl();
|
||||
}
|
||||
}
|
||||
else { // Normal text
|
||||
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 {
|
||||
// Collect further spans
|
||||
Vector<Element> spans = new Vector<Element>();
|
||||
|
||||
Node remember;
|
||||
boolean bContinue = false;
|
||||
do {
|
||||
spans.add((Element)childNode);
|
||||
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)))
|
||||
bContinue = true;
|
||||
}
|
||||
} while(bContinue);
|
||||
childNode = remember;
|
||||
|
||||
handleTextSpans(spans.toArray(new Element[spans.size()]),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_MARK_END)) {
|
||||
palette.getFieldCv().handleReferenceMarkEnd(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
|
||||
Element creator = null;
|
||||
Element date = null;
|
||||
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();
|
||||
}
|
||||
else if (Misc.isElement(child, XMLString.DC_CREATOR)) {
|
||||
creator = (Element) child;
|
||||
}
|
||||
else if (Misc.isElement(child, XMLString.DC_DATE)) {
|
||||
date = (Element) child;
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
if (creator!=null) {
|
||||
ldp.append("%");
|
||||
traversePlainInlineText(creator, ldp, oc);
|
||||
ldp.nl();
|
||||
}
|
||||
if (date!=null) {
|
||||
ldp.append("%")
|
||||
.append(Misc.formatDate(OfficeReader.getTextContent(date), palette.getI18n().getDefaultLanguage(), null))
|
||||
.nl();
|
||||
}
|
||||
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("{");
|
||||
Element creator = null;
|
||||
Element date = null;
|
||||
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;
|
||||
}
|
||||
else if (Misc.isElement(child, XMLString.DC_CREATOR)) {
|
||||
creator = (Element) child;
|
||||
}
|
||||
else if (Misc.isElement(child, XMLString.DC_DATE)) {
|
||||
date = (Element) child;
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
if (creator!=null) {
|
||||
if (!bFirst) ldp.append(" - ");
|
||||
traversePlainInlineText(creator, ldp, oc);
|
||||
}
|
||||
if (date!=null) {
|
||||
if (creator!=null) ldp.append(", ");
|
||||
else if (!bFirst) ldp.append(" ");
|
||||
ldp.append(Misc.formatDate(OfficeReader.getTextContent(date), palette.getI18n().getDefaultLanguage(), null));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,750 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LaTeXConfig.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-07-23)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.api.ComplexOption;
|
||||
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.latex.util.StyleMapItem;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
public class LaTeXConfig extends writer2latex.base.ConfigBase {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// I. Define items needed by ConfigBase
|
||||
|
||||
protected int getOptionCount() { return 73; }
|
||||
protected String getDefaultConfigPath() { return "/writer2latex/latex/config/"; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// II. Override getter and setter methods for simple options in order to:
|
||||
// - Treat the custom preamble like a regular option, even though the xml representation is different
|
||||
// - Be backwards compatible (renamed the option keep_image_size)
|
||||
|
||||
@Override public void setOption(String sName,String sValue) {
|
||||
if (sName.equals("custom-preamble")) {
|
||||
sCustomPreamble = sValue;
|
||||
}
|
||||
else {
|
||||
// this option has been renamed:
|
||||
if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
|
||||
super.setOption(sName, sValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String getOption(String sName) {
|
||||
if (sName.equals("custom-preamble")) {
|
||||
return sCustomPreamble;
|
||||
}
|
||||
else {
|
||||
return super.getOption(sName);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// III. Declare all constants
|
||||
|
||||
// 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;
|
||||
public static final int CONVERT_GEOMETRY = 6;
|
||||
|
||||
// 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
|
||||
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_TITLESEC = 19;
|
||||
private static final int USE_TITLETOC = 20;
|
||||
private static final int USE_HYPERREF = 21;
|
||||
private static final int USE_CAPTION = 22;
|
||||
private static final int USE_LONGTABLE = 23;
|
||||
private static final int USE_SUPERTABULAR = 24;
|
||||
private static final int USE_TABULARY = 25;
|
||||
private static final int USE_ENDNOTES = 26;
|
||||
private static final int USE_ULEM = 27;
|
||||
private static final int USE_LASTPAGE = 28;
|
||||
private static final int USE_TITLEREF = 29;
|
||||
private static final int USE_BIBTEX = 30;
|
||||
private static final int BIBTEX_STYLE = 31;
|
||||
private static final int EXTERNAL_BIBTEX_FILES = 32;
|
||||
private static final int BIBTEX_ENCODING = 33;
|
||||
private static final int ZOTERO_BIBTEX_FILES = 34;
|
||||
private static final int JABREF_BIBTEX_FILES = 35;
|
||||
private static final int INCLUDE_ORIGINAL_CITATIONS = 36;
|
||||
private static final int USE_NATBIB = 37;
|
||||
private static final int NATBIB_OPTIONS = 38;
|
||||
private static final int FONT = 39;
|
||||
private static final int FORMATTING = 40;
|
||||
private static final int PAGE_FORMATTING = 41;
|
||||
private static final int OTHER_STYLES = 42;
|
||||
private static final int IMAGE_CONTENT = 43;
|
||||
private static final int TABLE_CONTENT = 44;
|
||||
private static final int TABLE_FIRST_HEAD_STYLE = 45;
|
||||
private static final int TABLE_HEAD_STYLE = 46;
|
||||
private static final int TABLE_FOOT_STYLE = 47;
|
||||
private static final int TABLE_LAST_FOOT_STYLE = 48;
|
||||
private static final int IGNORE_HARD_PAGE_BREAKS = 49;
|
||||
private static final int IGNORE_HARD_LINE_BREAKS = 50;
|
||||
private static final int IGNORE_EMPTY_PARAGRAPHS =51;
|
||||
private static final int IGNORE_DOUBLE_SPACES = 52;
|
||||
private static final int DISPLAY_HIDDEN_TEXT = 53;
|
||||
private static final int ALIGN_FRAMES = 54;
|
||||
private static final int FLOAT_FIGURES = 55;
|
||||
private static final int FLOAT_TABLES = 56;
|
||||
private static final int FLOAT_OPTIONS = 57;
|
||||
private static final int FIGURE_SEQUENCE_NAME = 58;
|
||||
private static final int TABLE_SEQUENCE_NAME = 59;
|
||||
private static final int IMAGE_OPTIONS = 60;
|
||||
private static final int REMOVE_GRAPHICS_EXTENSION = 61;
|
||||
private static final int ORIGINAL_IMAGE_SIZE = 62;
|
||||
private static final int SIMPLE_TABLE_LIMIT = 63;
|
||||
private static final int NOTES = 64;
|
||||
private static final int METADATA = 65;
|
||||
private static final int TABSTOP = 66;
|
||||
private static final int WRAP_LINES_AFTER = 67;
|
||||
private static final int SPLIT_LINKED_SECTIONS = 68;
|
||||
private static final int SPLIT_TOPLEVEL_SECTIONS = 69;
|
||||
private static final int SAVE_IMAGES_IN_SUBDIR = 70;
|
||||
private static final int OLD_MATH_COLORS = 71;
|
||||
private static final int DEBUG = 72;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// IV. Our options data
|
||||
|
||||
private ComplexOption headingMap;
|
||||
private ComplexOption parMap;
|
||||
private ComplexOption parBlockMap;
|
||||
private ComplexOption listMap;
|
||||
private ComplexOption listItemMap;
|
||||
private ComplexOption textMap;
|
||||
private ComplexOption textAttrMap;
|
||||
private ComplexOption stringReplace;
|
||||
private ComplexOption mathSymbols;
|
||||
private String sCustomPreamble = "";
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// V. The rather long constructor setting all defaults
|
||||
|
||||
/** Construct a new <code>LaTeXConfig</code> with default values for all options
|
||||
*/
|
||||
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_TITLESEC] = new BooleanOption("use_titlesec","false");
|
||||
options[USE_TITLETOC] = new BooleanOption("use_titletoc","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_BIBTEX] = new BooleanOption("use_bibtex","false");
|
||||
options[BIBTEX_STYLE] = new Option("bibtex_style","plain");
|
||||
options[EXTERNAL_BIBTEX_FILES] = new Option("external_bibtex_files","");
|
||||
options[BIBTEX_ENCODING] = new IntegerOption("bibtex_encoding","document") {
|
||||
public void setString(String sValue) {
|
||||
super.setString(sValue);
|
||||
if ("document".equals(sValue)) { nValue = -1; }
|
||||
else { nValue = ClassicI18n.readInputenc(sValue); }
|
||||
}
|
||||
};
|
||||
options[ZOTERO_BIBTEX_FILES] = new Option("zotero_bibtex_files","");
|
||||
options[JABREF_BIBTEX_FILES] = new Option("jabref_bibtex_files","");
|
||||
options[INCLUDE_ORIGINAL_CITATIONS] = new BooleanOption("include_original_citations","false");
|
||||
options[USE_NATBIB] = new BooleanOption("use_natbib","false");
|
||||
options[NATBIB_OPTIONS] = new Option("natbib_options","");
|
||||
options[FONT] = new Option("font","default");
|
||||
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 ("convert_geometry".equals(sValue)) nValue = CONVERT_GEOMETRY;
|
||||
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[TABLE_FIRST_HEAD_STYLE] = new Option("table_first_head_style","");
|
||||
options[TABLE_HEAD_STYLE] = new Option("table_head_style","");
|
||||
options[TABLE_FOOT_STYLE] = new Option("table_foot_style","");
|
||||
options[TABLE_LAST_FOOT_STYLE] = new Option("table_last_foot_style","");
|
||||
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[DISPLAY_HIDDEN_TEXT] = new BooleanOption("display_hidden_text","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","120") {
|
||||
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[OLD_MATH_COLORS] = new BooleanOption("old_math_colors","false");
|
||||
options[DEBUG] = new BooleanOption("debug","false");
|
||||
|
||||
// Complex options - heading map
|
||||
headingMap = addComplexOption("heading-map");
|
||||
Map<String,String> attr = new HashMap<String,String>();
|
||||
attr.put("name", "section");
|
||||
attr.put("level", "1");
|
||||
headingMap.put("1", attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("name", "subsection");
|
||||
attr.put("level", "2");
|
||||
headingMap.put("2", attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("name", "subsubsection");
|
||||
attr.put("level", "3");
|
||||
headingMap.put("3", attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("name", "paragraph");
|
||||
attr.put("level", "4");
|
||||
headingMap.put("4", attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("name", "subparagraph");
|
||||
attr.put("level", "5");
|
||||
headingMap.put("5", attr);
|
||||
|
||||
// Complex options - style maps
|
||||
parMap = addComplexOption("paragraph-map");
|
||||
parBlockMap = addComplexOption("paragraph-block-map");
|
||||
listMap = addComplexOption("list-map");
|
||||
listItemMap = addComplexOption("listitem-map");
|
||||
textMap = addComplexOption("text-map");
|
||||
textAttrMap = addComplexOption("text-attribute-map");
|
||||
|
||||
// Complex options - string replace
|
||||
stringReplace=addComplexOption("string-replace");
|
||||
|
||||
// Standard string replace:
|
||||
// Fix french spacing; replace nonbreaking space
|
||||
// right before em-dash, !, ?, : and ; (babel handles this)
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("fontenc", "any");
|
||||
attr.put("latex-code", " \u2014");
|
||||
stringReplace.put("\u00A0\u2014",attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("fontenc", "any");
|
||||
attr.put("latex-code", " !");
|
||||
stringReplace.put("\u00A0!",attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("fontenc", "any");
|
||||
attr.put("latex-code", " ?");
|
||||
stringReplace.put("\u00A0?",attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("fontenc", "any");
|
||||
attr.put("latex-code", " :");
|
||||
stringReplace.put("\u00A0:",attr);
|
||||
|
||||
attr = new HashMap<String,String>();
|
||||
attr.put("fontenc", "any");
|
||||
attr.put("latex-code", " ;");
|
||||
stringReplace.put("\u00A0;",attr);
|
||||
|
||||
// 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"));
|
||||
|
||||
// Complex options - math user defined symbols
|
||||
mathSymbols = addComplexOption("math-symbol-map");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// VI. Provide methods to fill in the gaps in the supers read and write methods
|
||||
|
||||
protected void readInner(Element elm) {
|
||||
if (elm.getTagName().equals("heading-map")) {
|
||||
// Unlike other complex options, a heading map is completely replaced
|
||||
headingMap.clear();
|
||||
Node child = elm.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (child.getNodeType()==Node.ELEMENT_NODE) {
|
||||
Element childElm = (Element) child;
|
||||
if (childElm.getTagName().equals("heading-level-map")) {
|
||||
if (childElm.hasAttribute("writer-level")) {
|
||||
Map<String,String> attr = new HashMap<String,String>();
|
||||
attr.put("name",childElm.getAttribute("name"));
|
||||
attr.put("level",childElm.getAttribute("level"));
|
||||
headingMap.put(childElm.getAttribute("writer-level"), attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
else 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");
|
||||
}
|
||||
|
||||
Map<String,String> attr = new HashMap<String,String>();
|
||||
attr.put("before", elm.getAttribute("before"));
|
||||
attr.put("after", elm.getAttribute("after"));
|
||||
|
||||
if ("paragraph".equals(sFamily)) {
|
||||
if (elm.hasAttribute("line-break")) { attr.put("line-break", elm.getAttribute("line-break")); }
|
||||
if (elm.hasAttribute("break-after")) { attr.put("break-after", elm.getAttribute("break-after")); }
|
||||
if (elm.hasAttribute("verbatim")) { attr.put("verbatim", elm.getAttribute("verbatim")); }
|
||||
parMap.put(sName, attr);
|
||||
}
|
||||
if ("paragraph-block".equals(sFamily)) {
|
||||
attr.put("next", elm.getAttribute("next"));
|
||||
if (elm.hasAttribute("verbatim")) { attr.put("verbatim", elm.getAttribute("verbatim")); }
|
||||
parBlockMap.put(sName, attr);
|
||||
}
|
||||
else if ("list".equals(sFamily)) {
|
||||
listMap.put(sName, attr);
|
||||
}
|
||||
else if ("listitem".equals(sFamily)) {
|
||||
listItemMap.put(sName, attr);
|
||||
}
|
||||
else if ("text".equals(sFamily)) {
|
||||
if (elm.hasAttribute("verbatim")) { attr.put("verbatim", elm.getAttribute("verbatim")); }
|
||||
textMap.put(sName, attr);
|
||||
}
|
||||
else if ("text-attribute".equals(sFamily)) {
|
||||
textAttrMap.put(sName, attr);
|
||||
}
|
||||
}
|
||||
else if (elm.getTagName().equals("string-replace")) {
|
||||
String sInput = elm.getAttribute("input");
|
||||
Map<String,String> attributes = new HashMap<String,String>();
|
||||
attributes.put("latex-code", elm.getAttribute("latex-code"));
|
||||
if (elm.hasAttribute("fontenc") && elm.getAttribute("fontenc").length()>0) {
|
||||
// The fontenc attribute is optional
|
||||
attributes.put("fontenc", elm.getAttribute("fontenc"));
|
||||
}
|
||||
else {
|
||||
attributes.put("fontenc", "any");
|
||||
}
|
||||
stringReplace.put(sInput,attributes);
|
||||
}
|
||||
else if (elm.getTagName().equals("math-symbol-map")) {
|
||||
String sName = elm.getAttribute("name");
|
||||
Map<String,String> attr = new HashMap<String,String>();
|
||||
attr.put("latex", elm.getAttribute("latex"));
|
||||
mathSymbols.put(sName, attr);
|
||||
}
|
||||
else if (elm.getTagName().equals("custom-preamble")) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
Node child = elm.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (child.getNodeType()==Node.TEXT_NODE) {
|
||||
buf.append(child.getNodeValue());
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
sCustomPreamble = buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeInner(Document dom) {
|
||||
// Write heading map
|
||||
int nMaxLevel = 0;
|
||||
while (nMaxLevel<10 && headingMap.get(Integer.toString(nMaxLevel+1))!=null) { nMaxLevel++; }
|
||||
|
||||
Element hmNode = dom.createElement("heading-map");
|
||||
// This attribute is not used anymore, but we keep it for backwards compatibility
|
||||
hmNode.setAttribute("max-level",Integer.toString(nMaxLevel));
|
||||
dom.getDocumentElement().appendChild(hmNode);
|
||||
for (int i=1; i<=nMaxLevel; i++) {
|
||||
Element hlmNode = dom.createElement("heading-level-map");
|
||||
String sWriterLevel = Integer.toString(i);
|
||||
hlmNode.setAttribute("writer-level",sWriterLevel);
|
||||
Map<String,String> attr = headingMap.get(sWriterLevel);
|
||||
hlmNode.setAttribute("name",attr.get("name"));
|
||||
hlmNode.setAttribute("level",attr.get("level"));
|
||||
hmNode.appendChild(hlmNode);
|
||||
}
|
||||
|
||||
// Write style maps
|
||||
writeStyleMap(dom,parMap,"paragraph");
|
||||
writeStyleMap(dom,parBlockMap,"paragraph-block");
|
||||
writeStyleMap(dom,listMap,"list");
|
||||
writeStyleMap(dom,listItemMap,"listitem");
|
||||
writeStyleMap(dom,textMap,"text");
|
||||
writeStyleMap(dom,textAttrMap,"text-attribute");
|
||||
|
||||
// Write string replace
|
||||
Set<String> inputStrings = stringReplace.keySet();
|
||||
for (String sInput : inputStrings) {
|
||||
Map<String,String> attributes = stringReplace.get(sInput);
|
||||
Element srNode = dom.createElement("string-replace");
|
||||
srNode.setAttribute("input",sInput);
|
||||
srNode.setAttribute("latex-code",attributes.get("latex-code"));
|
||||
srNode.setAttribute("fontenc",attributes.get("fontenc"));
|
||||
dom.getDocumentElement().appendChild(srNode);
|
||||
}
|
||||
|
||||
// Write math symbol map
|
||||
for (String sName : mathSymbols.keySet()) {
|
||||
String sLatex = mathSymbols.get(sName).get("latex");
|
||||
Element msNode = dom.createElement("math-symbol-map");
|
||||
msNode.setAttribute("name",sName);
|
||||
msNode.setAttribute("latex",sLatex);
|
||||
dom.getDocumentElement().appendChild(msNode);
|
||||
}
|
||||
|
||||
// Write custom preamble
|
||||
Element cp = dom.createElement("custom-preamble");
|
||||
cp.appendChild(dom.createTextNode( sCustomPreamble));
|
||||
dom.getDocumentElement().appendChild(cp);
|
||||
}
|
||||
|
||||
private void writeStyleMap(Document dom, ComplexOption co, String sFamily) {
|
||||
for (String sName : co.keySet()) {
|
||||
Map<String,String> attr = co.get(sName);
|
||||
Element smNode = dom.createElement("style-map");
|
||||
smNode.setAttribute("name",sName);
|
||||
smNode.setAttribute("family",sFamily);
|
||||
smNode.setAttribute("before",attr.containsKey("before") ? attr.get("before") : "");
|
||||
smNode.setAttribute("after",attr.containsKey("after") ? attr.get("after") : "");
|
||||
if (attr.containsKey("next")) {
|
||||
smNode.setAttribute("next",attr.get("next"));
|
||||
}
|
||||
if (attr.containsKey("line-break")) {
|
||||
smNode.setAttribute("line-break",attr.get("line-break"));
|
||||
}
|
||||
if (attr.containsKey("break-after")) {
|
||||
smNode.setAttribute("break-after", attr.get("break-after"));
|
||||
}
|
||||
if (attr.containsKey("verbatim")) {
|
||||
smNode.setAttribute("verbatim",attr.get("verbatim"));
|
||||
}
|
||||
dom.getDocumentElement().appendChild(smNode);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// VII. Convenience accessor methods
|
||||
|
||||
public HeadingMap getHeadingMap() {
|
||||
int nMaxLevel = 0;
|
||||
while (nMaxLevel<10 && headingMap.get(Integer.toString(nMaxLevel+1))!=null) { nMaxLevel++; }
|
||||
|
||||
HeadingMap map = new HeadingMap(nMaxLevel);
|
||||
for (int i=1; i<=nMaxLevel; i++) {
|
||||
String sWriterLevel = Integer.toString(i);
|
||||
Map<String,String> attr = headingMap.get(sWriterLevel);
|
||||
String sName = attr.get("name");
|
||||
int nLevel = Misc.getPosInteger(attr.get("level"),0);
|
||||
map.setLevelData(i, sName, nLevel);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// Get style maps
|
||||
public StyleMap getParStyleMap() { return getStyleMap(parMap); }
|
||||
public StyleMap getParBlockStyleMap() { return getStyleMap(parBlockMap); }
|
||||
public StyleMap getListStyleMap() { return getStyleMap(listMap); }
|
||||
public StyleMap getListItemStyleMap() { return getStyleMap(listItemMap); }
|
||||
public StyleMap getTextAttributeStyleMap() { return getStyleMap(textAttrMap); }
|
||||
public StyleMap getTextStyleMap() { return getStyleMap(textMap); }
|
||||
|
||||
private StyleMap getStyleMap(ComplexOption co) {
|
||||
StyleMap map = new StyleMap();
|
||||
for (String sName : co.keySet()) {
|
||||
Map<String,String> attr = co.get(sName);
|
||||
String sBefore = attr.containsKey("before") ? attr.get("before") : "";
|
||||
String sAfter = attr.containsKey("after") ? attr.get("after") : "";
|
||||
String sNext = attr.containsKey("next") ? attr.get("next") : "";
|
||||
boolean bLineBreak = !"false".equals(attr.get("line-break"));
|
||||
int nBreakAfter = StyleMapItem.PAR;
|
||||
String sBreakAfter = attr.get("break-after");
|
||||
if ("none".equals(sBreakAfter)) { nBreakAfter = StyleMapItem.NONE; }
|
||||
else if ("line".equals(sBreakAfter)) { nBreakAfter = StyleMapItem.LINE; }
|
||||
boolean bVerbatim = "true".equals(attr.get("verbatim"));
|
||||
map.put(sName, sBefore, sAfter, sNext, bLineBreak, nBreakAfter, bVerbatim);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// Return current string replace as a trie
|
||||
public ReplacementTrie getStringReplace() {
|
||||
ReplacementTrie trie = new ReplacementTrie();
|
||||
for (String sInput : stringReplace.keySet()) {
|
||||
Map<String,String> attributes = stringReplace.get(sInput);
|
||||
String sLaTeXCode = attributes.get("latex-code");
|
||||
String sFontenc = attributes.get("fontenc");
|
||||
trie.put(sInput,sLaTeXCode!=null ? sLaTeXCode : "",
|
||||
ClassicI18n.readFontencs(sFontenc!=null ? sFontenc : "any"));
|
||||
}
|
||||
return trie;
|
||||
}
|
||||
|
||||
// Get the math symbols as a simple Map
|
||||
public Map<String, String> getMathSymbols() {
|
||||
Map<String,String> map = new HashMap<String,String>();
|
||||
for (String sName : mathSymbols.keySet()) {
|
||||
String sLatex = mathSymbols.get(sName).get("latex");
|
||||
map.put(sName, sLatex);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// Get the custom preamble
|
||||
public String getCustomPreamble() { return sCustomPreamble; }
|
||||
|
||||
// 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 useTitlesec() { return ((BooleanOption) options[USE_TITLESEC]).getValue(); }
|
||||
public boolean useTitletoc() { return ((BooleanOption) options[USE_TITLETOC]).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 useBibtex() { return ((BooleanOption) options[USE_BIBTEX]).getValue(); }
|
||||
public String bibtexStyle() { return options[BIBTEX_STYLE].getString(); }
|
||||
public String externalBibtexFiles() { return options[EXTERNAL_BIBTEX_FILES].getString(); }
|
||||
public int getBibtexEncoding() { return ((IntegerOption) options[BIBTEX_ENCODING]).getValue(); }
|
||||
public String zoteroBibtexFiles() { return options[ZOTERO_BIBTEX_FILES].getString(); }
|
||||
public String jabrefBibtexFiles() { return options[JABREF_BIBTEX_FILES].getString(); }
|
||||
public boolean includeOriginalCitations() { return ((BooleanOption) options[INCLUDE_ORIGINAL_CITATIONS]).getValue(); }
|
||||
public boolean useNatbib() { return ((BooleanOption) options[USE_NATBIB]).getValue(); }
|
||||
public String getNatbibOptions() { return options[NATBIB_OPTIONS].getString(); }
|
||||
|
||||
// Formatting options
|
||||
public String getFont() { return options[FONT].getString(); }
|
||||
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 String getTableFirstHeadStyle() { return options[TABLE_FIRST_HEAD_STYLE].getString(); }
|
||||
public String getTableHeadStyle() { return options[TABLE_HEAD_STYLE].getString(); }
|
||||
public String getTableFootStyle() { return options[TABLE_FOOT_STYLE].getString(); }
|
||||
public String getTableLastFootStyle() { return options[TABLE_LAST_FOOT_STYLE].getString(); }
|
||||
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(); }
|
||||
public boolean displayHiddenText() { return ((BooleanOption) options[DISPLAY_HIDDEN_TEXT]).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(); }
|
||||
|
||||
// Compatibility options
|
||||
public boolean oldMathColors() { return ((BooleanOption) options[OLD_MATH_COLORS]).getValue(); }
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LaTeXDocument.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-05)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import writer2latex.api.MIMETypes;
|
||||
import writer2latex.api.OutputFile;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* <p>Class representing a LaTeX document.</p>
|
||||
*
|
||||
*/
|
||||
public class LaTeXDocument implements OutputFile {
|
||||
private static final String FILE_EXTENSION = ".tex";
|
||||
|
||||
private String sName;
|
||||
|
||||
private boolean bIsMaster;
|
||||
|
||||
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
|
||||
* @param bIsMaster true if this is a master document
|
||||
*/
|
||||
public LaTeXDocument(String sName,int nWrap,boolean bIsMaster) {
|
||||
this.nWrap = nWrap;
|
||||
this.sName = trimDocumentName(sName);
|
||||
this.bIsMaster = bIsMaster;
|
||||
contents = new LaTeXDocumentPortion(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <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);
|
||||
}
|
||||
|
||||
public String getMIMEType() {
|
||||
return MIMETypes.LATEX;
|
||||
}
|
||||
|
||||
public boolean isMasterDocument() {
|
||||
return bIsMaster;
|
||||
}
|
||||
|
||||
public boolean containsMath() {
|
||||
// We don't use this information currently
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* LaTeXDocumentPortion.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-19)
|
||||
*
|
||||
*/
|
||||
|
||||
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<Object> nodes; // The collection of all nodes in this portion
|
||||
|
||||
private StringBuilder 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?
|
||||
|
||||
/** Construct a new empty <code>LaTeXDocumentPortion</code>
|
||||
*
|
||||
* @param bWrap set to true if lines may be wrapped on writing
|
||||
*/
|
||||
public LaTeXDocumentPortion(boolean bWrap){
|
||||
this.bWrap = bWrap;
|
||||
nodes = new Vector<Object>();
|
||||
curText = new StringBuilder();
|
||||
bEmpty = true;
|
||||
}
|
||||
|
||||
/** Add another portion to the end of this portion
|
||||
*
|
||||
* @param ldp The <code>LaTeXDocuemtPortion</code> to add
|
||||
* @return a reference to this <code>LaTeXDocumentPortion</code> (not the appended one)
|
||||
*/
|
||||
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 StringBuilder();
|
||||
bEmpty = true;
|
||||
}
|
||||
nodes.add(ldp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a string to the end of this portion
|
||||
*
|
||||
* @param s the string to add
|
||||
* @return a reference to this <code>LaTeXDocumentPortion</code>
|
||||
*/
|
||||
public LaTeXDocumentPortion append(String s){
|
||||
curText.append(s);
|
||||
bEmpty = false; // even if this is the empty string!
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add an integer to the end of this portion
|
||||
*
|
||||
* @param n the integer to add
|
||||
* @return a reference to this <code>LaTeXDocumentPortion</code>
|
||||
*/
|
||||
public LaTeXDocumentPortion append(int n){
|
||||
curText.append(n);
|
||||
bEmpty = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a newline to the end of this portion
|
||||
*
|
||||
* @return a reference to this <code>LaTeXDocumentPortion</code>
|
||||
*/
|
||||
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 StringBuilder to the output */
|
||||
private void writeBuffer(StringBuilder 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 StringBuilder to the output without wrap */
|
||||
private void writeBuffer(StringBuilder 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
|
||||
*
|
||||
* @param osw an <code>OutputStreamWriter</code> to write to
|
||||
* @param nLineLen the line length after which automatic line breaks should occur if allowed (nLineLen=0 means no wrap)
|
||||
* @param sNewline the newline character(s) to use
|
||||
* @throws IOException if an exception occurs writing to to osw
|
||||
*/
|
||||
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((StringBuilder) nodes.get(i),osw,nLineLen,sNewline);
|
||||
}
|
||||
else {
|
||||
writeBuffer((StringBuilder) 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 LaTeXDocumentPortion as a string
|
||||
*
|
||||
* @return a string representation of the <code>LaTeXDocumentPortion</code>
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
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((StringBuilder) nodes.get(i));
|
||||
}
|
||||
}
|
||||
if (!bEmpty) { // write current node as well
|
||||
buf.append(curText.toString());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
|
@ -1,588 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ListConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-14)
|
||||
*
|
||||
*/
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
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.office.ListStyle;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Calc;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
public class ListConverter extends StyleConverter {
|
||||
boolean bNeedSaveEnumCounter = false;
|
||||
private Hashtable<String, String[]> listStyleLevelNames = new Hashtable<String, String[]>();
|
||||
|
||||
|
||||
/** Construct a new <code>ListConverter</code>
|
||||
*/
|
||||
public ListConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
}
|
||||
|
||||
@Override 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> 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();
|
||||
if ("true".equals(node.getAttribute(XMLString.TEXT_CONTINUE_NUMBERING))) { ic.setInContinuedList(true); }
|
||||
|
||||
// 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();
|
||||
applyListStyle(bOrdered,ba,ic);
|
||||
|
||||
// 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()) {
|
||||
palette.getBlockCv().traverseBlockText(node,ldp,oc);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply the style
|
||||
BeforeAfter ba = new BeforeAfter();
|
||||
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,oc);
|
||||
|
||||
// export the list item (note the special treatment of lists in tables)
|
||||
if (ba.getBefore().length()>0) {
|
||||
ldp.append(ba.getBefore());
|
||||
if (config.formatting()>=LaTeXConfig.CONVERT_MOST && !oc.isInTable()) { ldp.nl(); }
|
||||
}
|
||||
palette.getBlockCv().traverseBlockText(node,ldp,oc);
|
||||
if (ba.getAfter().length()>0 || oc.isInTable()) { 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;
|
||||
}
|
||||
|
||||
// Convert style information
|
||||
/** <p>Apply a list style to an ordered or unordered list.</p> */
|
||||
private void applyListStyle(boolean bOrdered, BeforeAfter ba, Context oc) {
|
||||
// Step 1. We may have a style map, this always takes precedence
|
||||
String sDisplayName = ofr.getListStyles().getDisplayName(oc.getListStyleName());
|
||||
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(oc.getListStyleName());
|
||||
if (style==null || config.formatting()<=LaTeXConfig.IGNORE_MOST) {
|
||||
if (oc.getListLevel()<=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
|
||||
// (for list in tables this is the maximum formatting we export)
|
||||
if (config.formatting()==LaTeXConfig.CONVERT_BASIC ||
|
||||
(config.formatting()>=LaTeXConfig.CONVERT_MOST && oc.isInTable())) {
|
||||
if (oc.getListLevel()==1) {
|
||||
if (!listStyleLevelNames.containsKey(oc.getListStyleName())) {
|
||||
createListStyleLabels(oc.getListStyleName());
|
||||
}
|
||||
ba.add("\\liststyle"+styleNames.addToExport(getDisplayName(oc.getListStyleName()))+"\n","");
|
||||
}
|
||||
if (oc.getListLevel()<=4) {
|
||||
String sCounterName = listStyleLevelNames.get(oc.getListStyleName())[oc.getListLevel()];
|
||||
if (oc.isInContinuedList() && style.isNumber(oc.getListLevel())) {
|
||||
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 (oc.isInContinuedList() && style.isNumber(oc.getListLevel())) {
|
||||
ba.add("\n\\setcounter{"+sCounterName+"}{\\value{saveenum}}","");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Step 4: Export with formatting, as "Writer style" custom lists
|
||||
if (oc.getListLevel()<=4) { // TODO: Max level should not be fixed
|
||||
if (!styleNames.containsName(getDisplayName(oc.getListStyleName()))) {
|
||||
createListStyle(oc.getListStyleName());
|
||||
}
|
||||
String sTeXName="list"+styleNames.addToExport(getDisplayName(oc.getListStyleName()))
|
||||
+"level"+Misc.int2roman(oc.getListLevel());
|
||||
if (!oc.isInContinuedList() && style.isNumber(oc.getListLevel())) {
|
||||
int nStartValue = Misc.getPosInteger(style.getLevelProperty(oc.getListLevel(),XMLString.TEXT_START_VALUE),1)-1;
|
||||
// Note that we need a blank line after certain constructions to get proper indentation
|
||||
ba.add("\n\\setcounter{"+sTeXName+"}{"+Integer.toString(nStartValue)+"}\n","");
|
||||
}
|
||||
ba.add("\\begin{"+sTeXName+"}","\\end{"+sTeXName+"}");
|
||||
}
|
||||
}
|
||||
|
||||
/** <p>Apply a list style to a list item.</p> */
|
||||
private void applyListItemStyle(String sStyleName, int nLevel, boolean bHeader,
|
||||
boolean bRestart, int nStartValue, BeforeAfter ba, Context oc) {
|
||||
// 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)
|
||||
// (for list in tables this is the maximum formatting we export)
|
||||
if (config.formatting()==LaTeXConfig.CONVERT_BASIC ||
|
||||
(config.formatting()>=LaTeXConfig.CONVERT_MOST && oc.isInTable())) {
|
||||
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.addToExport(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.addToExport(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.addToExport(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++) {
|
||||
// The alignment of the label works the same for old and new format
|
||||
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"; }
|
||||
}
|
||||
|
||||
if (style.isNewType(i)) {
|
||||
// The new type from ODT 1.2 is somewhat weird; we take it step by step
|
||||
|
||||
// Fist the list style defines a left margin (leftskip) and a first line indent (parindent)
|
||||
// to *replace* the values from the paragraph style
|
||||
String sMarginLeft = style.getLevelStyleProperty(i, XMLString.FO_MARGIN_LEFT);
|
||||
if (sMarginLeft==null) { sMarginLeft = "0cm"; }
|
||||
String sTextIndent = style.getLevelStyleProperty(i, XMLString.FO_TEXT_INDENT);
|
||||
if (sTextIndent==null) { sTextIndent = "0cm"; }
|
||||
|
||||
// Generate the LaTeX code to replace these values
|
||||
String sDefWriterlistleftskip = "\\def\\writerlistleftskip{\\setlength\\leftskip{"+sMarginLeft+"}}";
|
||||
String sDefWriterlistparindent = "\\def\\writerlistparindent{\\setlength\\parindent{"+sTextIndent+"}}";
|
||||
|
||||
// Next we have three types of label format: listtab, space, nothing
|
||||
String sFormat = style.getLevelStyleProperty(i, XMLString.TEXT_LABEL_FOLLOWED_BY);
|
||||
|
||||
// Generate LaTeX code to typeset the label, followed by a space character if required
|
||||
String sTheLabel = "\\label"+sLevelName[i]+("space".equals(sFormat) ? "\\ " : "");
|
||||
|
||||
if ("listtab".equals(sFormat) || sAlignmentChar=="r") {
|
||||
// In these cases we typeset the label aligned at a zero width box (rather than as an integrated part of the text)
|
||||
sTheLabel = "\\makebox[0cm][" + sAlignmentChar + "]{"+sTheLabel+"}";
|
||||
|
||||
if ("listtab".equals(sFormat)) {
|
||||
// In the tab case we must the calculate the hspace to put *after* the zero width box
|
||||
// This defines the position of an additional tab stop, which really means the start position of the text *after* the label
|
||||
String sTabPos = style.getLevelStyleProperty(i, XMLString.TEXT_LIST_TAB_STOP_POSITION);
|
||||
if (sTabPos==null) { sTabPos = "0cm"; }
|
||||
sTheLabel += "\\hspace{"+Calc.sub(sTabPos, Calc.add(sMarginLeft, sTextIndent))+"}";
|
||||
}
|
||||
}
|
||||
|
||||
// We are now ready to declare the list style
|
||||
declarations.append("\\newenvironment{").append(sLevelName[i]).append("}{")
|
||||
// Initialize hooks
|
||||
.append(sDefWriterlistleftskip)
|
||||
.append("\\def\\writerlistparindent{}")
|
||||
.append("\\def\\writerlistlabel{}")
|
||||
// Redefine \item
|
||||
.append("\\def\\item{")
|
||||
// The new parindent is the position of the label
|
||||
.append(sDefWriterlistparindent)
|
||||
.append("\\def\\writerlistlabel{");
|
||||
if (style.isNumber(i)) {
|
||||
declarations.append("\\stepcounter{").append(sLevelName[i]).append("}");
|
||||
}
|
||||
declarations.append(sTheLabel).append("\\writerlistremovelabel}}}{}").nl();
|
||||
}
|
||||
else {
|
||||
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);
|
||||
declarations
|
||||
.append("\\newenvironment{")
|
||||
.append(sLevelName[i]).append("}{")
|
||||
.append("\\def\\writerlistleftskip{\\addtolength\\leftskip{")
|
||||
.append(Calc.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(palette.getI18n().convert(sPrefix,false,"en")); }
|
||||
ldp.append("\\the").append(sName[i]);
|
||||
if (sSuffix!=null) { ldp.append(palette.getI18n().convert(sSuffix,false,"en")); }
|
||||
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) {
|
||||
String sFontName = palette.getCharSc().getFontName(style.getLevelProperty(i,XMLString.TEXT_STYLE_NAME));
|
||||
palette.getI18n().pushSpecialTable(sFontName);
|
||||
// Bullets are usually symbols, so this should be OK:
|
||||
ldp.append(palette.getI18n().convert(sBullet,false,"en"));
|
||||
palette.getI18n().popSpecialTable();
|
||||
}
|
||||
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; }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,401 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* MathConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-03)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import writer2latex.base.ConverterBase.TexMathsStyle;
|
||||
import writer2latex.office.EmbeddedObject;
|
||||
import writer2latex.office.EmbeddedXMLObject;
|
||||
import writer2latex.office.MIMETypes;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.TableReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/**
|
||||
* This ConverterHelper converts mathematical content to LaTeX.
|
||||
* It works slightly different than the other helpers: A number of elements may or may not
|
||||
* have content that should be converted to math. Thus the methods offered first examines
|
||||
* the content. If it turns out to be a mathematical formula, it is converted. Otherwise
|
||||
* nothing is done, and the method returns false.
|
||||
* Mathematical content may be MathML (with StarMath annotation), TexMaths or (the now obsolete) OOoLaTeX
|
||||
*/
|
||||
public final class MathConverter extends ConverterHelper {
|
||||
|
||||
private StarMathConverter smc;
|
||||
|
||||
private boolean bContainsFormulas = false;
|
||||
private boolean bAddParAfterDisplay = false;
|
||||
|
||||
private boolean bNeedTexMathsPreamble = false;
|
||||
private boolean bNeedOOoLaTeXPreamble = false;
|
||||
|
||||
private Element theEquation = null;
|
||||
private Element theSequence = null;
|
||||
|
||||
public MathConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
smc = new StarMathConverter(palette.getI18n(),config);
|
||||
bAddParAfterDisplay = config.formatting()>=LaTeXConfig.CONVERT_MOST;
|
||||
}
|
||||
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
if (bContainsFormulas) {
|
||||
smc.appendDeclarations(pack,decl);
|
||||
}
|
||||
if (bNeedTexMathsPreamble) {
|
||||
// The preamble may be stored as a user defined property (newline is represented as paragraph sign)
|
||||
Map<String,String> props = palette.getMetaData().getUserDefinedMetaData();
|
||||
if (props.containsKey("TexMathsPreamble")) {
|
||||
decl.append("% TexMaths preamble\n")
|
||||
.append(props.get("TexMathsPreamble").replace('\u00a7', '\n'));
|
||||
}
|
||||
}
|
||||
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: Replace with a method "handleEquation"
|
||||
public String convert(Element 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.SEMANTICS); // Since OOo 3.2
|
||||
if (semantics==null) {
|
||||
semantics = Misc.getChildByTagName(formula,XMLString.MATH_SEMANTICS);
|
||||
}
|
||||
if (semantics!=null) {
|
||||
Node annotation = Misc.getChildByTagName(semantics,XMLString.ANNOTATION); // Since OOo 3.2
|
||||
if (annotation==null) {
|
||||
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)
|
||||
if (formula.hasChildNodes()) {
|
||||
return "\\text{Warning: No StarMath annotation}";
|
||||
}
|
||||
else { // empty formula
|
||||
return " ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Try to convert a draw:frame or draw:g element as an (inline) TexMaths or OOoLaTeX equation
|
||||
*
|
||||
* @param node the element containing the equation (draw:frame or draw:g)
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
*
|
||||
* @return true if this elements happen to be a TexMaths equation, otherwise false
|
||||
*/
|
||||
public boolean handleTexMathsEquation(Element node, LaTeXDocumentPortion ldp) {
|
||||
String sLaTeX = null;
|
||||
Element equation = palette.getTexMathsEquation(node);
|
||||
if (equation!=null) {
|
||||
sLaTeX = Misc.getPCDATA(equation);
|
||||
if (sLaTeX!=null) { bNeedTexMathsPreamble = true; }
|
||||
}
|
||||
else { // Try OOoLaTeX
|
||||
// The LaTeX code is embedded in a custom style attribute:
|
||||
StyleWithProperties style = ofr.getFrameStyle(Misc.getAttribute(node, XMLString.DRAW_STYLE_NAME));
|
||||
if (style!=null) {
|
||||
sLaTeX = style.getProperty("OOoLatexArgs");
|
||||
if (sLaTeX!=null) { bNeedOOoLaTeXPreamble = true; }
|
||||
}
|
||||
}
|
||||
if (sLaTeX!=null) {
|
||||
// Format is <point size>X<mode>X<TeX code>X<format>X<resolution>X<transparency>
|
||||
// where X is a paragraph sign
|
||||
switch (palette.getTexMathsStyle(sLaTeX)) {
|
||||
case inline:
|
||||
ldp.append("$").append(palette.getTexMathsEquation(sLaTeX)).append("$");
|
||||
break;
|
||||
case display:
|
||||
ldp.append("$\\displaystyle ").append(palette.getTexMathsEquation(sLaTeX)).append("$");
|
||||
break;
|
||||
case latex:
|
||||
ldp.append(palette.getTexMathsEquation(sLaTeX));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Try to convert a table as a display equation:
|
||||
* A 1 row by 2 columns table in which each cell contains exactly one paragraph,
|
||||
* the left cell contains exactly one formula and the right cell contains exactly
|
||||
* one sequence number is treated as a (numbered) display equation.
|
||||
* This happens to coincide with the AutoText provided with OOo Writer :-)
|
||||
* @param table the table reader
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the table
|
||||
* did not represent a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(TableReader table, LaTeXDocumentPortion ldp) {
|
||||
if (table.getRowCount()==1 && table.getColCount()==2 &&
|
||||
OfficeReader.isSingleParagraph(table.getCell(0, 0)) && OfficeReader.isSingleParagraph(table.getCell(0, 1)) ) {
|
||||
// Table of the desired form
|
||||
if (parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 0))) && theEquation!=null && theSequence==null) {
|
||||
// Found equation in first cell
|
||||
Element myEquation = theEquation;
|
||||
if (parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 1))) && theEquation==null && theSequence!=null) {
|
||||
// Found sequence in second cell
|
||||
handleDisplayEquation(myEquation, theSequence, ldp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**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 (possibly with formatting).
|
||||
* @param node the paragraph
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the paragraph
|
||||
* did not contain a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(Element node, LaTeXDocumentPortion ldp) {
|
||||
if (parseDisplayEquation(node) && theEquation!=null) {
|
||||
handleDisplayEquation(theEquation, theSequence, ldp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDisplayEquation(Element equation, Element sequence, LaTeXDocumentPortion ldp) {
|
||||
boolean bTexMaths = equation.getTagName().equals(XMLString.SVG_DESC);
|
||||
TexMathsStyle style = TexMathsStyle.inline;
|
||||
String sLaTeX;
|
||||
if (bTexMaths) {
|
||||
// TeXMaths equation
|
||||
sLaTeX = palette.getTexMathsEquation(Misc.getPCDATA(equation));
|
||||
style = palette.getTexMathsStyle(Misc.getPCDATA(equation));
|
||||
if (sLaTeX!=null) { bNeedTexMathsPreamble = true; }
|
||||
}
|
||||
else {
|
||||
// MathML equation
|
||||
sLaTeX = convert(equation);
|
||||
}
|
||||
if (sLaTeX!=null && !" ".equals(sLaTeX)) { // ignore empty formulas
|
||||
if (!bTexMaths || style!=TexMathsStyle.latex) {
|
||||
// Unfortunately we can't do numbered equations for TexMaths equations with latex style
|
||||
if (sequence!=null) {
|
||||
// Numbered equation
|
||||
ldp.append("\\begin{equation}");
|
||||
palette.getFieldCv().handleSequenceLabel(sequence,ldp);
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation}").nl();
|
||||
}
|
||||
else {
|
||||
// Unnumbered equation
|
||||
ldp.append("\\begin{equation*}");
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation*}").nl();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ldp.append(sLaTeX).nl();
|
||||
}
|
||||
if (bAddParAfterDisplay) { ldp.nl(); }
|
||||
}
|
||||
}
|
||||
|
||||
/** Determine whether or not a paragraph contains a display equation.
|
||||
* A paragraph is a display equation if it contains a single formula and no text content except whitespace
|
||||
* and an optional sequence number which may be in brackets.
|
||||
* As a side effect, this method keeps a reference to the equation and the sequence number
|
||||
*
|
||||
* @param node the paragraph
|
||||
* @return true if this is a display equation
|
||||
*/
|
||||
private boolean parseDisplayEquation(Node node) {
|
||||
theEquation = null;
|
||||
theSequence = null;
|
||||
return doParseDisplayEquation(node);
|
||||
}
|
||||
|
||||
private boolean doParseDisplayEquation(Node node) {
|
||||
Node child = node.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (Misc.isElement(child)) {
|
||||
Element elm = (Element) child;
|
||||
String sName = elm.getTagName();
|
||||
// First check for MathML or TexMaths equation
|
||||
Element equation = getMathmlEquation(elm);
|
||||
if (equation==null) {
|
||||
equation = palette.getTexMathsEquation(elm);
|
||||
}
|
||||
|
||||
if (equation!=null) {
|
||||
if (theEquation==null) {
|
||||
theEquation = equation;
|
||||
}
|
||||
else { // two or more equations -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (XMLString.TEXT_SEQUENCE.equals(sName)) {
|
||||
if (theSequence==null) {
|
||||
theSequence = elm;
|
||||
}
|
||||
else { // two sequence numbers -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (XMLString.TEXT_SPAN.equals(sName)) {
|
||||
if (!doParseDisplayEquation(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 if (XMLString.TEXT_SOFT_PAGE_BREAK.equals(sName)) { // since ODF 1.1
|
||||
// Soft page breaks 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;
|
||||
}
|
||||
|
||||
/** Get a MathML formula from a draw:frame
|
||||
*
|
||||
* @param node the draw:frame
|
||||
* @return the MathML element, or null if this is not a MathML formula
|
||||
*/
|
||||
private Element getMathmlEquation(Element node) {
|
||||
if (node.getTagName().equals(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();
|
||||
Element formula = Misc.getChildByTagName(formuladoc,XMLString.MATH); // Since OOo 3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
catch (org.xml.sax.SAXException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (java.io.IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // flat XML, object is contained in node
|
||||
Element formula = Misc.getChildByTagName(node,XMLString.MATH); // Since OOo 3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(node,XMLString.MATH_MATH);
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,400 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* NoteConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-15)
|
||||
*
|
||||
*/
|
||||
|
||||
// TODO: Get the styles for footnotes and endnotes and use Context.resetFormattingFromStyle...
|
||||
|
||||
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<Element> postponedFootnotes = new LinkedList<Element>();
|
||||
|
||||
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.addToExport(sId)+"}");
|
||||
}
|
||||
traverseNoteBody(fntbody,ldp,ic);
|
||||
ldp.append("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Do we have any pending footnotes, that may be inserted in this context?
|
||||
*
|
||||
* @param oc the context to verify against
|
||||
* @return true if there are pending footnotes
|
||||
*/
|
||||
public boolean hasPendingFootnotes(Context oc) {
|
||||
return !oc.isNoFootnotes() && postponedFootnotes.size()>0;
|
||||
}
|
||||
|
||||
/** 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(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(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.addToExport(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.addToExport(sName)+"}");
|
||||
}
|
||||
else if ("text".equals(sFormat) && sName!=null) {
|
||||
ldp.append("\\ref{fnt:"+footnotenames.addToExport(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.addToExport(sName)+"}");
|
||||
}
|
||||
else if ("text".equals(sFormat) && sName!=null) {
|
||||
ldp.append("\\ref{ent:"+endnotenames.addToExport(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);
|
||||
|
||||
// Headings inside footnotes are considere a mistake and exported as ordinary paragraphs
|
||||
if (nodeName.equals(XMLString.TEXT_H) || nodeName.equals(XMLString.TEXT_P)) {
|
||||
StyleWithProperties style = ofr.getParStyle(node.getAttribute(XMLString.TEXT_STYLE_NAME));
|
||||
oc.resetFormattingFromStyle(style);
|
||||
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.getListCv().handleList(child,ldp,oc);
|
||||
}
|
||||
|
||||
if (nodeName.equals(XMLString.TEXT_ORDERED_LIST)) {
|
||||
palette.getListCv().handleList(child,ldp,oc);
|
||||
}
|
||||
|
||||
if (nodeName.equals(XMLString.TEXT_UNORDERED_LIST)) {
|
||||
palette.getListCv().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(ListConverter.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();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<!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>
|
|
@ -1,596 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* PageStyleConverter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-15)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import writer2latex.util.CSVList;
|
||||
import writer2latex.util.Calc;
|
||||
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 || config.pageFormatting()==LaTeXConfig.CONVERT_GEOMETRY) 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.addToExport(getDisplayName(sName))+"}\n", "");
|
||||
}
|
||||
else {
|
||||
ba.add("\\pagestyle{"+styleNames.addToExport(getDisplayName(sNextName))+"}\n"+
|
||||
"\\thispagestyle{"+styleNames.addToExport(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 || config.pageFormatting()==LaTeXConfig.CONVERT_GEOMETRY) { return; }
|
||||
|
||||
Context context = new Context();
|
||||
context.resetFormattingFromStyle(ofr.getDefaultParStyle());
|
||||
context.setInHeaderFooter(true);
|
||||
|
||||
|
||||
Enumeration<OfficeStyle> 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.addToExport(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.addToExport(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(ListConverter.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(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 && config.pageFormatting()!=LaTeXConfig.CONVERT_GEOMETRY) { 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<OfficeStyle> 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 && Calc.isLessThan(sHeadHeight,sThisHeadHeight)) {
|
||||
sHeadHeight = sThisHeadHeight;
|
||||
}
|
||||
String sThisHeadSep = layout.getHeaderProperty(XMLString.FO_MARGIN_BOTTOM);
|
||||
if (sThisHeadSep!=null && Calc.isLessThan(sHeadSep,sThisHeadSep)) {
|
||||
sHeadSep = sThisHeadSep;
|
||||
}
|
||||
bIncludeHead = true;
|
||||
}
|
||||
if (layout.hasFooterStyle()) {
|
||||
String sThisFootHeight = layout.getFooterProperty(XMLString.FO_MIN_HEIGHT);
|
||||
if (sThisFootHeight!=null && Calc.isLessThan(sFootHeight,sThisFootHeight)) {
|
||||
sFootHeight = sThisFootHeight;
|
||||
}
|
||||
String sThisFootSep = layout.getFooterProperty(XMLString.FO_MARGIN_TOP);
|
||||
if (sThisFootSep!=null && Calc.isLessThan(sFootSep,sThisFootSep)) {
|
||||
sFootSep = sThisFootSep;
|
||||
}
|
||||
bIncludeFoot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Define 12pt as minimum height (the source may specify 0pt..)
|
||||
if (bIncludeHead && Calc.isLessThan(sHeadHeight,"12pt")) {
|
||||
sHeadHeight = "12pt";
|
||||
}
|
||||
if (bIncludeFoot && Calc.isLessThan(sFootHeight,"12pt")) {
|
||||
sFootHeight = "12pt";
|
||||
}
|
||||
|
||||
String sFootSkip = Calc.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 = Calc.sub(sPaperHeight,sMarginTop);
|
||||
sTextHeight = Calc.sub(sTextHeight,sHeadHeight);
|
||||
sTextHeight = Calc.sub(sTextHeight,sHeadSep);
|
||||
sTextHeight = Calc.sub(sTextHeight,sFootSkip);
|
||||
sTextHeight = Calc.sub(sTextHeight,sMarginBottom);
|
||||
String sTextWidth = Calc.sub(sPaperWidth,sMarginLeft);
|
||||
sTextWidth = Calc.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(Calc.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 = Calc.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 Calc.isLessThan(Calc.abs(Calc.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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,586 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ParConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-08)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
import writer2latex.latex.util.Context;
|
||||
import writer2latex.latex.util.StyleMapItem;
|
||||
import writer2latex.latex.util.StyleMap;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Calc;
|
||||
|
||||
/* <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;
|
||||
|
||||
// Display hidden text?
|
||||
private boolean bDisplayHiddenText = false;
|
||||
|
||||
/** <p>Constructs a new <code>ParConverter</code>.</p>
|
||||
*/
|
||||
public ParConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
this.bDisplayHiddenText = config.displayHiddenText();
|
||||
}
|
||||
|
||||
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:p element node containing the paragraph
|
||||
* @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) {
|
||||
// Check for display equation (except in table cells)
|
||||
if ((!oc.isInTable()) && palette.getMathCv().handleDisplayEquation(node,ldp)) { return; }
|
||||
|
||||
// Get the style for this paragraph
|
||||
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
|
||||
StyleWithProperties style = ofr.getParStyle(sStyleName);
|
||||
String sDisplayName = ofr.getParStyles().getDisplayName(sStyleName);
|
||||
|
||||
// Check for hidden text
|
||||
if (!bDisplayHiddenText && style!=null && "none".equals(style.getProperty(XMLString.TEXT_DISPLAY))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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();
|
||||
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
|
||||
int nBreakAfter;
|
||||
BeforeAfter ba = new BeforeAfter();
|
||||
if (oc.isInTable()) {
|
||||
nBreakAfter = applyCellParStyle(sStyleName,ba,ic,OfficeReader.getCharacterCount(node)==0,bLastInBlock);
|
||||
}
|
||||
else {
|
||||
nBreakAfter = 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 line break if desired
|
||||
if (nBreakAfter!=StyleMapItem.NONE) { ldp.nl(); }
|
||||
// Add a blank line except within verbatim and last in a block, and if desired by style map
|
||||
if (!bLastInBlock && !ic.isVerbatim() && !ic.isInSimpleTable() && nBreakAfter==StyleMapItem.PAR) { 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 int 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
|
||||
|
||||
context.setVerbatim(false);
|
||||
|
||||
int nBreakAfter = bLastInBlock ? StyleMapItem.NONE : StyleMapItem.PAR;
|
||||
|
||||
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(" ",""); }
|
||||
}
|
||||
}
|
||||
nBreakAfter = StyleMapItem.NONE;
|
||||
}
|
||||
else if (config.getParStyleMap().contains(ofr.getParStyles().getDisplayName(sName))) {
|
||||
// We have a style map in the configuration
|
||||
StyleMap sm = config.getParStyleMap();
|
||||
String sDisplayName = ofr.getParStyles().getDisplayName(sName);
|
||||
String sBefore = sm.getBefore(sDisplayName);
|
||||
String sAfter = sm.getAfter(sDisplayName);
|
||||
ba.add(sBefore, sAfter);
|
||||
// Add line breaks inside?
|
||||
if (sm.getLineBreak(sDisplayName)) {
|
||||
if (sBefore.length()>0) { ba.add("\n",""); }
|
||||
if (sAfter.length()>0 && !"}".equals(sAfter)) { ba.add("","\n"); }
|
||||
}
|
||||
nBreakAfter = sm.getBreakAfter(sDisplayName);
|
||||
if (sm.getVerbatim(sDisplayName)) { context.setVerbatim(true); }
|
||||
}
|
||||
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}"); }
|
||||
nBreakAfter = StyleMapItem.LINE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Export character formatting + alignment only
|
||||
BeforeAfter baPar = new BeforeAfter();
|
||||
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)) { baPar.add("\\centering\\arraybslash",""); }
|
||||
else if ("end".equals(sTextAlign)) { baPar.add("\\raggedleft\\arraybslash",""); }
|
||||
bNeedArrayBslash = true;
|
||||
}
|
||||
else if (bLastInBlock) { // no \par needed
|
||||
if ("center".equals(sTextAlign)) { baPar.add("\\centering",""); }
|
||||
else if ("end".equals(sTextAlign)) { baPar.add("\\raggedleft",""); }
|
||||
}
|
||||
else {
|
||||
if ("center".equals(sTextAlign)) { baPar.add("\\centering","\\par"); }
|
||||
else if ("end".equals(sTextAlign)) { baPar.add("\\raggedleft","\\par"); }
|
||||
}
|
||||
palette.getI18n().applyLanguage(style,true,true,baText);
|
||||
palette.getCharSc().applyFont(style,true,true,baText,context);
|
||||
}
|
||||
|
||||
// Group the contents if this is not the last paragraph in the cell
|
||||
boolean bIsGrouped = false;
|
||||
if ((!baPar.isEmpty() || !baText.isEmpty()) && !bLastInBlock) {
|
||||
ba.add("{","}");
|
||||
bIsGrouped = true;
|
||||
}
|
||||
ba.add(baPar);
|
||||
// Group the text formatting in any case (supertabular needs this)
|
||||
if (!baText.isEmpty() && !bIsGrouped) {
|
||||
ba.add("{", "}");
|
||||
}
|
||||
ba.add(baText);
|
||||
if (ba.getBefore().length()>0) { ba.add(" ",""); }
|
||||
}
|
||||
|
||||
// Update context
|
||||
StyleWithProperties style = ofr.getParStyle(sName);
|
||||
if (style!=null) {
|
||||
context.updateFormattingFromStyle(style);
|
||||
}
|
||||
return nBreakAfter;
|
||||
}
|
||||
|
||||
|
||||
/** <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 int applyParStyle(String sName, BeforeAfter ba, Context context, boolean bNoTextPar) {
|
||||
return applyParStyle(sName,ba,context,bNoTextPar,true);
|
||||
}
|
||||
|
||||
private int applyParStyle(String sName, BeforeAfter ba, Context context, boolean bNoTextPar, boolean bBreakInside) {
|
||||
// No style specified?
|
||||
if (sName==null) { return StyleMapItem.PAR; }
|
||||
|
||||
/*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*/
|
||||
int nBreakAfter = StyleMapItem.PAR;
|
||||
|
||||
if (bNoTextPar && (config.formatting()==LaTeXConfig.CONVERT_BASIC || config.formatting()==LaTeXConfig.IGNORE_MOST) ) {
|
||||
//TODO: If there is a style map, we should respect that despite the fact that the paragraph is empty
|
||||
// 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}"); nBreakAfter = StyleMapItem.LINE; }
|
||||
else if ("end".equals(sTextAlign)) { ba.add("{\\raggedleft ","\\par}"); nBreakAfter = StyleMapItem.LINE; }
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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"); }
|
||||
}
|
||||
nBreakAfter = styleMap.getBreakAfter(sName);
|
||||
}
|
||||
|
||||
// Update context
|
||||
StyleWithProperties style = ofr.getParStyle(sName);
|
||||
if (style!=null) {
|
||||
context.updateFormattingFromStyle(style);
|
||||
}
|
||||
context.setVerbatim(styleMap.getVerbatim(sName));
|
||||
|
||||
return nBreakAfter;
|
||||
}
|
||||
|
||||
/** <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.getBreakAfter(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.getBreakAfter(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,styleMap.getBreakAfter(sParentName), 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.addToExport(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=Calc.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 = Calc.multiply("10%",sMarginTop);
|
||||
if (Calc.length2px(sRubberMarginTop).equals("0")) { sRubberMarginTop="1pt"; }
|
||||
String sRubberMarginBottom = Calc.multiply("10%",sMarginBottom);
|
||||
if (Calc.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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* SectionConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-08)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
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;
|
||||
|
||||
// Display hidden text?
|
||||
private boolean bDisplayHiddenText = 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);
|
||||
this.bDisplayHiddenText = config.displayHiddenText();
|
||||
}
|
||||
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
if (bNeedMulticol) { pack.append("\\usepackage{multicol}").nl(); }
|
||||
}
|
||||
|
||||
// Handle a section as a Zotero bibliography
|
||||
private boolean handleZoteroBibliography(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
String sName = node.getAttribute(XMLString.TEXT_NAME);
|
||||
if (config.useBibtex() && config.zoteroBibtexFiles().length()>0 && sName.startsWith("ZOTERO_BIBL")) {
|
||||
// This section is a Zotero bibliography, and the user wishes to handle it as such
|
||||
// A Zotero bibliography name has the form ZOTERO_BIBL <json object> <identifier> with a single space separating the items
|
||||
// The identifier is a unique identifier for the bibliography and is not used here
|
||||
if (!config.noIndex()) {
|
||||
// Parse the name (errors are ignored) and add \nocite commands as appropriate
|
||||
int nObjectStart = sName.indexOf('{');
|
||||
int nObjectEnd = sName.lastIndexOf('}');
|
||||
if (nObjectStart>-1 && nObjectEnd>-1 && nObjectStart<nObjectEnd) {
|
||||
String sJsonObject = sName.substring(nObjectStart, nObjectEnd+1);
|
||||
JSONObject jo = null;
|
||||
try {
|
||||
jo = new JSONObject(sJsonObject);
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
if (jo!=null) {
|
||||
JSONArray uncited = null;
|
||||
try {
|
||||
uncited = jo.getJSONArray("uncited");
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
if (uncited!=null) {
|
||||
int nCount = uncited.length();
|
||||
if (nCount>0) {
|
||||
ldp.append("\\nocite{");
|
||||
for (int nIndex=0; nIndex<nCount; nIndex++) {
|
||||
if (nIndex>0) {
|
||||
ldp.append(",");
|
||||
}
|
||||
String sURI = null;
|
||||
try { // Each item is an array containing a single string
|
||||
sURI = uncited.getJSONArray(nIndex).getString(0);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
}
|
||||
if (sURI!=null) {
|
||||
int nSlash = sURI.lastIndexOf('/');
|
||||
if (nSlash>0) { ldp.append(sURI.substring(nSlash+1)); }
|
||||
else { ldp.append(sURI); }
|
||||
}
|
||||
}
|
||||
ldp.append("}").nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the BibTeX style and files given in the configuration
|
||||
ldp.append("\\bibliographystyle{").append(config.bibtexStyle()).append("}").nl()
|
||||
.append("\\bibliography{").append(config.zoteroBibtexFiles()).append("}").nl();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a section as a JabRef bibliography
|
||||
private boolean handleJabRefBibliography(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
String sName = node.getAttribute(XMLString.TEXT_NAME);
|
||||
if (config.useBibtex() && config.jabrefBibtexFiles().length()>0 && sName.equals("JR_bib")) {
|
||||
// This section is a JabRef bibliography, and the user wishes to handle it as such
|
||||
// A JabRef bibliography is identified by the name JR_bib
|
||||
// Use the BibTeX style and files given in the configuration
|
||||
ldp.append("\\bibliographystyle{").append(config.bibtexStyle()).append("}").nl()
|
||||
.append("\\bibliography{").append(config.jabrefBibtexFiles()).append("}").nl();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** <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) {
|
||||
// Unlike headings, paragraphs and spans, text:display is not attached to the style:
|
||||
if (!bDisplayHiddenText && "none".equals(Misc.getAttribute(node,XMLString.TEXT_DISPLAY))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.addToExport(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.addToExport(node.getAttribute(XMLString.TEXT_NAME));
|
||||
}
|
||||
|
||||
LaTeXDocumentPortion sectionLdp = ldp;
|
||||
if (sFileName!=null) {
|
||||
LaTeXDocument newDoc = new LaTeXDocument(sFileName,config.getWrapLinesAfter(),false);
|
||||
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();
|
||||
}
|
||||
// Zotero or JabRef might have generated this section as a bibliograhy:
|
||||
if (!handleZoteroBibliography(node,sectionLdp,ic) && !handleJabRefBibliography(node,sectionLdp,ic)) {
|
||||
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
|
@ -1,50 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* StyleConverter.java
|
||||
*
|
||||
* Copyright: 2002-2008 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,491 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* TableConverter.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-03)
|
||||
*
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
enum RowType {
|
||||
FIRST_HEAD, HEAD, BODY, FOOT, LAST_FOOT;
|
||||
}
|
||||
|
||||
/** <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 = <string></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 RowType[] rowTypes;
|
||||
|
||||
// Return the paragraph style of the first paragraph/heading within this block text
|
||||
private String getFirstParStyle(Element node) {
|
||||
Node child = node.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (Misc.isElement(child, XMLString.TEXT_P) || Misc.isElement(child, XMLString.TEXT_H)) {
|
||||
String sStyleName = Misc.getAttribute(child, XMLString.TEXT_STYLE_NAME);
|
||||
if (sStyleName!=null) {
|
||||
StyleWithProperties style = ofr.getParStyle(sStyleName);
|
||||
if (style!=null) {
|
||||
if (style.isAutomatic()) {
|
||||
sStyleName = style.getParentName();
|
||||
}
|
||||
return ofr.getParStyles().getDisplayName(sStyleName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (OfficeReader.isTextElement(child)) {
|
||||
return getFirstParStyle((Element)child);
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasRowType(RowType test) {
|
||||
for (RowType type : rowTypes) {
|
||||
if (type==test) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (palette.getMathCv().handleDisplayEquation(table,ldp)) { return; }
|
||||
|
||||
// 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,config.floatTables() && !ic.isInFrame() && !table.isSubTable());
|
||||
|
||||
// Identify the row types
|
||||
rowTypes = new RowType[table.getRowCount()];
|
||||
for (int nRow=0; nRow<table.getRowCount(); nRow++) {
|
||||
// First collect the row type as defined in the document
|
||||
if (nRow<table.getFirstBodyRow()) {
|
||||
rowTypes[nRow] = RowType.HEAD;
|
||||
}
|
||||
else {
|
||||
rowTypes[nRow] = RowType.BODY;
|
||||
}
|
||||
if (formatter.isLongtable() || formatter.isSupertabular()) {
|
||||
// Then override with user defined row types where applicable
|
||||
// (but only for multipage tables)
|
||||
// The row type is determined from the first paragraph in the first cell
|
||||
String sStyleName = getFirstParStyle(table.getCell(nRow, 0));
|
||||
if (sStyleName!=null) {
|
||||
if (sStyleName.equals(config.getTableFirstHeadStyle())) {
|
||||
rowTypes[nRow] = RowType.FIRST_HEAD;
|
||||
}
|
||||
else if (sStyleName.equals(config.getTableHeadStyle())) {
|
||||
rowTypes[nRow] = RowType.HEAD;
|
||||
}
|
||||
else if (sStyleName.equals(config.getTableFootStyle())) {
|
||||
rowTypes[nRow] = RowType.FOOT;
|
||||
}
|
||||
else if (sStyleName.equals(config.getTableLastFootStyle())) {
|
||||
rowTypes[nRow] = RowType.LAST_FOOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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("\\tablefirsthead{");
|
||||
if (hasRowType(RowType.FIRST_HEAD)) {
|
||||
handleRows(ldp,oc,RowType.FIRST_HEAD,true,false);
|
||||
}
|
||||
else {
|
||||
handleRows(ldp,oc,RowType.HEAD,true,false);
|
||||
}
|
||||
ldp.append("}\n");
|
||||
ldp.append("\\tablehead{");
|
||||
handleRows(ldp,oc,RowType.HEAD,true,false);
|
||||
ldp.append("}\n");
|
||||
|
||||
// Table foot
|
||||
ldp.append("\\tabletail{");
|
||||
handleRows(ldp,oc,RowType.FOOT,true,true);
|
||||
ldp.append("}\n");
|
||||
ldp.append("\\tablelasttail{");
|
||||
if (hasRowType(RowType.LAST_FOOT)) {
|
||||
handleRows(ldp,oc,RowType.LAST_FOOT,true,true);
|
||||
}
|
||||
else {
|
||||
handleRows(ldp,oc,RowType.FOOT,true,true);
|
||||
}
|
||||
ldp.append("}\n");
|
||||
|
||||
// The table body
|
||||
handleHyperTarget(ldp);
|
||||
ldp.append(baTable.getBefore()).nl();
|
||||
handleRows(ldp,oc,RowType.BODY,true,!hasRowType(RowType.FOOT) && !hasRowType(RowType.LAST_FOOT));
|
||||
ldp.nl().append(baTable.getAfter()).nl();
|
||||
|
||||
ldp.append(baTableAlign.getAfter());
|
||||
}
|
||||
|
||||
private void handleLongtable(LaTeXDocumentPortion ldp, Context oc) {
|
||||
handleHyperTarget(ldp);
|
||||
ldp.append(baTable.getBefore()).nl();
|
||||
|
||||
// First head
|
||||
if (caption!=null && bCaptionAbove) {
|
||||
// If there's a caption above, we must use \endfirsthead
|
||||
// and have to repeat the head if there's no first head
|
||||
handleCaption("\\caption",ldp,oc);
|
||||
ldp.append("\\\\").nl();
|
||||
if (hasRowType(RowType.FIRST_HEAD)) {
|
||||
handleRows(ldp,oc,RowType.FIRST_HEAD,true,true);
|
||||
}
|
||||
else {
|
||||
handleRows(ldp,oc,RowType.HEAD,true,true);
|
||||
}
|
||||
ldp.nl().append("\\endfirsthead").nl();
|
||||
}
|
||||
else if (hasRowType(RowType.FIRST_HEAD)) {
|
||||
// Otherwise we only need it if the table contains a first head
|
||||
handleRows(ldp,oc,RowType.FIRST_HEAD,true,true);
|
||||
ldp.nl().append("\\endfirsthead").nl();
|
||||
}
|
||||
|
||||
// Head
|
||||
handleRows(ldp,oc,RowType.HEAD,true,true);
|
||||
ldp.nl().append("\\endhead").nl();
|
||||
|
||||
// Foot
|
||||
handleRows(ldp,oc,RowType.FOOT,false,true);
|
||||
ldp.nl().append("\\endfoot").nl();
|
||||
|
||||
// Last foot
|
||||
if (caption!=null && !bCaptionAbove) {
|
||||
// If there's a caption below, we must use \endlastfoot
|
||||
// and have to repeat the foot if there's no last foot
|
||||
if (hasRowType(RowType.LAST_FOOT)) {
|
||||
handleRows(ldp,oc,RowType.LAST_FOOT,false,true);
|
||||
ldp.nl();
|
||||
}
|
||||
else if (hasRowType(RowType.FOOT)){
|
||||
handleRows(ldp,oc,RowType.FOOT,false,true);
|
||||
ldp.nl();
|
||||
}
|
||||
handleCaption("\\caption",ldp,oc);
|
||||
ldp.append("\\endlastfoot").nl();
|
||||
}
|
||||
else if (hasRowType(RowType.LAST_FOOT)) {
|
||||
// Otherwise we only need it if the table contains a last foot
|
||||
handleRows(ldp,oc,RowType.LAST_FOOT,false,true);
|
||||
ldp.nl().append("\\endlastfoot").nl();
|
||||
}
|
||||
|
||||
// Body
|
||||
handleRows(ldp,oc,RowType.BODY,!hasRowType(RowType.HEAD) && !hasRowType(RowType.FIRST_HEAD),true);
|
||||
|
||||
ldp.nl().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();
|
||||
handleRows(ldp,oc,RowType.HEAD,true,true);
|
||||
ldp.nl();
|
||||
handleRows(ldp,oc,RowType.BODY,!hasRowType(RowType.HEAD),true);
|
||||
ldp.append(baTable.getAfter()).nl();
|
||||
|
||||
// Caption below
|
||||
if (caption!=null && !bCaptionAbove) {
|
||||
handleCaption("\\caption",ldp,oc);
|
||||
}
|
||||
|
||||
ldp.nl().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();
|
||||
handleRows(ldp,oc,RowType.HEAD,true,true);
|
||||
ldp.nl();
|
||||
handleRows(ldp,oc,RowType.BODY,!hasRowType(RowType.HEAD),true);
|
||||
ldp.nl().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 handleRows(LaTeXDocumentPortion ldp, Context oc, RowType rowType, boolean bLineBefore, boolean bLineAfter) {
|
||||
int nRowCount = table.getRowCount();
|
||||
int nColCount = table.getColCount();
|
||||
boolean bFirst = true;
|
||||
boolean bProtect = false; // Do we need to protect '['?
|
||||
int nPreviousRow = -1;
|
||||
for (int nRow=0; nRow<nRowCount; nRow++) {
|
||||
if (rowTypes[nRow]==rowType) {
|
||||
// Add interrow material from previous row, if any
|
||||
if (nPreviousRow>-1) {
|
||||
String sInterRowMaterial = formatter.getInterrowMaterial(nPreviousRow+1);
|
||||
ldp.append(sInterRowMaterial).nl();
|
||||
if (sInterRowMaterial.length()>0) { bProtect=false; }
|
||||
}
|
||||
nPreviousRow = nRow;
|
||||
|
||||
// If it's the first row, add top interrow material
|
||||
if (bFirst && bLineBefore) {
|
||||
String sInter = formatter.getInterrowMaterial(nRow);
|
||||
if (sInter.length()>0) { ldp.append(sInter).nl(); }
|
||||
bFirst=false;
|
||||
}
|
||||
// Export columns in this row
|
||||
LaTeXDocumentPortion rowLdp = new LaTeXDocumentPortion(true);
|
||||
Context icRow = (Context) oc.clone();
|
||||
BeforeAfter baRow = new BeforeAfter();
|
||||
formatter.applyRowStyle(nRow,baRow,icRow);
|
||||
if (!baRow.isEmpty()) {
|
||||
rowLdp.append(baRow.getBefore());
|
||||
if (!formatter.isSimple()) { rowLdp.nl(); }
|
||||
}
|
||||
int nCol = 0;
|
||||
while (nCol<nColCount) {
|
||||
Element cell = (Element) table.getCell(nRow,nCol);
|
||||
if (cell!=null) {
|
||||
if (XMLString.TABLE_TABLE_CELL.equals(cell.getNodeName())) {
|
||||
Context icCell = (Context) icRow.clone();
|
||||
BeforeAfter baCell = new BeforeAfter();
|
||||
formatter.applyCellStyle(nRow,nCol,baCell,icCell);
|
||||
rowLdp.append(baCell.getBefore());
|
||||
if (nCol==nColCount-1) { icCell.setInLastTableColumn(true); }
|
||||
palette.getBlockCv().traverseBlockText(cell,rowLdp,icCell);
|
||||
rowLdp.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()) { rowLdp.append(" & "); }
|
||||
else { rowLdp.append(" &").nl(); }
|
||||
}
|
||||
nCol+=nColSpan;
|
||||
}
|
||||
else { // Non-existing cell, ignore (assuming it is a trailing cell)
|
||||
nCol++;
|
||||
}
|
||||
}
|
||||
rowLdp.append("\\\\");
|
||||
// We have to translate the row to a string to avoid extra newlines and to see the first characters
|
||||
String sRowLdp = rowLdp.toString();
|
||||
// Protect leading [
|
||||
if (bProtect && ((sRowLdp.length()>0 && sRowLdp.charAt(0)=='[') || sRowLdp.startsWith("\n["))) {
|
||||
ldp.append("{}");
|
||||
}
|
||||
ldp.append(sRowLdp);
|
||||
bProtect = true;
|
||||
}
|
||||
}
|
||||
// Add interrow material from last row, if required
|
||||
if (nPreviousRow>-1 && bLineAfter) {
|
||||
ldp.append(formatter.getInterrowMaterial(nPreviousRow+1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,473 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* TableFormatter.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-04-15)
|
||||
*
|
||||
*/
|
||||
|
||||
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 (cell!=null && 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);
|
||||
if (cell!=null) {
|
||||
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);
|
||||
}
|
||||
else { // Non-existing cell, treat as empty cell with no borders
|
||||
nCol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
}
|
||||
|
||||
/** 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>
|
||||
* @param ba the <code>BeforeAfter</code> to contain the table code
|
||||
* @param baAlign the <code>BeforeAfter</code> to contain the alignment code, if it's separate
|
||||
* @param bInFloat true if the table should be floating
|
||||
*/
|
||||
public void applyTableStyle(BeforeAfter ba, BeforeAfter baAlign, boolean bInFloat) {
|
||||
// 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()) {
|
||||
if (bInFloat & !bIsSupertabular) {
|
||||
// Inside a float we don't want the extra glue added by the flushleft/center/flushright environment
|
||||
switch (cAlign) {
|
||||
case 'c' : baAlign.add("\\centering\n", ""); break;
|
||||
case 'r' : baAlign.add("\\raggedleft\n", ""); break;
|
||||
case 'l' : baAlign.add("\\raggedright\n", "");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// But outside floats we do want it
|
||||
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{"+Calc.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
|
||||
StringBuilder buf = new StringBuilder();
|
||||
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 = Calc.add(sTotalColumnWidth,sColumnWidth[i]);
|
||||
}
|
||||
sTotalColumnWidth = Calc.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?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="display_hidden_text" 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>
|
||||
<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="} \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=" \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>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?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/>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?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="false" />
|
||||
<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="display_hidden_text" 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>
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
<?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="false" />
|
||||
<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="display_hidden_text" 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>
|
||||
|
||||
<!-- 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>
|
|
@ -1,78 +0,0 @@
|
|||
<?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="display_hidden_text" 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>
|
||||
<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="} \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=" \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>
|
||||
|
|
@ -1,773 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ClassicI18n.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-05-12)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Stack;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
|
||||
import writer2latex.util.CSVList;
|
||||
import writer2latex.latex.LaTeXConfig;
|
||||
import writer2latex.latex.LaTeXDocumentPortion;
|
||||
import writer2latex.latex.ConverterPalette;
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
|
||||
/** This class (and the helpers in the same package) takes care of i18n in
|
||||
* Writer2LaTeX. In classic LaTeX, i18n is a mixture of inputencodings, fontencodings
|
||||
* and babel languages. The class ClassicI18n thus manages these, and in particular
|
||||
* implements a Unicode->LaTeX translation that can handle different
|
||||
* inputencodings and fontencodings.
|
||||
* The translation is table driven, using symbols.xml (embedded in the jar)
|
||||
* Various sections of symbols.xml handles different cases:
|
||||
* <ul>
|
||||
* <li>common symbols in various font encodings such as T1, T2A, LGR etc.</li>
|
||||
* <li>input encodings such as ISO-8859-1 (latin-1), ISO-8859-7 (latin/greek) etc.</li>
|
||||
* <li>additional symbol fonts such as wasysym, dingbats etc.</li>
|
||||
* <li>font-specific symbols, eg. for 8-bit fonts/private use area</li>
|
||||
* </ul>
|
||||
* The class uses the packages inputenc, fontenc, babel, tipa, bbding,
|
||||
* ifsym, pifont, eurosym, amsmath, wasysym, amssymb, amsfonts and textcomp
|
||||
* in various combinations depending on the configuration.
|
||||
*/
|
||||
public class ClassicI18n extends I18n {
|
||||
// **** Static data and methods: Inputencodings ****
|
||||
public static final int ASCII = 0;
|
||||
public static final int LATIN1 = 1; // ISO Latin 1 (ISO-8859-1)
|
||||
public static final int LATIN2 = 2; // ISO Latin 1 (ISO-8859-1)
|
||||
public static final int ISO_8859_7 = 3; // ISO latin/greek
|
||||
public static final int CP1250 = 4; // Microsoft Windows Eastern European
|
||||
public static final int CP1251 = 5; // Microsoft Windows Cyrillic
|
||||
public static final int KOI8_R = 6; // Latin/russian
|
||||
public static final int UTF8 = 7; // UTF-8
|
||||
|
||||
// Read an inputencoding from a string
|
||||
public static final int readInputenc(String sInputenc) {
|
||||
if ("ascii".equals(sInputenc)) return ASCII;
|
||||
else if ("latin1".equals(sInputenc)) return LATIN1;
|
||||
else if ("latin2".equals(sInputenc)) return LATIN2;
|
||||
else if ("iso-8859-7".equals(sInputenc)) return ISO_8859_7;
|
||||
else if ("cp1250".equals(sInputenc)) return CP1250;
|
||||
else if ("cp1251".equals(sInputenc)) return CP1251;
|
||||
else if ("koi8-r".equals(sInputenc)) return KOI8_R;
|
||||
else if ("utf8".equals(sInputenc)) return UTF8;
|
||||
else return ASCII; // unknown = ascii
|
||||
}
|
||||
|
||||
// Return the LaTeX name of an inputencoding
|
||||
public static final String writeInputenc(int nInputenc) {
|
||||
switch (nInputenc) {
|
||||
case ASCII : return "ascii";
|
||||
case LATIN1 : return "latin1";
|
||||
case LATIN2 : return "latin2";
|
||||
case ISO_8859_7 : return "iso-8859-7";
|
||||
case CP1250 : return "cp1250";
|
||||
case CP1251 : return "cp1251";
|
||||
case KOI8_R : return "koi8-r";
|
||||
case UTF8 : return "utf8";
|
||||
default : return "???";
|
||||
}
|
||||
}
|
||||
|
||||
// Return the java i18n name of an inputencoding
|
||||
public static final String writeJavaEncoding(int nInputenc) {
|
||||
switch (nInputenc) {
|
||||
case ASCII : return "ASCII";
|
||||
case LATIN1 : return "ISO8859_1";
|
||||
case LATIN2 : return "ISO8859_2";
|
||||
case ISO_8859_7 : return "ISO8859_7";
|
||||
case CP1250 : return "Cp1250";
|
||||
case CP1251 : return "Cp1251";
|
||||
case KOI8_R : return "KOI8_R";
|
||||
case UTF8 : return "UTF-8";
|
||||
default : return "???";
|
||||
}
|
||||
}
|
||||
|
||||
// **** Static data and methods: Fontencodings ****
|
||||
private static final int T1_ENC = 1;
|
||||
private static final int T2A_ENC = 2;
|
||||
private static final int T3_ENC = 4;
|
||||
private static final int LGR_ENC = 8;
|
||||
private static final int ANY_ENC = 15;
|
||||
|
||||
// read set of font encodings from a string
|
||||
public static final int readFontencs(String sFontencs) {
|
||||
sFontencs = sFontencs.toUpperCase();
|
||||
if ("ANY".equals(sFontencs)) return ANY_ENC;
|
||||
int nFontencs = 0;
|
||||
if (sFontencs.indexOf("T1")>=0) nFontencs+=T1_ENC;
|
||||
if (sFontencs.indexOf("T2A")>=0) nFontencs+=T2A_ENC;
|
||||
if (sFontencs.indexOf("T3")>=0) nFontencs+=T3_ENC;
|
||||
if (sFontencs.indexOf("LGR")>=0) nFontencs+=LGR_ENC;
|
||||
return nFontencs;
|
||||
}
|
||||
|
||||
// return string representation of a single font encoding
|
||||
/*private static final String writeFontenc(int nFontenc) {
|
||||
switch (nFontenc) {
|
||||
case T1_ENC: return "T1";
|
||||
case T2A_ENC: return "T2A";
|
||||
case T3_ENC: return "T3";
|
||||
case LGR_ENC: return "LGR";
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
|
||||
// check that a given set of font encodings contains a specific font encoding
|
||||
private static final boolean supportsFontenc(int nFontencs, int nFontenc) {
|
||||
return (nFontencs & nFontenc) != 0;
|
||||
}
|
||||
|
||||
// get one fontencoding from a set of fontencodings
|
||||
private static final int getFontenc(int nFontencs) {
|
||||
if (supportsFontenc(nFontencs,T1_ENC)) return T1_ENC;
|
||||
if (supportsFontenc(nFontencs,T2A_ENC)) return T2A_ENC;
|
||||
if (supportsFontenc(nFontencs,T3_ENC)) return T3_ENC;
|
||||
if (supportsFontenc(nFontencs,LGR_ENC)) return LGR_ENC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the font encoding for a specific iso language
|
||||
private static final int getFontenc(String sLang) {
|
||||
// Greek uses "local greek" encoding
|
||||
if ("el".equals(sLang)) return LGR_ENC;
|
||||
// Russian, ukrainian, bulgarian and serbian uses T2A encoding
|
||||
else if ("ru".equals(sLang)) return T2A_ENC;
|
||||
else if ("uk".equals(sLang)) return T2A_ENC;
|
||||
else if ("bg".equals(sLang)) return T2A_ENC;
|
||||
else if ("sr".equals(sLang)) return T2A_ENC;
|
||||
// Other languages uses T1 encoding
|
||||
else return T1_ENC;
|
||||
}
|
||||
|
||||
// return cs for a fontencoding
|
||||
private static final String getFontencCs(int nFontenc) {
|
||||
switch (nFontenc) {
|
||||
case T1_ENC: return "\\textlatin"; // requires babel
|
||||
case T2A_ENC: return "\\textcyrillic"; // requires babel with russian, bulgarian or ukrainian option
|
||||
case T3_ENC: return "\\textipa"; // requires tipa.sty
|
||||
case LGR_ENC: return "\\textgreek"; // requires babel with greek option
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Hashtable<String,String> babelLanguages; // mappings iso->babel language
|
||||
|
||||
static {
|
||||
babelLanguages = new Hashtable<String,String>();
|
||||
babelLanguages.put("en", "english"); // latin1
|
||||
babelLanguages.put("bg", "bulgarian"); // cp1251?
|
||||
babelLanguages.put("cs", "czech"); // latin2
|
||||
babelLanguages.put("da", "danish"); // latin1
|
||||
babelLanguages.put("de", "ngerman"); // latin1
|
||||
babelLanguages.put("el", "greek"); // iso-8859-7
|
||||
babelLanguages.put("es", "spanish"); // latin1
|
||||
babelLanguages.put("fi", "finnish"); // latin1 (latin9?)
|
||||
babelLanguages.put("fr", "french"); // latin1 (latin9?)
|
||||
babelLanguages.put("ga", "irish"); // latin1
|
||||
babelLanguages.put("hr", "croatian"); // latin2
|
||||
babelLanguages.put("hu", "magyar"); // latin2
|
||||
babelLanguages.put("la", "latin"); // ascii
|
||||
babelLanguages.put("is", "icelandic"); // latin1
|
||||
babelLanguages.put("it", "italian"); // latin1
|
||||
babelLanguages.put("nl", "dutch"); // latin1
|
||||
babelLanguages.put("nb", "norsk"); // latin1
|
||||
babelLanguages.put("nn", "nynorsk"); // latin1
|
||||
babelLanguages.put("pl", "polish"); // latin2
|
||||
babelLanguages.put("pt", "portuges"); // latin1
|
||||
babelLanguages.put("ro", "romanian"); // latin2
|
||||
babelLanguages.put("ru", "russian"); // cp1251?
|
||||
babelLanguages.put("sk", "slovak"); // latin2
|
||||
babelLanguages.put("sl", "slovene"); // latin2
|
||||
babelLanguages.put("sr", "serbian"); // cp1251?
|
||||
babelLanguages.put("sv", "swedish"); // latin1
|
||||
babelLanguages.put("tr", "turkish");
|
||||
babelLanguages.put("uk", "ukrainian"); // cp1251?
|
||||
}
|
||||
|
||||
// End of static part of I18n!
|
||||
|
||||
// **** Global variables ****
|
||||
|
||||
// Unicode translation
|
||||
private Hashtable<String,UnicodeTable> tableSet; // all tables
|
||||
private UnicodeTable table; // currently active table (top of stack)
|
||||
private Stack<UnicodeTable> tableStack; // stack of active tables
|
||||
private UnicodeStringParser ucparser; // Unicode string parser
|
||||
|
||||
// Collected data
|
||||
private int nDefaultFontenc; // Fontenc for the default language
|
||||
private boolean bT2A = false; // Do we use cyrillic letters?
|
||||
private boolean bGreek = false; // Do we use greek letters?
|
||||
private boolean bPolytonicGreek = false; // Do we use polytonic greek letters?
|
||||
|
||||
// **** Constructors ****
|
||||
|
||||
/** Construct a new ClassicI18n as ConverterHelper
|
||||
* @param ofr the OfficeReader to get language information from
|
||||
* @param config the configuration which determines the symbols to use
|
||||
* @param palette the ConverterPalette (unused)
|
||||
*/
|
||||
public ClassicI18n(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
// We don't need the palette and the office reader is only used to
|
||||
// identify the default language
|
||||
|
||||
nDefaultFontenc = getFontenc(sDefaultLanguage);
|
||||
|
||||
// Unicode stuff
|
||||
ucparser = new UnicodeStringParser();
|
||||
|
||||
String sSymbols="ascii"; // always load common symbols
|
||||
if (config.getInputencoding()!=ASCII) {
|
||||
sSymbols+="|"+writeInputenc(config.getInputencoding());
|
||||
}
|
||||
|
||||
if (config.useWasysym()) sSymbols+="|wasysym";
|
||||
if (config.useBbding()) sSymbols+="|bbding";
|
||||
if (config.useIfsym()) sSymbols+="|ifsym";
|
||||
if (config.usePifont()) sSymbols+="|dingbats";
|
||||
if (config.useEurosym()) sSymbols+="|eurosym";
|
||||
if (config.useTipa()) sSymbols+="|tipa";
|
||||
|
||||
tableSet = new Hashtable<String,UnicodeTable>();
|
||||
UnicodeTableHandler handler=new UnicodeTableHandler(tableSet, sSymbols);
|
||||
SAXParserFactory factory=SAXParserFactory.newInstance();
|
||||
InputStream is = this.getClass().getResourceAsStream("symbols.xml");
|
||||
try {
|
||||
SAXParser saxParser=factory.newSAXParser();
|
||||
saxParser.parse(is,handler);
|
||||
}
|
||||
catch (Throwable t){
|
||||
System.err.println("Oops - Unable to read symbols.xml");
|
||||
t.printStackTrace();
|
||||
}
|
||||
// put root table at top of stack
|
||||
tableStack = new Stack<UnicodeTable>();
|
||||
tableStack.push(tableSet.get("root"));
|
||||
table = tableSet.get("root");
|
||||
}
|
||||
|
||||
/** Construct a new I18n for general use
|
||||
* @param config the configuration which determines the symbols to use
|
||||
*/
|
||||
public ClassicI18n(LaTeXConfig config) {
|
||||
this (null, config, null);
|
||||
}
|
||||
|
||||
/** Add declarations to the preamble to load the required packages
|
||||
* @param pack usepackage declarations
|
||||
* @param decl other declarations
|
||||
*/
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
useInputenc(pack);
|
||||
useSymbolFonts(pack);
|
||||
useTextFonts(pack);
|
||||
useBabel(pack);
|
||||
}
|
||||
|
||||
private void useInputenc(LaTeXDocumentPortion ldp) {
|
||||
ldp.append("\\usepackage[")
|
||||
.append(writeInputenc(config.getInputencoding()))
|
||||
.append("]{inputenc}").nl();
|
||||
}
|
||||
|
||||
private void useBabel(LaTeXDocumentPortion ldp) {
|
||||
// If the document contains "anonymous" greek letters we need greek in any case
|
||||
// If the document contains "anonymous cyrillic letters we need one of the
|
||||
// languages russian, ukrainian or bulgarian
|
||||
if (greek() && !languages.contains("el")) languages.add("el");
|
||||
if (cyrillic() && !(languages.contains("ru") || languages.contains("uk") || languages.contains("bg"))) {
|
||||
languages.add("ru");
|
||||
}
|
||||
|
||||
// Load babel with the used languages
|
||||
CSVList babelopt = new CSVList(",");
|
||||
Iterator<String> langiter = languages.iterator();
|
||||
while (langiter.hasNext()) {
|
||||
String sLang = langiter.next();
|
||||
if (!sLang.equals(sDefaultLanguage)) {
|
||||
if ("el".equals(sLang) && this.polytonicGreek()) {
|
||||
babelopt.addValue("polutonikogreek");
|
||||
}
|
||||
else {
|
||||
String sBabelLang = getBabelLanguage(sLang);
|
||||
if (sBabelLang!=null) {
|
||||
babelopt.addValue(sBabelLang);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The default language must be the last one
|
||||
if (sDefaultLanguage!=null) {
|
||||
if ("el".equals(sDefaultLanguage) && this.polytonicGreek()) {
|
||||
babelopt.addValue("polutonikogreek");
|
||||
}
|
||||
else {
|
||||
String sBabelLang = getBabelLanguage(sDefaultLanguage);
|
||||
if (sBabelLang!=null) {
|
||||
babelopt.addValue(sBabelLang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!babelopt.isEmpty()) {
|
||||
ldp.append("\\usepackage[")
|
||||
.append(babelopt.toString())
|
||||
.append("]{babel}").nl();
|
||||
// For Polish we must undefine \lll which is later defined by ams
|
||||
if (languages.contains("pl")) {
|
||||
ldp.append("\\let\\lll\\undefined").nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void useSymbolFonts(LaTeXDocumentPortion ldp) {
|
||||
if (config.useTipa()) {
|
||||
ldp.append("\\usepackage[noenc]{tipa}").nl()
|
||||
.append("\\usepackage{tipx}").nl();
|
||||
}
|
||||
|
||||
// Has to avoid some nameclashes
|
||||
if (config.useBbding()) {
|
||||
ldp.append("\\usepackage{bbding}").nl()
|
||||
.append("\\let\\bbCross\\Cross\\let\\Cross\\undefined").nl()
|
||||
.append("\\let\\bbSquare\\Square\\let\\Square\\undefined").nl()
|
||||
.append("\\let\\bbTrianbleUp\\TriangleUp\\let\\TriangleUp\\undefined").nl()
|
||||
.append("\\let\\bbTrianlgeDown\\TriangleDown\\let\\TriangleDown\\undefined").nl();
|
||||
}
|
||||
|
||||
if (config.useIfsym()) {
|
||||
ldp.append("\\usepackage[geometry,weather,misc,clock]{ifsym}").nl();
|
||||
}
|
||||
|
||||
if (config.usePifont()) { ldp.append("\\usepackage{pifont}").nl(); }
|
||||
|
||||
if (config.useEurosym()) { ldp.append("\\usepackage{eurosym}").nl(); }
|
||||
|
||||
// Always use amsmath
|
||||
ldp.append("\\usepackage{amsmath}").nl();
|
||||
|
||||
// wasysym *must* be loaded between amsmath and amsfonts!
|
||||
if (config.useWasysym()) {
|
||||
ldp.append("\\usepackage{wasysym}").nl();
|
||||
}
|
||||
|
||||
// Always use amssymb, amsfonts, textcomp (always!)
|
||||
ldp.append("\\usepackage{amssymb,amsfonts,textcomp}").nl();
|
||||
}
|
||||
|
||||
private void useTextFonts(LaTeXDocumentPortion ldp) {
|
||||
// usepackage fontenc
|
||||
CSVList fontencs = new CSVList(',');
|
||||
if (bT2A) { fontencs.addValue("T2A"); }
|
||||
if (bGreek) { fontencs.addValue("LGR"); }
|
||||
if (config.useTipa()) { fontencs.addValue("T3"); }
|
||||
fontencs.addValue("T1");
|
||||
ldp.append("\\usepackage[").append(fontencs.toString())
|
||||
.append("]{fontenc}").nl();
|
||||
|
||||
// use font package(s)
|
||||
useFontPackages(ldp);
|
||||
}
|
||||
|
||||
private void useFontPackages(LaTeXDocumentPortion ldp) {
|
||||
String sFont = config.getFont();
|
||||
// Sources:
|
||||
// A Survey of Free Math Fonts for TeX and LaTeX, Stephen G. Hartke 2006
|
||||
if ("cmbright".equals(sFont)) { // Computer Modern Bright designed by Walter A. Schmidt
|
||||
ldp.append("\\usepackage{cmbright}").nl();
|
||||
}
|
||||
else if ("ccfonts".equals(sFont)) { // Concrete designed by Donald E. Knuth
|
||||
ldp.append("\\usepackage{ccfonts}").nl();
|
||||
}
|
||||
else if ("ccfonts-euler".equals(sFont)) { // Concrete with Euler math fonts
|
||||
ldp.append("\\usepackage{ccfonts,eulervm}").nl();
|
||||
}
|
||||
else if ("iwona".equals(sFont)) { // Iwona
|
||||
ldp.append("\\usepackage[math]{iwona}").nl();
|
||||
}
|
||||
else if ("kurier".equals(sFont)) { // Kurier
|
||||
ldp.append("\\usepackage[math]{kurier}").nl();
|
||||
}
|
||||
else if ("anttor".equals(sFont)) { // Antykwa Torunska
|
||||
ldp.append("\\usepackage[math]{anttor}").nl();
|
||||
}
|
||||
else if ("kmath-kerkis".equals(sFont)) { // Kerkis
|
||||
ldp.append("\\usepackage{kmath,kerkis}");
|
||||
}
|
||||
else if ("fouriernc".equals(sFont)) { // New Century Schoolbook + Fourier
|
||||
ldp.append("\\usepackage{fouriernc}");
|
||||
}
|
||||
else if ("pxfonts".equals(sFont)) { // Palatino + pxfonts math
|
||||
ldp.append("\\usepackage{pxfonts}");
|
||||
}
|
||||
else if ("mathpazo".equals(sFont)) { // Palatino + Pazo math
|
||||
ldp.append("\\usepackage{mathpazo}");
|
||||
}
|
||||
else if ("mathpple".equals(sFont)) { // Palatino + Euler
|
||||
ldp.append("\\usepackage{mathpple}");
|
||||
}
|
||||
else if ("txfonts".equals(sFont)) { // Times + txfonts math
|
||||
ldp.append("\\usepackage[varg]{txfonts}");
|
||||
}
|
||||
else if ("mathptmx".equals(sFont)) { // Times + Symbol
|
||||
ldp.append("\\usepackage{mathptmx}");
|
||||
}
|
||||
else if ("arev".equals(sFont)) { // Arev Sans + Arev math
|
||||
ldp.append("\\usepackage{arev}");
|
||||
}
|
||||
else if ("charter-mathdesign".equals(sFont)) { // Bitstream Charter + Math Design
|
||||
ldp.append("\\usepackage[charter]{mathdesign}");
|
||||
}
|
||||
else if ("utopia-mathdesign".equals(sFont)) { // Utopia + Math Design
|
||||
ldp.append("\\usepackage[utopia]{mathdesign}");
|
||||
}
|
||||
else if ("fourier".equals(sFont)) { // Utopia + Fourier
|
||||
ldp.append("\\usepackage{fourier}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Apply a language language
|
||||
* @param style the OOo style to read attributes from
|
||||
* @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 applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba) {
|
||||
if (!bAlwaysUseDefaultLang && style!=null) {
|
||||
String sISOLang = style.getProperty(XMLString.FO_LANGUAGE,bInherit);
|
||||
if (sISOLang!=null) {
|
||||
languages.add(sISOLang);
|
||||
String sLang = getBabelLanguage(sISOLang);
|
||||
if (sLang!=null) {
|
||||
if (bDecl) {
|
||||
ba.add("\\selectlanguage{"+sLang+"}","");
|
||||
//ba.add("\\begin{otherlanguage}{"+sLang+"}","\\end{otherlanguage}");
|
||||
}
|
||||
else {
|
||||
ba.add("\\foreignlanguage{"+sLang+"}{","}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Push a font to the font stack
|
||||
* @param sName the name of the font
|
||||
*/
|
||||
public void pushSpecialTable(String sName) {
|
||||
// If no name is specified we should keep the current table
|
||||
// Otherwise try to find the table, and use root if it's not available
|
||||
if (sName!=null) {
|
||||
table = tableSet.get(sName);
|
||||
if (table==null) { table = tableSet.get("root"); }
|
||||
}
|
||||
tableStack.push(table);
|
||||
}
|
||||
|
||||
/** Pop a font from the font stack
|
||||
*/
|
||||
public void popSpecialTable() {
|
||||
tableStack.pop();
|
||||
table = tableStack.peek();
|
||||
}
|
||||
|
||||
/** Get the number of characters defined in the current table
|
||||
* (for informational purposes only)
|
||||
* @return the number of characters
|
||||
*/
|
||||
public int getCharCount() { return table.getCharCount(); }
|
||||
|
||||
/** Convert a string of characters into LaTeX
|
||||
* @param s the source string
|
||||
* @param bMathMode true if the string should be rendered in math mode
|
||||
* @param sLang the iso language of the string
|
||||
* @return the LaTeX string
|
||||
*/
|
||||
public String convert(String s, boolean bMathMode, String sLang){
|
||||
if (!bAlwaysUseDefaultLang && sLang!=null) { languages.add(sLang); }
|
||||
StringBuilder buf=new StringBuilder();
|
||||
int nFontenc = bAlwaysUseDefaultLang ? nDefaultFontenc : getFontenc(sLang);
|
||||
int nLen = s.length();
|
||||
int i = 0;
|
||||
int nStart = i;
|
||||
while (i<nLen) {
|
||||
ReplacementTrieNode node = stringReplace.get(s,i,nLen);
|
||||
if (node!=null) {
|
||||
if (i>nStart) {
|
||||
convert(s,nStart,i,bMathMode,sLang,buf,nFontenc);
|
||||
}
|
||||
boolean bOtherFontenc = !supportsFontenc(node.getFontencs(),nFontenc);
|
||||
if (bOtherFontenc) {
|
||||
buf.append(getFontencCs(getFontenc(node.getFontencs()))).append("{");
|
||||
}
|
||||
buf.append(node.getLaTeXCode());
|
||||
if (bOtherFontenc) {
|
||||
buf.append("}");
|
||||
}
|
||||
i += node.getInputLength();
|
||||
nStart = i;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (nStart<nLen) {
|
||||
convert(s,nStart,nLen,bMathMode,sLang,buf,nFontenc);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void convert(String s, int nStart, int nEnd, boolean bMathMode, String sLang, StringBuilder buf, int nFontenc) {
|
||||
int nCurFontenc = nFontenc;
|
||||
ucparser.reset(table,s,nStart,nEnd);
|
||||
boolean bIsFirst = true; // Protect all dangerous characters at the start
|
||||
char cProtect = '\u0000'; // Current character to protect
|
||||
boolean bTempMathMode = false;
|
||||
while (ucparser.next()) {
|
||||
char c = ucparser.getChar();
|
||||
if (bMathMode) {
|
||||
buf.append(convertMathChar(c,nFontenc));
|
||||
}
|
||||
else if (greekMath(c,nFontenc) || (table.hasMathChar(c) && !table.hasTextChar(c))) {
|
||||
if (!bTempMathMode) { // switch to math mode
|
||||
buf.append("$");
|
||||
bTempMathMode = true;
|
||||
}
|
||||
buf.append(convertMathChar(c,nFontenc));
|
||||
cProtect = '\u0000';
|
||||
}
|
||||
else if (table.hasTextChar(c)) {
|
||||
if (bTempMathMode) { // switch to text mode
|
||||
buf.append("$");
|
||||
bTempMathMode = false;
|
||||
}
|
||||
int nFontencs = table.getFontencs(c);
|
||||
if (supportsFontenc(nFontencs,nCurFontenc)) {
|
||||
// The text character is valid in the current font encoding
|
||||
// Note: Change of font encoding is greedy - change?
|
||||
|
||||
// Prevent unwanted ligatures (-, ', `)
|
||||
char cProtectThis = table.getProtectChar(c);
|
||||
if (cProtectThis!='\u0000' && (cProtectThis==cProtect || bIsFirst)) {
|
||||
buf.append("{}");
|
||||
}
|
||||
cProtect = cProtectThis;
|
||||
|
||||
setFlags(c,nCurFontenc);
|
||||
if (ucparser.hasCombiningChar()) {
|
||||
char cc = ucparser.getCombiningChar();
|
||||
if (supportsFontenc(table.getFontencs(cc),nCurFontenc)) {
|
||||
buf.append(table.getTextChar(cc)).append("{")
|
||||
.append(table.getTextChar(c)).append("}");
|
||||
}
|
||||
else { // ignore combining char if not valid in this font encoding
|
||||
buf.append(table.getTextChar(c));
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append(table.getTextChar(c));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The text character is valid in another font encoding
|
||||
|
||||
cProtect = table.getProtectChar(c);
|
||||
|
||||
int nFontenc1 = getFontenc(nFontencs);
|
||||
setFlags(c,nFontenc1);
|
||||
if (nCurFontenc!=nFontenc) { // end "other font encoding"
|
||||
buf.append("}");
|
||||
}
|
||||
if (nFontenc1!=nFontenc) { // start "other font encoding"
|
||||
buf.append(getFontencCs(nFontenc1)).append("{");
|
||||
}
|
||||
|
||||
if (ucparser.hasCombiningChar()) {
|
||||
char cc = ucparser.getCombiningChar();
|
||||
if (supportsFontenc(table.getFontencs(cc),nCurFontenc)) {
|
||||
buf.append(table.getTextChar(cc)).append("{")
|
||||
.append(table.getTextChar(c)).append("}");
|
||||
}
|
||||
else { // ignore combining char if not valid in this font encoding
|
||||
buf.append(table.getTextChar(c));
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append(table.getTextChar(c));
|
||||
}
|
||||
nCurFontenc = nFontenc1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append(notFound(c,nCurFontenc));
|
||||
}
|
||||
|
||||
bIsFirst = false;
|
||||
}
|
||||
|
||||
if (bTempMathMode) { // turn of math mode
|
||||
buf.append("$");
|
||||
}
|
||||
|
||||
if (nCurFontenc!=nFontenc) { // end unfinished "other font encoding"
|
||||
buf.append("}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// convert a single math character
|
||||
private String convertMathChar(char c, int nFontenc) {
|
||||
if (table.hasMathChar(c)) {
|
||||
return table.getMathChar(c);
|
||||
}
|
||||
else if (table.hasTextChar(c)) { // use text mode as a fallback
|
||||
int nFontencs = table.getFontencs(c);
|
||||
if (supportsFontenc(nFontencs,nFontenc)) {
|
||||
// The text character is valid in the current font encoding
|
||||
setFlags(c,nFontenc);
|
||||
if (table.getCharType(c)==UnicodeCharacter.COMBINING) {
|
||||
return "\\text{" + table.getTextChar(c) +"{}}";
|
||||
}
|
||||
else {
|
||||
return "\\text{" + table.getTextChar(c) +"}";
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The text character is valid in another font encoding
|
||||
int nFontenc1 = getFontenc(nFontencs);
|
||||
setFlags(c,nFontenc1);
|
||||
if (table.getCharType(c)==UnicodeCharacter.COMBINING) {
|
||||
return "\\text{" + getFontencCs(nFontenc1) + "{" + table.getTextChar(c) +"{}}}";
|
||||
}
|
||||
else {
|
||||
return "\\text{" + getFontencCs(nFontenc1) + "{" + table.getTextChar(c) +"}}";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "\\text{" + notFound(c,nFontenc) + "}";
|
||||
}
|
||||
}
|
||||
|
||||
// Missing symbol
|
||||
private String notFound(char c,int nFontenc) {
|
||||
//String sErrorMsg = "[Warning: Missing symbol " + Integer.toHexString(c).toUpperCase() +"]";
|
||||
String sErrorMsg = "["+Integer.toHexString(c).toUpperCase() +"?]";
|
||||
if (nFontenc==T1_ENC) return sErrorMsg;
|
||||
else return "\\textlatin{"+sErrorMsg+"}";
|
||||
}
|
||||
|
||||
|
||||
// Convert a single character
|
||||
/*private String convert(char c, boolean bMathMode, String sLang){
|
||||
int nFontenc = bAlwaysUseDefaultLang ? nDefaultFontenc : getFontenc(sLang);
|
||||
if (bMathMode) {
|
||||
return convertMathChar(c,nFontenc);
|
||||
}
|
||||
else if (greekMath(c,nFontenc) || (table.hasMathChar(c) && !table.hasTextChar(c))) {
|
||||
return "$" + convertMathChar(c,nFontenc) + "$";
|
||||
}
|
||||
else if (table.hasTextChar(c)) {
|
||||
int nFontencs = table.getFontencs(c);
|
||||
if (supportsFontenc(nFontencs,nFontenc)) {
|
||||
// The text character is valid in the current font encoding
|
||||
setFlags(c,nFontenc);
|
||||
if (table.getCharType(c)==UnicodeCharacter.COMBINING) {
|
||||
return table.getTextChar(c)+"{}";
|
||||
}
|
||||
else {
|
||||
return table.getTextChar(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The text character is valid in another font encoding
|
||||
int nFontenc1 = getFontenc(nFontencs);
|
||||
setFlags(c,nFontenc1);
|
||||
if (table.getCharType(c)==UnicodeCharacter.COMBINING) {
|
||||
return getFontencCs(nFontenc1) + "{" + table.getTextChar(c) +"{}}";
|
||||
}
|
||||
else {
|
||||
return getFontencCs(nFontenc1) + "{" + table.getTextChar(c) +"}";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return notFound(c,nFontenc);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
// **** Languages ****
|
||||
|
||||
// Convert iso language to babel language
|
||||
// todo: include iso country
|
||||
// todo: support automatic choice of inputenc (see comments)?
|
||||
private String getBabelLanguage(String sLang) {
|
||||
if (babelLanguages.containsKey(sLang)) {
|
||||
return babelLanguages.get(sLang);
|
||||
}
|
||||
else {
|
||||
return null; // Unknown language
|
||||
}
|
||||
}
|
||||
|
||||
// **** Helpers to collect various information ****
|
||||
|
||||
// Did we use cyrillic?
|
||||
private boolean cyrillic() { return bT2A; }
|
||||
|
||||
// Did we use greek?
|
||||
private boolean greek() { return bGreek; }
|
||||
|
||||
// Did we use polytonic greek?
|
||||
private boolean polytonicGreek() { return bPolytonicGreek; }
|
||||
|
||||
// Outside greek text, greek letters may be rendered in math mode,
|
||||
// if the user requires that in the configuration.
|
||||
private boolean greekMath(char c, int nFontenc) {
|
||||
return bGreekMath && nFontenc!=LGR_ENC && table.getFontencs(c)==LGR_ENC;
|
||||
}
|
||||
|
||||
// Set cyrillic and greek flags
|
||||
private void setFlags(char c, int nFontenc) {
|
||||
if ((c>='\u1F00') && (c<='\u1FFF')) bPolytonicGreek = true;
|
||||
if (nFontenc==LGR_ENC) bGreek = true;
|
||||
if (nFontenc==T2A_ENC) bT2A = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* I18n.java
|
||||
*
|
||||
* Copyright: 2002-2011 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2011-05-09)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import writer2latex.office.*;
|
||||
import writer2latex.latex.LaTeXConfig;
|
||||
import writer2latex.latex.LaTeXDocumentPortion;
|
||||
import writer2latex.latex.ConverterPalette;
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
|
||||
/** This abstract class takes care of i18n in the LaTeX export.
|
||||
* Since i18n is handled quite differently in LaTeX "Classic"
|
||||
* and XeTeX, we use two different classes
|
||||
*/
|
||||
public abstract class I18n {
|
||||
// **** Global variables ****
|
||||
|
||||
// The office reader
|
||||
protected OfficeReader ofr;
|
||||
|
||||
// Configuration items
|
||||
protected LaTeXConfig config;
|
||||
protected ReplacementTrie stringReplace;
|
||||
protected boolean bGreekMath; // Use math mode for Greek letters
|
||||
protected boolean bAlwaysUseDefaultLang; // Ignore sLang parameter to convert()
|
||||
|
||||
// Collected data
|
||||
protected String sDefaultCTLLanguage; // The default CTL ISO language to use
|
||||
protected String sDefaultCTLCountry; // The default CTL ISO country to use
|
||||
protected String sDefaultLanguage; // The default LCG ISO language to use
|
||||
protected String sDefaultCountry; // The default LCG ISO country to use
|
||||
protected HashSet<String> languages = new HashSet<String>(); // All LCG languages used
|
||||
|
||||
// **** Constructors ****
|
||||
|
||||
/** Construct a new I18n as ConverterHelper
|
||||
* @param ofr the OfficeReader to get language information from
|
||||
* @param config the configuration which determines the symbols to use
|
||||
* @param palette the ConverterPalette (unused)
|
||||
*/
|
||||
public I18n(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
// We don't need the palette
|
||||
this.ofr = ofr;
|
||||
|
||||
// Set up config items
|
||||
this.config = config;
|
||||
stringReplace = config.getStringReplace();
|
||||
bGreekMath = config.greekMath();
|
||||
bAlwaysUseDefaultLang = !config.multilingual();
|
||||
|
||||
// Default language
|
||||
if (ofr!=null) {
|
||||
if (config.multilingual()) {
|
||||
// Read the default language from the default paragraph style
|
||||
StyleWithProperties style = ofr.getDefaultParStyle();
|
||||
if (style!=null) {
|
||||
sDefaultLanguage = style.getProperty(XMLString.FO_LANGUAGE);
|
||||
sDefaultCountry = style.getProperty(XMLString.FO_COUNTRY);
|
||||
sDefaultCTLLanguage = style.getProperty(XMLString.STYLE_LANGUAGE_COMPLEX);
|
||||
sDefaultCTLCountry = style.getProperty(XMLString.STYLE_COUNTRY_COMPLEX);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the most common language is the only language
|
||||
sDefaultLanguage = ofr.getMajorityLanguage();
|
||||
}
|
||||
}
|
||||
if (sDefaultLanguage==null) { sDefaultLanguage="en"; }
|
||||
}
|
||||
|
||||
/** Add declarations to the preamble to load the required packages
|
||||
* @param pack usepackage declarations
|
||||
* @param decl other declarations
|
||||
*/
|
||||
public abstract void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl);
|
||||
|
||||
/** Apply a language language
|
||||
* @param style the OOo style to read attributes from
|
||||
* @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 abstract void applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba);
|
||||
|
||||
/** Push a font to the font stack
|
||||
* @param sName the name of the font
|
||||
*/
|
||||
public abstract void pushSpecialTable(String sName);
|
||||
|
||||
/** Pop a font from the font stack
|
||||
*/
|
||||
public abstract void popSpecialTable();
|
||||
|
||||
/** Convert a string of characters into LaTeX
|
||||
* @param s the source string
|
||||
* @param bMathMode true if the string should be rendered in math mode
|
||||
* @param sLang the ISO language of the string
|
||||
* @return the LaTeX string
|
||||
*/
|
||||
public abstract String convert(String s, boolean bMathMode, String sLang);
|
||||
|
||||
/** Get the default language (either the document language or the most used language)
|
||||
*
|
||||
* @return the default language
|
||||
*/
|
||||
public String getDefaultLanguage() {
|
||||
return sDefaultLanguage;
|
||||
}
|
||||
|
||||
/** Get the default country
|
||||
*
|
||||
* @return the default country
|
||||
*/
|
||||
public String getDefaultCountry() {
|
||||
return sDefaultCountry;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The package writer2latex.xhtml.i18n</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>This package takes care of i18n for LaTeX.</p>
|
||||
<p>In LaTeX, i18n is a mixture of inputencodings, fontencodings
|
||||
and babel languages. In particualar, the package provides a Unicode->LaTeX
|
||||
translation that can handle different inputencodings and fontencodings.</p>
|
||||
<p>The pacakge could (with modification) in theory be used in other programs
|
||||
that convert unicode to LaTeX.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,216 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* XeTeXI18n.java
|
||||
*
|
||||
* Copyright: 2002-2010 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2010-12-15)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Polyglossia {
|
||||
private static Map<String,String> languageMap;
|
||||
private static Map<String,String> variantMap;
|
||||
|
||||
static {
|
||||
languageMap = new HashMap<String,String>();
|
||||
languageMap.put("am", "amharic");
|
||||
languageMap.put("ar", "arabic");
|
||||
languageMap.put("ast", "asturian");
|
||||
languageMap.put("bg", "bulgarian");
|
||||
languageMap.put("bn", "bengali");
|
||||
languageMap.put("br", "breton");
|
||||
languageMap.put("ca", "catalan");
|
||||
languageMap.put("cop", "coptic");
|
||||
languageMap.put("cs", "czech");
|
||||
languageMap.put("cy", "welsh");
|
||||
languageMap.put("da", "danish");
|
||||
languageMap.put("de", "german");
|
||||
languageMap.put("dsb", "lsorbian");
|
||||
languageMap.put("dv", "divehi");
|
||||
languageMap.put("el", "greek");
|
||||
languageMap.put("en", "english");
|
||||
languageMap.put("eo", "esperanto");
|
||||
languageMap.put("es", "spanish");
|
||||
languageMap.put("et", "estonian");
|
||||
languageMap.put("eu", "basque");
|
||||
languageMap.put("fa", "farsi");
|
||||
languageMap.put("fi", "finnish");
|
||||
languageMap.put("fr", "french");
|
||||
languageMap.put("ga", "irish");
|
||||
languageMap.put("gd", "scottish");
|
||||
languageMap.put("gl", "galician");
|
||||
languageMap.put("grc", "greek");
|
||||
languageMap.put("he", "hebrew");
|
||||
languageMap.put("hi", "hindi");
|
||||
languageMap.put("hr", "croatian");
|
||||
languageMap.put("hsb", "usorbian");
|
||||
languageMap.put("hu", "magyar");
|
||||
languageMap.put("hy", "armenian");
|
||||
languageMap.put("id", "bahasai"); // Bahasa Indonesia
|
||||
languageMap.put("ie", "interlingua");
|
||||
languageMap.put("is", "icelandic");
|
||||
languageMap.put("it", "italian");
|
||||
languageMap.put("la", "latin");
|
||||
languageMap.put("lo", "lao");
|
||||
languageMap.put("lt", "lithuanian");
|
||||
languageMap.put("lv", "latvian");
|
||||
languageMap.put("ml", "malayalam");
|
||||
languageMap.put("mr", "marathi");
|
||||
languageMap.put("ms", "bahasam"); // Bahasa Melayu
|
||||
languageMap.put("nb", "norsk");
|
||||
languageMap.put("nl", "dutch");
|
||||
languageMap.put("nn", "nynorsk");
|
||||
languageMap.put("oc", "occitan");
|
||||
languageMap.put("pl", "polish");
|
||||
languageMap.put("pt", "portuges");
|
||||
languageMap.put("pt-BR", "brazilian");
|
||||
languageMap.put("ro", "romanian");
|
||||
languageMap.put("ru", "russian");
|
||||
languageMap.put("sa", "sanskrit");
|
||||
languageMap.put("sk", "slovak");
|
||||
languageMap.put("sl", "slovenian");
|
||||
languageMap.put("sq", "albanian");
|
||||
languageMap.put("sr", "serbian");
|
||||
languageMap.put("sv", "swedish");
|
||||
languageMap.put("syr", "syriac");
|
||||
languageMap.put("ta", "tamil");
|
||||
languageMap.put("te", "telugu");
|
||||
languageMap.put("th", "thai");
|
||||
languageMap.put("tk", "turkmen");
|
||||
languageMap.put("tr", "turkish");
|
||||
languageMap.put("uk", "ukrainian");
|
||||
languageMap.put("ur", "urdu");
|
||||
languageMap.put("vi", "vietnamese");
|
||||
// TODO: Which language is samin?? One guess could be sami with the n for north?
|
||||
//languageMap.put("??", "samin");
|
||||
|
||||
variantMap = new HashMap<String,String>();
|
||||
// English variants
|
||||
variantMap.put("en-US", "american");
|
||||
variantMap.put("en-GB", "british");
|
||||
variantMap.put("en-AU", "australian");
|
||||
variantMap.put("en-NZ", "newzealand");
|
||||
// Greek variants
|
||||
variantMap.put("el", "monotonic");
|
||||
variantMap.put("grc", "ancient"); // Supported in OOo since 3.2
|
||||
}
|
||||
|
||||
private static String getEntry(Map<String,String> map, String sLocale, String sLang) {
|
||||
if (map.containsKey(sLocale)) {
|
||||
return map.get(sLocale);
|
||||
}
|
||||
else if (map.containsKey(sLang)) {
|
||||
return map.get(sLang);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// This ended the static part of Polyglossia
|
||||
|
||||
private Set<String> languages = new HashSet<String>();
|
||||
private List<String> declarations = new ArrayList<String>();
|
||||
private Map<String,String[]> commands = new HashMap<String,String[]>();
|
||||
|
||||
/** <p>Get the declarations for the applied languages, in the form</p>
|
||||
* <p><code>\\usepackage{polyglossia}</code></p>
|
||||
* <p><code>\\setdefaultlanguage{language1}</code></p>
|
||||
* <p><code>\\setotherlanguage{language2}</code></p>
|
||||
* <p><code>\\setotherlanguage{language3}</code></p>
|
||||
* <p><code>...</code></p>
|
||||
*
|
||||
* @return the declarations as a string array
|
||||
*/
|
||||
public String[] getDeclarations() {
|
||||
return declarations.toArray(new String[declarations.size()]);
|
||||
}
|
||||
|
||||
/** <p>Add the given locale to the list of applied locales and return definitions for applying the
|
||||
* language to a text portion:</p>
|
||||
* <ul>
|
||||
* <li>A command of the forn <code>\textlanguage[variant=languagevariant]</code></li>
|
||||
* <li>An environment in the form
|
||||
* <code>\begin{language}[variant=languagevariant]</code>...<code>\end{language}</code></li>
|
||||
* </ul>
|
||||
* <p>The first applied language is the default language</p>
|
||||
*
|
||||
* @param sLang The language
|
||||
* @param sCountry The country (may be null)
|
||||
* @return a string array containing definitions to apply the language: Entry 0 contains a command
|
||||
* and Entry 1 and 2 contains an environment
|
||||
*/
|
||||
public String[] applyLanguage(String sLang, String sCountry) {
|
||||
String sLocale = sCountry!=null ? sLang+"-"+sCountry : sLang;
|
||||
if (commands.containsKey(sLocale)) {
|
||||
return commands.get(sLocale);
|
||||
}
|
||||
else {
|
||||
// Get the Polyglossia language and variant
|
||||
String sPolyLang = getEntry(languageMap,sLocale,sLang);
|
||||
if (sPolyLang!=null) {
|
||||
String sVariant = getEntry(variantMap,sLocale,sLang);
|
||||
if (sVariant!=null) {
|
||||
sVariant = "[variant="+sVariant+"]";
|
||||
}
|
||||
else {
|
||||
sVariant = "";
|
||||
}
|
||||
|
||||
if (languages.size()==0) {
|
||||
// First language, load Polyglossia and make the language default
|
||||
declarations.add("\\usepackage{polyglossia}");
|
||||
declarations.add("\\setdefaultlanguage"+sVariant+"{"+sPolyLang+"}");
|
||||
languages.add(sPolyLang);
|
||||
sVariant = ""; // Do not apply variant directly
|
||||
}
|
||||
else if (!languages.contains(sPolyLang)) {
|
||||
// New language, add to declarations
|
||||
declarations.add("\\setotherlanguage"+sVariant+"{"+sPolyLang+"}");
|
||||
languages.add(sPolyLang);
|
||||
sVariant = ""; // Do not apply variant directly
|
||||
}
|
||||
|
||||
String[] sCommand = new String[3];
|
||||
sCommand[0] = "\\text"+sPolyLang+sVariant;
|
||||
if ("arabic".equals(sPolyLang)) { sPolyLang="Arabic"; }
|
||||
sCommand[1] = "\\begin{"+sPolyLang+"}"+sVariant;
|
||||
sCommand[2] = "\\end{"+sPolyLang+"}";
|
||||
commands.put(sLocale, sCommand);
|
||||
return sCommand;
|
||||
}
|
||||
else {
|
||||
// Unknown language
|
||||
String[] sCommand = new String[3];
|
||||
sCommand[0] = "";
|
||||
sCommand[1] = "";
|
||||
sCommand[2] = "";
|
||||
commands.put(sLocale, sCommand);
|
||||
return sCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ReplacementTrie.java
|
||||
*
|
||||
* Copyright: 2002-2009 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2009-09-20)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** This class contains a trie of string -> LaTeX code replacements
|
||||
*/
|
||||
public class ReplacementTrie extends ReplacementTrieNode {
|
||||
|
||||
public ReplacementTrie() {
|
||||
super('*',0);
|
||||
}
|
||||
|
||||
public ReplacementTrieNode get(String sInput) {
|
||||
return get(sInput,0,sInput.length());
|
||||
}
|
||||
|
||||
public ReplacementTrieNode get(String sInput, int nStart, int nEnd) {
|
||||
if (sInput.length()==0) { return null; }
|
||||
else { return super.get(sInput,nStart,nEnd); }
|
||||
}
|
||||
|
||||
public void put(String sInput, String sLaTeXCode, int nFontencs) {
|
||||
if (sInput.length()==0) { return; }
|
||||
else { super.put(sInput,sLaTeXCode,nFontencs); }
|
||||
}
|
||||
|
||||
public Set<String> getInputStrings() {
|
||||
HashSet<String> strings = new HashSet<String>();
|
||||
collectStrings(strings,"");
|
||||
return strings;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* ReplacementTrieNode.java
|
||||
*
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.4 (2014-09-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/** This class contains a node in a trie of string -> LaTeX code replacements
|
||||
*/
|
||||
public class ReplacementTrieNode {
|
||||
|
||||
private char cLetter;
|
||||
private int nInputLength;
|
||||
private String sLaTeXCode = null;
|
||||
private int nFontencs = 0;
|
||||
private ReplacementTrieNode son = null;
|
||||
private ReplacementTrieNode brother = null;
|
||||
|
||||
public ReplacementTrieNode(char cLetter, int nInputLength) {
|
||||
this.cLetter = cLetter;
|
||||
this.nInputLength = nInputLength;
|
||||
}
|
||||
|
||||
public char getLetter() { return this.cLetter; }
|
||||
|
||||
public int getInputLength() { return this.nInputLength; }
|
||||
|
||||
public String getLaTeXCode() { return this.sLaTeXCode; }
|
||||
|
||||
public int getFontencs() { return this.nFontencs; }
|
||||
|
||||
protected void setLaTeXCode(String sLaTeXCode) {
|
||||
this.sLaTeXCode = sLaTeXCode;
|
||||
}
|
||||
|
||||
protected void setFontencs(int nFontencs) {
|
||||
this.nFontencs = nFontencs;
|
||||
}
|
||||
|
||||
protected ReplacementTrieNode getFirstChild() {
|
||||
return this.son;
|
||||
}
|
||||
|
||||
protected ReplacementTrieNode getNextSibling() {
|
||||
return this.brother;
|
||||
}
|
||||
|
||||
protected ReplacementTrieNode getChildByLetter(char cLetter) {
|
||||
ReplacementTrieNode child = this.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (cLetter==child.getLetter()) { return child; }
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void appendChild(ReplacementTrieNode node) {
|
||||
if (son==null) { son = node; }
|
||||
else { son.appendSibling(node); }
|
||||
}
|
||||
|
||||
protected void appendSibling(ReplacementTrieNode node) {
|
||||
if (brother==null) { brother = node; }
|
||||
else { brother.appendSibling(node); }
|
||||
}
|
||||
|
||||
protected ReplacementTrieNode get(String sInput, int nStart, int nEnd) {
|
||||
if (nStart>=nEnd) { return null; }
|
||||
char c = sInput.charAt(nStart);
|
||||
ReplacementTrieNode child = this.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (child.getLetter()==c) {
|
||||
if (child.getLaTeXCode()!=null) { return child; }
|
||||
else { return child.get(sInput,nStart+1,nEnd); }
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void put(String sInput, String sLaTeXCode, int nFontencs) {
|
||||
char c = sInput.charAt(0);
|
||||
ReplacementTrieNode child = this.getChildByLetter(c);
|
||||
if (child==null) {
|
||||
child = new ReplacementTrieNode(c,this.getInputLength()+1);
|
||||
this.appendChild(child);
|
||||
}
|
||||
if (sInput.length()>1) {
|
||||
child.put(sInput.substring(1),sLaTeXCode,nFontencs);
|
||||
}
|
||||
else {
|
||||
child.setLaTeXCode(sLaTeXCode);
|
||||
child.setFontencs(nFontencs);
|
||||
}
|
||||
}
|
||||
|
||||
protected void collectStrings(Set<String> strings, String sPrefix) {
|
||||
ReplacementTrieNode child = this.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (child.getLaTeXCode()!=null) {
|
||||
strings.add(sPrefix+child.getLetter());
|
||||
}
|
||||
child.collectStrings(strings, sPrefix+child.getLetter());
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String s = Character.toString(cLetter);
|
||||
if (brother!=null) { s+=brother.toString(); }
|
||||
if (son!=null) { s+="\nInputLength "+(nInputLength+1)+", "+son.toString(); }
|
||||
else { s+="\n"; }
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* UnicodeCharacter.java
|
||||
*
|
||||
* Copyright: 2002-2010 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2010-05-11)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
// Helper class: A struct to hold the LaTeX representations of a unicode character
|
||||
class UnicodeCharacter implements Cloneable {
|
||||
final static int NORMAL = 0; // this is a normal character
|
||||
final static int COMBINING = 1; // this character should be ignored
|
||||
final static int IGNORE = 2; // this is a combining character
|
||||
final static int UNKNOWN = 3; // this character is unknown
|
||||
|
||||
int nType; // The type of character
|
||||
String sMath; // LaTeX representation in math mode
|
||||
String sText; // LaTeX representation in text mode
|
||||
int nFontencs; // Valid font encoding(s) for the text mode representation
|
||||
char cProtect; // This character is represented by this character which may produce unwanted ligatures (-, ', `)
|
||||
|
||||
protected Object clone() {
|
||||
UnicodeCharacter uc = new UnicodeCharacter();
|
||||
uc.nType = this.nType;
|
||||
uc.sMath = this.sMath;
|
||||
uc.sText = this.sText;
|
||||
uc.nFontencs = this.nFontencs;
|
||||
uc.cProtect = this.cProtect;
|
||||
return uc;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* UnicodeRow.java
|
||||
*
|
||||
* Copyright: 2002-2007 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 0.5 (2007-07-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
// Helper class: A row of 256 unicode characters
|
||||
class UnicodeRow implements Cloneable {
|
||||
UnicodeCharacter[] entries;
|
||||
UnicodeRow(){ entries=new UnicodeCharacter[256]; }
|
||||
|
||||
protected Object clone() {
|
||||
UnicodeRow ur = new UnicodeRow();
|
||||
for (int i=0; i<256; i++) {
|
||||
if (this.entries[i]!=null) {
|
||||
ur.entries[i] = (UnicodeCharacter) this.entries[i].clone();
|
||||
}
|
||||
}
|
||||
return ur;
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* UnicodeStringParser.java
|
||||
*
|
||||
* Copyright: 2002-2007 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 0.5 (2007-07-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
// Helper class: Parse a unicode string.
|
||||
// Note: Some 8-bit fonts have additional "spacer" characters that are used
|
||||
// for manual placement of accents. These are ignored between the base character
|
||||
// and the combining character, thus we are parsing according to the rule
|
||||
// <base char> <spacer char>* <combining char>?
|
||||
class UnicodeStringParser {
|
||||
private UnicodeTable table; // the table to use
|
||||
private String s; // the string
|
||||
private int i; // the current index
|
||||
private int nEnd; // the maximal index
|
||||
private char c; // the current character
|
||||
private char cc; // the current combining character
|
||||
|
||||
protected void reset(UnicodeTable table, String s, int i, int nEnd) {
|
||||
this.table=table;
|
||||
this.s=s;
|
||||
this.i=i;
|
||||
this.nEnd=nEnd;
|
||||
}
|
||||
|
||||
protected boolean next() {
|
||||
if (i>=nEnd) { return false; }
|
||||
// Pick up base character
|
||||
c = s.charAt(i++);
|
||||
if (table.getCharType(c)==UnicodeCharacter.COMBINING) {
|
||||
// Lonely combining character - combine with space
|
||||
cc = c;
|
||||
c = ' ';
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip characters that should be ignored
|
||||
while (i<s.length() && table.getCharType(s.charAt(i))==UnicodeCharacter.IGNORE) { i++; }
|
||||
// Pick up combining character, if any
|
||||
if (i<s.length() && table.getCharType(s.charAt(i))==UnicodeCharacter.COMBINING) {
|
||||
cc = s.charAt(i++);
|
||||
}
|
||||
else {
|
||||
cc = '\u0000';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected char getChar() { return c; }
|
||||
|
||||
protected boolean hasCombiningChar() { return cc!='\u0000'; }
|
||||
|
||||
protected char getCombiningChar() { return cc; }
|
||||
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* UnicodeTable.java
|
||||
*
|
||||
* Copyright: 2002-2010 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2010-05-11)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
// Helper class: Table of up to 65536 unicode characters
|
||||
class UnicodeTable {
|
||||
protected UnicodeRow[] table=new UnicodeRow[256];
|
||||
private UnicodeTable parent;
|
||||
|
||||
// Constructor; creates a new table, possibly based on a parent
|
||||
// Note: The parent must be fully loaded before the child is created.
|
||||
public UnicodeTable(UnicodeTable parent){
|
||||
this.parent = parent;
|
||||
if (parent!=null) {
|
||||
// *Copy* the rows from the parent
|
||||
for (int i=0; i<256; i++) {
|
||||
table[i] = parent.table[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the required entry exists
|
||||
private void createEntry(int nRow, int nCol) {
|
||||
if (table[nRow]==null) {
|
||||
table[nRow]=new UnicodeRow();
|
||||
}
|
||||
else if (parent!=null && table[nRow]==parent.table[nRow]) {
|
||||
// Before changing a row it must be *cloned*
|
||||
table[nRow] = (UnicodeRow) parent.table[nRow].clone();
|
||||
}
|
||||
if (table[nRow].entries[nCol]==null) {
|
||||
table[nRow].entries[nCol]=new UnicodeCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
// Addd a single character (type only), by number
|
||||
protected void addCharType(char c, int nType) {
|
||||
int nRow=c/256; int nCol=c%256;
|
||||
createEntry(nRow,nCol);
|
||||
table[nRow].entries[nCol].nType = nType;
|
||||
}
|
||||
|
||||
// Addd a single character (type only), by name
|
||||
protected void addCharType(char c, String sType) {
|
||||
int nRow=c/256; int nCol=c%256;
|
||||
createEntry(nRow,nCol);
|
||||
if ("combining".equals(sType)) {
|
||||
table[nRow].entries[nCol].nType = UnicodeCharacter.COMBINING;
|
||||
}
|
||||
else if ("ignore".equals(sType)) {
|
||||
table[nRow].entries[nCol].nType = UnicodeCharacter.IGNORE;
|
||||
}
|
||||
else {
|
||||
table[nRow].entries[nCol].nType = UnicodeCharacter.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a single math character to the table
|
||||
protected void addMathChar(char c, String sLaTeX){
|
||||
int nRow=c/256; int nCol=c%256;
|
||||
createEntry(nRow,nCol);
|
||||
table[nRow].entries[nCol].sMath=sLaTeX;
|
||||
}
|
||||
|
||||
// Add a single text character to the table
|
||||
protected void addTextChar(char c, String sLaTeX, int nFontencs, char cProtect){
|
||||
int nRow=c/256; int nCol=c%256;
|
||||
createEntry(nRow,nCol);
|
||||
table[nRow].entries[nCol].sText=sLaTeX;
|
||||
table[nRow].entries[nCol].nFontencs=nFontencs;
|
||||
table[nRow].entries[nCol].cProtect=cProtect;
|
||||
}
|
||||
|
||||
// Retrieve entry for a character (or null)
|
||||
private UnicodeCharacter getEntry(char c) {
|
||||
int nRow=c/256; int nCol=c%256;
|
||||
if (table[nRow]==null) return null;
|
||||
return table[nRow].entries[nCol];
|
||||
}
|
||||
|
||||
// Get character type
|
||||
public int getCharType(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return UnicodeCharacter.UNKNOWN;
|
||||
return entry.nType;
|
||||
}
|
||||
|
||||
// Check to see if this math character exists?
|
||||
public boolean hasMathChar(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return false;
|
||||
return entry.sMath!=null;
|
||||
}
|
||||
|
||||
// Get math character (or null)
|
||||
public String getMathChar(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return null;
|
||||
return entry.sMath;
|
||||
}
|
||||
|
||||
// Check to see if this text character exists?
|
||||
public boolean hasTextChar(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return false;
|
||||
return entry.sText!=null;
|
||||
}
|
||||
|
||||
// Get text character (or null)
|
||||
public String getTextChar(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return null;
|
||||
return entry.sText;
|
||||
}
|
||||
|
||||
// Get font encoding(s) for text character (or 0)
|
||||
public int getFontencs(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return 0;
|
||||
return entry.nFontencs;
|
||||
}
|
||||
|
||||
// Get ligature protect character for text character
|
||||
public char getProtectChar(char c) {
|
||||
UnicodeCharacter entry = getEntry(c);
|
||||
if (entry==null) return '\u0000';
|
||||
return entry.cProtect;
|
||||
}
|
||||
|
||||
// Get number of defined characters
|
||||
public int getCharCount() {
|
||||
int nCount = 0;
|
||||
for (int nRow=0; nRow<256; nRow++) {
|
||||
if (table[nRow]!=null) {
|
||||
for (int nCol=0; nCol<256; nCol++) {
|
||||
UnicodeCharacter entry = table[nRow].entries[nCol];
|
||||
if (entry!=null) nCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* UnicodeTableHandler.java
|
||||
*
|
||||
* Copyright: 2002-2010 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2010-05-11)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/** Helper classs: SAX handler to parse symbols.xml from jar
|
||||
*/
|
||||
public class UnicodeTableHandler extends DefaultHandler{
|
||||
private Hashtable<String,UnicodeTable> tableSet; // collection of all tables
|
||||
private UnicodeTable table; // the current table
|
||||
private String sSymbolSets;
|
||||
private boolean bGlobalReadThisSet;
|
||||
private boolean bReadThisSet;
|
||||
private int nGlobalFontencs = 0; // The global fontencodings for current symbol set
|
||||
private int nFontencs = 0; // The currently active fontencodings
|
||||
private boolean b8bit = false;
|
||||
|
||||
/** Create a new <code>UnicodeTableHandler</code>
|
||||
*
|
||||
* @param tableSet the <code>Hashtable</code> to fill with tables read from the file
|
||||
* @param sSymbolSets string containing table names to read (separated by |)
|
||||
*/
|
||||
public UnicodeTableHandler(Hashtable<String,UnicodeTable> tableSet, String sSymbolSets){
|
||||
this.sSymbolSets = sSymbolSets;
|
||||
this.tableSet = tableSet;
|
||||
}
|
||||
|
||||
public void startElement(String nameSpace, String localName, String qName, Attributes attributes){
|
||||
if (qName.equals("symbols")) {
|
||||
//root element - create root table!
|
||||
table = new UnicodeTable(null);
|
||||
tableSet.put("root",table);
|
||||
}
|
||||
else if (qName.equals("symbol-set")) {
|
||||
// start a new symbol set; maybe we want to include it?
|
||||
bGlobalReadThisSet = sSymbolSets.indexOf(attributes.getValue("name")) >= 0;
|
||||
bReadThisSet = bGlobalReadThisSet;
|
||||
// Change global and current fontencodings
|
||||
nGlobalFontencs = ClassicI18n.readFontencs(attributes.getValue("fontenc"));
|
||||
nFontencs = nGlobalFontencs;
|
||||
}
|
||||
else if (qName.equals("special-symbol-set")) {
|
||||
// start a new special symbol set; this requires a new table
|
||||
table = new UnicodeTable(tableSet.get("root"));
|
||||
tableSet.put(attributes.getValue("name"),table);
|
||||
|
||||
// Read it if it requires nothing, or something we read
|
||||
bGlobalReadThisSet = attributes.getValue("requires")==null ||
|
||||
sSymbolSets.indexOf(attributes.getValue("requires")) >= 0;
|
||||
bReadThisSet = bGlobalReadThisSet;
|
||||
b8bit = "true".equals(attributes.getValue("eight-bit"));
|
||||
// Change global and current fontencodings
|
||||
nGlobalFontencs = ClassicI18n.readFontencs(attributes.getValue("fontenc"));
|
||||
nFontencs = nGlobalFontencs;
|
||||
}
|
||||
else if (qName.equals("symbol-subset")) {
|
||||
// Do we requires something here?
|
||||
if (attributes.getValue("requires")!=null) {
|
||||
bReadThisSet = sSymbolSets.indexOf(attributes.getValue("requires")) >= 0;
|
||||
}
|
||||
// Change current fontencodings
|
||||
nFontencs = ClassicI18n.readFontencs(attributes.getValue("fontenc"));
|
||||
}
|
||||
else if (qName.equals("symbol")) {
|
||||
if (bReadThisSet) {
|
||||
char c=(char)Integer.parseInt(attributes.getValue("char"),16);
|
||||
String sEqChar=attributes.getValue("eq-char");
|
||||
if (sEqChar!=null) { // copy existing definitions, if any
|
||||
char eqc = (char)Integer.parseInt(sEqChar,16);
|
||||
if (table.getCharType(eqc)!=UnicodeCharacter.UNKNOWN) {
|
||||
table.addCharType(c,table.getCharType(eqc));
|
||||
}
|
||||
if (table.hasMathChar(eqc)) {
|
||||
table.addMathChar(c,table.getMathChar(eqc));
|
||||
}
|
||||
if (table.hasTextChar(eqc)) {
|
||||
table.addTextChar(c,table.getTextChar(eqc),table.getFontencs(eqc),table.getProtectChar(eqc));
|
||||
}
|
||||
}
|
||||
else {
|
||||
String sType=attributes.getValue("char-type");
|
||||
String sMath=attributes.getValue("math");
|
||||
String sText=attributes.getValue("text");
|
||||
String sProtect=attributes.getValue("protect");
|
||||
char cProtect = sProtect!=null && sProtect.length()>0 ? sProtect.charAt(0) : '\u0000';
|
||||
if (sType!=null) table.addCharType(c,sType);
|
||||
if (sMath!=null) table.addMathChar(c,sMath);
|
||||
if (sText!=null) table.addTextChar(c,sText,nFontencs,cProtect);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (qName.equals("preserve-symbol")) {
|
||||
if (bReadThisSet) {
|
||||
String sMode=attributes.getValue("mode");
|
||||
char c=(char)Integer.parseInt(attributes.getValue("char"),16);
|
||||
table.addCharType(c,attributes.getValue("char-type"));
|
||||
if ("math".equals(sMode) || "both".equals(sMode)) {
|
||||
table.addMathChar(c,Character.toString(c));
|
||||
}
|
||||
if ("text".equals(sMode) || "both".equals(sMode)) {
|
||||
table.addTextChar(c,Character.toString(c),nFontencs,'\u0000');
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (qName.equals("preserve-symbols")) {
|
||||
if (bReadThisSet) {
|
||||
String sMode=attributes.getValue("mode");
|
||||
String sType=attributes.getValue("char-type");
|
||||
char c1=(char)Integer.parseInt(attributes.getValue("first-char"),16);
|
||||
char c2=(char)Integer.parseInt(attributes.getValue("last-char"),16);
|
||||
boolean bMath = "math".equals(sMode) || "both".equals(sMode);
|
||||
boolean bText = "text".equals(sMode) || "both".equals(sMode);
|
||||
for (char c=c1; c<=c2; c++) {
|
||||
table.addCharType(c,sType);
|
||||
if (bMath) {
|
||||
table.addMathChar(c,Character.toString(c));
|
||||
}
|
||||
if (bText) {
|
||||
table.addTextChar(c,Character.toString(c),nFontencs,'\u0000');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String nameSpace, String localName, String qName){
|
||||
if (qName.equals("symbol-subset")) {
|
||||
// Revert to global setting of reading status
|
||||
bReadThisSet = bGlobalReadThisSet;
|
||||
// Revert to global fontencoding
|
||||
nFontencs = nGlobalFontencs;
|
||||
}
|
||||
else if (qName.equals("special-symbol-set")) {
|
||||
if (b8bit) {
|
||||
// Row 0 = Row 240 (F0)
|
||||
// Note: 8-bit fonts are supposed to be relocated to F000..F0FF
|
||||
// This may fail on import from msword, hence this hack
|
||||
table.table[0] = table.table[240];
|
||||
}
|
||||
b8bit = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,231 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* XeTeXI18n.java
|
||||
*
|
||||
* Copyright: 2002-2015 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.6 (2015-06-30)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.i18n;
|
||||
|
||||
import java.text.Bidi;
|
||||
|
||||
import writer2latex.office.*;
|
||||
import writer2latex.latex.LaTeXConfig;
|
||||
import writer2latex.latex.LaTeXDocumentPortion;
|
||||
import writer2latex.latex.ConverterPalette;
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
|
||||
/** This class takes care of i18n in XeLaTeX
|
||||
*/
|
||||
public class XeTeXI18n extends I18n {
|
||||
|
||||
private Polyglossia polyglossia;
|
||||
private boolean bLTR;
|
||||
private boolean bUseXepersian;
|
||||
private String sLTRCommand=null;
|
||||
private String sRTLCommand=null;
|
||||
|
||||
/** Construct a new XeTeXI18n as ConverterHelper
|
||||
* @param ofr the OfficeReader to get language information from
|
||||
* @param config the configuration which determines the symbols to use
|
||||
* @param palette the ConverterPalette (unused)
|
||||
*/
|
||||
public XeTeXI18n(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
|
||||
// CTL support: Currently two CTL languages are supported
|
||||
// - hebrew (he_IL) using polyglossia.sty
|
||||
// - farsi (fa_IR) using xepersian.sty
|
||||
// TODO: Add a use_xepersian option, using polyglossia if false
|
||||
// For these languages currently only monolingual documents are supported
|
||||
// For LTR languages, multilingual documents are supported using polyglossia
|
||||
polyglossia = new Polyglossia();
|
||||
bLTR = !"fa".equals(sDefaultCTLLanguage) && !"he".equals(sDefaultCTLLanguage);
|
||||
if (bLTR) {
|
||||
polyglossia.applyLanguage(sDefaultLanguage, sDefaultCountry);
|
||||
}
|
||||
else {
|
||||
polyglossia.applyLanguage(sDefaultCTLLanguage, sDefaultCTLCountry);
|
||||
}
|
||||
// For farsi, we load xepersian.sty
|
||||
bUseXepersian = "fa".equals(sDefaultCTLLanguage);
|
||||
if (bUseXepersian) {
|
||||
sLTRCommand = "\\lr";
|
||||
sRTLCommand = "\\rl";
|
||||
}
|
||||
}
|
||||
|
||||
/** Add declarations to the preamble to load the required packages
|
||||
* @param pack usepackage declarations
|
||||
* @param decl other declarations
|
||||
*/
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
pack.append("\\usepackage{amsmath,amssymb,amsfonts}").nl()
|
||||
.append("\\usepackage{fontspec}").nl()
|
||||
.append("\\usepackage{xunicode}").nl()
|
||||
.append("\\usepackage{xltxtra}").nl();
|
||||
// xepersian.sty and polyglossia (or rather bidi) should be loaded as the last package
|
||||
// We put it them the declarations part to achieve this
|
||||
if (!bUseXepersian) {
|
||||
String[] polyglossiaDeclarations = polyglossia.getDeclarations();
|
||||
for (String s: polyglossiaDeclarations) {
|
||||
decl.append(s).nl();
|
||||
}
|
||||
if (!bLTR) { // Use a default font set for hebrew
|
||||
decl.append("\\setmainfont[Script=Hebrew]{Frank Ruehl CLM}").nl();
|
||||
decl.append("\\setsansfont[Script=Hebrew]{Nachlieli CLM}").nl();
|
||||
decl.append("\\setmonofont[Script=Hebrew]{Miriam Mono CLM}").nl();
|
||||
}
|
||||
}
|
||||
else {
|
||||
decl.append("\\usepackage{xepersian}").nl();
|
||||
// Set the default font to the default CTL font defined in the document
|
||||
StyleWithProperties defaultStyle = ofr.getDefaultParStyle();
|
||||
if (defaultStyle!=null) {
|
||||
String sDefaultCTLFont = defaultStyle.getProperty(XMLString.STYLE_FONT_NAME_COMPLEX);
|
||||
if (sDefaultCTLFont!=null) {
|
||||
decl.append("\\settextfont{").append(sDefaultCTLFont).append("}").nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply a language
|
||||
* @param style the OOo style to read attributes from
|
||||
* @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 applyLanguage(StyleWithProperties style, boolean bDecl, boolean bInherit, BeforeAfter ba) {
|
||||
if (bLTR && !bAlwaysUseDefaultLang && style!=null) {
|
||||
// TODO: Support CTL and CJK
|
||||
String sISOLang = style.getProperty(XMLString.FO_LANGUAGE,bInherit);
|
||||
String sISOCountry = style.getProperty(XMLString.FO_COUNTRY, bInherit);
|
||||
if (sISOLang!=null) {
|
||||
String[] sCommand = polyglossia.applyLanguage(sISOLang, sISOCountry);
|
||||
if (bDecl) {
|
||||
ba.add(sCommand[1],sCommand[2]);
|
||||
}
|
||||
else {
|
||||
ba.add(sCommand[0]+"{","}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Push a font to the font stack
|
||||
* @param sName the name of the font
|
||||
*/
|
||||
public void pushSpecialTable(String sName) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/** Pop a font from the font stack
|
||||
*/
|
||||
public void popSpecialTable() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/** Convert a string of characters into LaTeX
|
||||
* @param s the source string
|
||||
* @param bMathMode true if the string should be rendered in math mode
|
||||
* @param sLang the ISO language of the string
|
||||
* @return the LaTeX string
|
||||
*/
|
||||
public String convert(String s, boolean bMathMode, String sLang){
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int nLen = s.length();
|
||||
char c;
|
||||
if (bMathMode) {
|
||||
// No string replace or writing direction in math mode
|
||||
for (int i=0; i<nLen; i++) {
|
||||
convert(s.charAt(i),buf);
|
||||
}
|
||||
}
|
||||
else if (!bUseXepersian) {
|
||||
int i = 0;
|
||||
while (i<nLen) {
|
||||
ReplacementTrieNode node = stringReplace.get(s,i,nLen);
|
||||
if (node!=null) {
|
||||
buf.append(node.getLaTeXCode());
|
||||
i += node.getInputLength();
|
||||
}
|
||||
else {
|
||||
c = s.charAt(i++);
|
||||
convert (c,buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: Add support for string replace
|
||||
Bidi bidi = new Bidi(s,Bidi.DIRECTION_RIGHT_TO_LEFT);
|
||||
int nCurrentLevel = bidi.getBaseLevel();
|
||||
int nNestingLevel = 0;
|
||||
for (int i=0; i<nLen; i++) {
|
||||
int nLevel = bidi.getLevelAt(i);
|
||||
if (nLevel>nCurrentLevel) {
|
||||
if (nLevel%2==0) { // even is LTR
|
||||
buf.append(sLTRCommand).append("{");
|
||||
}
|
||||
else { // odd is RTL
|
||||
buf.append(sRTLCommand).append("{");
|
||||
}
|
||||
nCurrentLevel=nLevel;
|
||||
nNestingLevel++;
|
||||
}
|
||||
else if (nLevel<nCurrentLevel) {
|
||||
buf.append("}");
|
||||
nCurrentLevel=nLevel;
|
||||
nNestingLevel--;
|
||||
}
|
||||
convert(s.charAt(i),buf);
|
||||
}
|
||||
while (nNestingLevel>0) {
|
||||
buf.append("}");
|
||||
nNestingLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void convert(char c, StringBuilder buf) {
|
||||
switch (c) {
|
||||
case '#' : buf.append("\\#"); break; // Parameter
|
||||
case '$' : buf.append("\\$"); break; // Math shift
|
||||
case '%' : buf.append("\\%"); break; // Comment
|
||||
case '&' : buf.append("\\&"); break; // Alignment tab
|
||||
case '\\' : buf.append("\\textbackslash{}"); break; // Escape
|
||||
case '^' : buf.append("\\^{}"); break; // Superscript
|
||||
case '_' : buf.append("\\_"); break; // Subscript
|
||||
case '{' : buf.append("\\{"); break; // Begin group
|
||||
case '}' : buf.append("\\}"); break; // End group
|
||||
case '~' : buf.append("\\textasciitilde{}"); break; // Active (non-breaking space)
|
||||
case '\u00A0' : buf.append('~'); break; // Make non-breaking spaces visible
|
||||
default: buf.append(c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,96 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* BeforeAfter.java
|
||||
*
|
||||
* Copyright: 2002-2011 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2011-03-29)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.util;
|
||||
|
||||
/** Utility class to hold LaTeX code to put before/after other LaTeX code
|
||||
*/
|
||||
public class BeforeAfter {
|
||||
private String sBefore="";
|
||||
private String sAfter="";
|
||||
|
||||
/** Constructor to initialize the object with a pair of strings
|
||||
* @param sBefore1 LaTeX code to put before
|
||||
* @param sAfter1 LaTeX code to put after
|
||||
*/
|
||||
public BeforeAfter(String sBefore1, String sAfter1) {
|
||||
sBefore=sBefore1; sAfter=sAfter1;
|
||||
}
|
||||
|
||||
/** Default constructor: Create with empty strings
|
||||
*/
|
||||
public BeforeAfter() { }
|
||||
|
||||
/** <p>Add data to the <code>BeforeAfter</code></p>
|
||||
* <p>The new data will be be added "inside", thus for example</p>
|
||||
* <ul><li><code>add("\textsf{","}");</code>
|
||||
* <li><code>add("\textit{","}");</code></ul>
|
||||
* <p>will create the pair <code>\textsf{\textit{</code>, <code>}}</code></p>
|
||||
*
|
||||
* @param sBefore1 LaTeX code to put before
|
||||
* @param sAfter1 LaTeX code to put after
|
||||
*/
|
||||
public void add(String sBefore1, String sAfter1) {
|
||||
sBefore+=sBefore1; sAfter=sAfter1+sAfter;
|
||||
}
|
||||
|
||||
/** <p>Add data to the <code>BeforeAfter</code></p>
|
||||
* <p>The new data will be be added "outside", thus for example</p>
|
||||
* <ul><li><code>enclose("\textsf{","}");</code>
|
||||
* <li><code>enclose("\textit{","}");</code></ul>
|
||||
* <p>will create the pair <code>\textit{\textsf{</code>, <code>}}</code></p>
|
||||
*
|
||||
* @param sBefore1 LaTeX code to put before
|
||||
* @param sAfter1 LaTeX code to put after
|
||||
*/
|
||||
public void enclose(String sBefore1, String sAfter1) {
|
||||
sBefore=sBefore1+sBefore; sAfter+=sAfter1;
|
||||
}
|
||||
|
||||
/** <p>Add the content of another <code>BeforeAfter</code> to this <code>BeforeAfter</code></p>
|
||||
* <p>The new data will be be added "inside"</p>
|
||||
*
|
||||
* @param ba the code to add
|
||||
*/
|
||||
public void add(BeforeAfter ba) {
|
||||
add(ba.getBefore(), ba.getAfter());
|
||||
}
|
||||
|
||||
/** Get LaTeX code to put before
|
||||
* @return then LaTeX code
|
||||
*/
|
||||
public String getBefore() { return sBefore; }
|
||||
|
||||
/** Get LaTeX code to put after
|
||||
* @return then LaTeX code
|
||||
*/
|
||||
public String getAfter() { return sAfter; }
|
||||
|
||||
/** Check if this <code>BeforeAfter</code> contains any data
|
||||
* @return true if there is data in at least one part
|
||||
*/
|
||||
public boolean isEmpty() { return sBefore.length()==0 && sAfter.length()==0; }
|
||||
|
||||
}
|
|
@ -1,325 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* Context.java
|
||||
*
|
||||
* Copyright: 2002-2011 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2011-01-24)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.util;
|
||||
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
|
||||
/** <p>LaTeX code is in general very context dependent. This class tracks the
|
||||
* current context, which is the used by the converter to create valid and
|
||||
* optimal LaTeX code.</p>
|
||||
*/
|
||||
public class Context {
|
||||
|
||||
// *** Formatting Info (current values in the source OOo document) ***
|
||||
|
||||
// Current list style
|
||||
private String sListStyleName = null;
|
||||
|
||||
// Current background color
|
||||
private String sBgColor = null;
|
||||
|
||||
// Current character formatting attributes
|
||||
private String sFontName = null;
|
||||
private String sFontStyle = null;
|
||||
private String sFontVariant = null;
|
||||
private String sFontWeight = null;
|
||||
private String sFontSize = null;
|
||||
private String sFontColor = null;
|
||||
private String sLang = null;
|
||||
private String sCountry = null;
|
||||
|
||||
// *** Structural Info (identifies contructions in the LaTeX document) ***
|
||||
|
||||
// within the header or footer of a pagestyle
|
||||
private boolean bInHeaderFooter = false;
|
||||
|
||||
// within a table cell
|
||||
private boolean bInTable = false; // any column
|
||||
private boolean bInLastTableColumn = false; // last column
|
||||
private boolean bInSimpleTable = false; // l, c or r-column
|
||||
|
||||
// within a multicols environment
|
||||
private boolean bInMulticols = false;
|
||||
|
||||
// within a list of this level
|
||||
private int nListLevel = 0;
|
||||
|
||||
// within a list that continues numbering
|
||||
private boolean bInContinuedList = false;
|
||||
|
||||
// within a section command
|
||||
private boolean bInSection = false;
|
||||
|
||||
// within a caption
|
||||
private boolean bInCaption = false;
|
||||
|
||||
// within a Zotero/JabRef citation
|
||||
private boolean bInZoteroJabRefText = false;
|
||||
|
||||
// within a floating figure (figure environment)
|
||||
private boolean bInFigureFloat = false;
|
||||
|
||||
// within a floating table (table environment)
|
||||
private boolean bInTableFloat = false;
|
||||
|
||||
// within a minipage environment
|
||||
private boolean bInFrame = false;
|
||||
|
||||
// within a \footnote or \endnote
|
||||
private boolean bInFootnote = false;
|
||||
|
||||
// in verbatim mode
|
||||
private boolean bVerbatim = false;
|
||||
|
||||
// in math mode
|
||||
private boolean bMathMode = false;
|
||||
|
||||
// *** Special Info ***
|
||||
|
||||
// Inside (inline) verbatim text, where line breaks are disallowed
|
||||
private boolean bNoLineBreaks = false;
|
||||
|
||||
// Inside a construction, where footnotes are disallowed
|
||||
private boolean bNoFootnotes = false;
|
||||
|
||||
// Inside an area, where lists are ignored
|
||||
private boolean bIgnoreLists = false;
|
||||
|
||||
// *** Accessor Methods ***
|
||||
|
||||
public void setBgColor(String sBgColor) { this.sBgColor = sBgColor; }
|
||||
|
||||
public String getBgColor() { return sBgColor; }
|
||||
|
||||
public void setListStyleName(String sListStyleName) { this.sListStyleName = sListStyleName; }
|
||||
|
||||
public String getListStyleName() { return sListStyleName; }
|
||||
|
||||
public void setFontName(String sFontName) { this.sFontName = sFontName; }
|
||||
|
||||
public String getFontName() { return sFontName; }
|
||||
|
||||
public void setFontStyle(String sFontStyle) { this.sFontStyle = sFontStyle; }
|
||||
|
||||
public String getFontStyle() { return sFontStyle; }
|
||||
|
||||
public void setFontVariant(String sFontVariant) { this.sFontVariant = sFontVariant; }
|
||||
|
||||
public String getFontVariant() { return sFontVariant; }
|
||||
|
||||
public void setFontWeight(String sFontWeight) { this.sFontWeight = sFontWeight; }
|
||||
|
||||
public String getFontWeight() { return sFontWeight; }
|
||||
|
||||
public void setFontSize(String sFontSize) { this.sFontSize = sFontSize; }
|
||||
|
||||
public String getFontSize() { return sFontSize; }
|
||||
|
||||
public void setFontColor(String sFontColor) { this.sFontColor = sFontColor; }
|
||||
|
||||
public String getFontColor() { return sFontColor; }
|
||||
|
||||
public void setLang(String sLang) { this.sLang = sLang; }
|
||||
|
||||
public String getLang() { return sLang; }
|
||||
|
||||
public void setCountry(String sCountry) { this.sCountry = sCountry; }
|
||||
|
||||
public String getCountry() { return sCountry; }
|
||||
|
||||
public void setInHeaderFooter(boolean bInHeaderFooter) {
|
||||
this.bInHeaderFooter = bInHeaderFooter;
|
||||
}
|
||||
|
||||
public boolean isInHeaderFooter() { return bInHeaderFooter; }
|
||||
|
||||
public void setInTable(boolean bInTable) { this.bInTable = bInTable; }
|
||||
|
||||
public boolean isInTable() { return bInTable; }
|
||||
|
||||
public void setInLastTableColumn(boolean bInLastTableColumn) { this.bInLastTableColumn = bInLastTableColumn; }
|
||||
|
||||
public boolean isInLastTableColumn() { return bInLastTableColumn; }
|
||||
|
||||
public void setInSimpleTable(boolean bInSimpleTable) { this.bInSimpleTable = bInSimpleTable; }
|
||||
|
||||
public boolean isInSimpleTable() { return bInSimpleTable; }
|
||||
|
||||
public void setInMulticols(boolean bInMulticols) {
|
||||
this.bInMulticols = bInMulticols;
|
||||
}
|
||||
|
||||
public boolean isInMulticols() { return bInMulticols; }
|
||||
|
||||
public void setListLevel(int nListLevel) { this.nListLevel = nListLevel; }
|
||||
|
||||
public void incListLevel() { nListLevel++; }
|
||||
|
||||
public int getListLevel() { return nListLevel; }
|
||||
|
||||
public void setInContinuedList(boolean bInContinuedList) { this.bInContinuedList=bInContinuedList; }
|
||||
|
||||
public boolean isInContinuedList() { return this.bInContinuedList; }
|
||||
|
||||
public void setInSection(boolean bInSection) { this.bInSection = bInSection; }
|
||||
|
||||
public boolean isInSection() { return bInSection; }
|
||||
|
||||
public void setInCaption(boolean bInCaption) { this.bInCaption = bInCaption; }
|
||||
|
||||
public boolean isInCaption() { return bInCaption; }
|
||||
|
||||
public void setInZoteroJabRefText(boolean bInZoteroJabRefText) { this.bInZoteroJabRefText = bInZoteroJabRefText; }
|
||||
|
||||
public boolean isInZoteroJabRefText() { return bInZoteroJabRefText; }
|
||||
|
||||
public void setInFigureFloat(boolean bInFigureFloat) { this.bInFigureFloat = bInFigureFloat; }
|
||||
|
||||
public boolean isInFigureFloat() { return bInFigureFloat; }
|
||||
|
||||
public void setInTableFloat(boolean bInTableFloat) { this.bInTableFloat = bInTableFloat; }
|
||||
|
||||
public boolean isInTableFloat() { return bInTableFloat; }
|
||||
|
||||
public void setInFrame(boolean bInFrame) { this.bInFrame = bInFrame; }
|
||||
|
||||
public boolean isInFrame() { return bInFrame; }
|
||||
|
||||
public void setInFootnote(boolean bInFootnote) {
|
||||
this.bInFootnote = bInFootnote;
|
||||
}
|
||||
|
||||
public boolean isInFootnote() { return bInFootnote; }
|
||||
|
||||
public void setNoFootnotes(boolean bNoFootnotes) {
|
||||
this.bNoFootnotes = bNoFootnotes;
|
||||
}
|
||||
|
||||
public boolean isNoFootnotes() { return bNoFootnotes; }
|
||||
|
||||
public void setIgnoreLists(boolean bIgnoreLists) {
|
||||
this.bIgnoreLists = bIgnoreLists;
|
||||
}
|
||||
|
||||
public boolean isIgnoreLists() { return bIgnoreLists; }
|
||||
|
||||
public void setNoLineBreaks(boolean bNoLineBreaks) {
|
||||
this.bNoLineBreaks = bNoLineBreaks;
|
||||
}
|
||||
public boolean isNoLineBreaks() { return bNoLineBreaks; }
|
||||
|
||||
public boolean isVerbatim() { return bVerbatim; }
|
||||
|
||||
public void setVerbatim(boolean bVerbatim) { this.bVerbatim = bVerbatim; }
|
||||
|
||||
public boolean isMathMode() { return bMathMode; }
|
||||
|
||||
public void setMathMode(boolean bMathMode) { this.bMathMode = bMathMode; }
|
||||
|
||||
// update context
|
||||
|
||||
public void updateFormattingFromStyle(StyleWithProperties style) {
|
||||
String s;
|
||||
|
||||
if (style==null) { return; }
|
||||
|
||||
s = style.getProperty(XMLString.STYLE_FONT_NAME);
|
||||
if (s!=null) { setFontName(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_FONT_STYLE);
|
||||
if (s!=null) { setFontStyle(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_FONT_VARIANT);
|
||||
if (s!=null) { setFontVariant(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_FONT_WEIGHT);
|
||||
if (s!=null) { setFontWeight(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_FONT_SIZE);
|
||||
if (s!=null) { setFontSize(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_COLOR);
|
||||
if (s!=null) { setFontColor(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_LANGUAGE);
|
||||
if (s!=null) { setLang(s); }
|
||||
|
||||
s = style.getProperty(XMLString.FO_COUNTRY);
|
||||
if (s!=null) { setCountry(s); }
|
||||
}
|
||||
|
||||
public void resetFormattingFromStyle(StyleWithProperties style) {
|
||||
setFontName(null);
|
||||
setFontStyle(null);
|
||||
setFontVariant(null);
|
||||
setFontWeight(null);
|
||||
setFontSize(null);
|
||||
setFontColor(null);
|
||||
setLang(null);
|
||||
setCountry(null);
|
||||
updateFormattingFromStyle(style);
|
||||
}
|
||||
|
||||
|
||||
// clone this Context
|
||||
public Object clone() {
|
||||
Context newContext = new Context();
|
||||
|
||||
newContext.setListStyleName(sListStyleName);
|
||||
newContext.setBgColor(sBgColor);
|
||||
newContext.setFontName(sFontName);
|
||||
newContext.setFontStyle(sFontStyle);
|
||||
newContext.setFontVariant(sFontVariant);
|
||||
newContext.setFontWeight(sFontWeight);
|
||||
newContext.setFontSize(sFontSize);
|
||||
newContext.setFontColor(sFontColor);
|
||||
newContext.setLang(sLang);
|
||||
newContext.setCountry(sCountry);
|
||||
newContext.setInHeaderFooter(bInHeaderFooter);
|
||||
newContext.setInTable(bInTable);
|
||||
newContext.setInLastTableColumn(bInLastTableColumn);
|
||||
newContext.setInSimpleTable(bInSimpleTable);
|
||||
newContext.setInMulticols(bInMulticols);
|
||||
newContext.setListLevel(nListLevel);
|
||||
newContext.setInContinuedList(bInContinuedList);
|
||||
newContext.setInSection(bInSection);
|
||||
newContext.setInCaption(bInCaption);
|
||||
newContext.setInZoteroJabRefText(bInZoteroJabRefText);
|
||||
newContext.setInFigureFloat(bInFigureFloat);
|
||||
newContext.setInTableFloat(bInTableFloat);
|
||||
newContext.setInFrame(bInFrame);
|
||||
newContext.setInFootnote(bInFootnote);
|
||||
newContext.setVerbatim(bVerbatim);
|
||||
newContext.setMathMode(bMathMode);
|
||||
newContext.setNoFootnotes(bNoFootnotes);
|
||||
newContext.setIgnoreLists(bIgnoreLists);
|
||||
newContext.setNoLineBreaks(bNoLineBreaks);
|
||||
|
||||
return newContext;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* HeadingMap.java
|
||||
*
|
||||
* Copyright: 2002-2006 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 0.5 (2006-11-02)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.util;
|
||||
|
||||
/** This class contains data for the mapping of OOo headings to LaTeX headings.
|
||||
A LaTeX heading is characterized by a name and a level.
|
||||
The heading is inserted with \name{...} or \name[...]{...}
|
||||
The headings are supposed to be "normal" LaTeX headings,
|
||||
ie. the names are also counter names, and the headings
|
||||
can be reformatted using \@startsection etc.
|
||||
Otherwise max-level should be zero.
|
||||
*/
|
||||
public class HeadingMap {
|
||||
private int nMaxLevel;
|
||||
private String[] sName;
|
||||
private int[] nLevel;
|
||||
|
||||
/** Constructor: Create a new HeadingMap
|
||||
@param nMaxLevel the maximal level of headings that are mapped */
|
||||
public HeadingMap(int nMaxLevel) {
|
||||
reset(nMaxLevel);
|
||||
}
|
||||
|
||||
/** Clear all data associated with this HeadingMap (in order to reuse it) */
|
||||
public void reset(int nMaxLevel) {
|
||||
this.nMaxLevel = nMaxLevel;
|
||||
sName = new String[nMaxLevel+1];
|
||||
nLevel = new int[nMaxLevel+1];
|
||||
}
|
||||
|
||||
/** Set data associated with a specific heading level */
|
||||
public void setLevelData(int nWriterLevel, String sName, int nLevel) {
|
||||
this.sName[nWriterLevel] = sName;
|
||||
this.nLevel[nWriterLevel] = nLevel;
|
||||
}
|
||||
|
||||
/** Returns the maximal Writer level associated with this HeadingMap */
|
||||
public int getMaxLevel() { return nMaxLevel; }
|
||||
|
||||
/** Return the name (for counter and \@startsection) for this level */
|
||||
public String getName(int nWriterLevel) { return sName[nWriterLevel]; }
|
||||
|
||||
/** Return the LaTeX level for this Writer level (for \@startsection) */
|
||||
public int getLevel(int nWriterLevel) { return nLevel[nWriterLevel]; }
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The package writer2latex.xhtml.util</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Some general utility classes for LaTeX export.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,116 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* StyleMap.java
|
||||
*
|
||||
* Copyright: 2002-2011 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2011-03-30)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.util;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class StyleMap {
|
||||
private Hashtable<String, StyleMapItem> items = new Hashtable<String, StyleMapItem>();
|
||||
|
||||
public void put(String sName, String sBefore, String sAfter, String sNext, boolean bLineBreak, int nBreakAfter, boolean bVerbatim) {
|
||||
StyleMapItem item = new StyleMapItem();
|
||||
item.sBefore = sBefore;
|
||||
item.sAfter = sAfter;
|
||||
item.sNext = ";"+sNext+";";
|
||||
item.bLineBreak = bLineBreak;
|
||||
item.nBreakAfter = nBreakAfter;
|
||||
item.bVerbatim = bVerbatim;
|
||||
items.put(sName,item);
|
||||
}
|
||||
|
||||
public void put(String sName, String sBefore, String sAfter, boolean bLineBreak, int nBreakAfter, boolean bVerbatim) {
|
||||
StyleMapItem item = new StyleMapItem();
|
||||
item.sBefore = sBefore;
|
||||
item.sAfter = sAfter;
|
||||
item.sNext = ";;";
|
||||
item.bLineBreak = bLineBreak;
|
||||
item.nBreakAfter = nBreakAfter;
|
||||
item.bVerbatim = bVerbatim;
|
||||
items.put(sName,item);
|
||||
}
|
||||
|
||||
public void put(String sName, String sBefore, String sAfter, String sNext, boolean bVerbatim) {
|
||||
StyleMapItem item = new StyleMapItem();
|
||||
item.sBefore = sBefore;
|
||||
item.sAfter = sAfter;
|
||||
item.sNext = ";"+sNext+";";
|
||||
item.bLineBreak = true;
|
||||
item.nBreakAfter = StyleMapItem.PAR;
|
||||
item.bVerbatim = bVerbatim;
|
||||
items.put(sName,item);
|
||||
}
|
||||
|
||||
public void put(String sName, String sBefore, String sAfter) {
|
||||
StyleMapItem item = new StyleMapItem();
|
||||
item.sBefore = sBefore;
|
||||
item.sAfter = sAfter;
|
||||
item.sNext = ";;";
|
||||
item.bLineBreak = true;
|
||||
item.nBreakAfter = StyleMapItem.PAR;
|
||||
item.bVerbatim = false;
|
||||
items.put(sName,item);
|
||||
}
|
||||
|
||||
public boolean contains(String sName) {
|
||||
return sName!=null && items.containsKey(sName);
|
||||
}
|
||||
|
||||
public String getBefore(String sName) {
|
||||
return items.get(sName).sBefore;
|
||||
}
|
||||
|
||||
public String getAfter(String sName) {
|
||||
return items.get(sName).sAfter;
|
||||
}
|
||||
|
||||
public String getNext(String sName) {
|
||||
String sNext = items.get(sName).sNext;
|
||||
return sNext.substring(1,sNext.length()-1);
|
||||
}
|
||||
|
||||
public boolean isNext(String sName, String sNext) {
|
||||
String sNext1 = items.get(sName).sNext;
|
||||
return sNext1.indexOf(";"+sNext+";")>-1;
|
||||
}
|
||||
|
||||
public boolean getLineBreak(String sName) {
|
||||
return contains(sName) && items.get(sName).bLineBreak;
|
||||
}
|
||||
|
||||
public int getBreakAfter(String sName) {
|
||||
return contains(sName) ? items.get(sName).nBreakAfter : StyleMapItem.PAR;
|
||||
}
|
||||
|
||||
public boolean getVerbatim(String sName) {
|
||||
return contains(sName) && items.get(sName).bVerbatim;
|
||||
}
|
||||
|
||||
public Enumeration<String> getNames() {
|
||||
return items.keys();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* StyleMapItem.java
|
||||
*
|
||||
* Copyright: 2002-2011 by Henrik Just
|
||||
*
|
||||
* This file is part of Writer2LaTeX.
|
||||
*
|
||||
* Writer2LaTeX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Writer2LaTeX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Version 1.2 (2011-03-30)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex.util;
|
||||
|
||||
// A struct to hold data about a style map
|
||||
public class StyleMapItem {
|
||||
public static final int NONE = 0;
|
||||
public static final int LINE = 1;
|
||||
public static final int PAR = 2;
|
||||
|
||||
String sBefore;
|
||||
String sAfter;
|
||||
String sNext;
|
||||
int nBreakAfter;
|
||||
boolean bLineBreak;
|
||||
boolean bVerbatim;
|
||||
}
|
|
@ -33,13 +33,13 @@ import org.w3c.dom.NamedNodeMap;
|
|||
import writer2latex.office.*;
|
||||
import writer2latex.util.Misc;
|
||||
import writer2latex.base.BinaryGraphicsDocument;
|
||||
import writer2latex.latex.StarMathConverter;
|
||||
//import writer2latex.latex.StarMathConverter;
|
||||
|
||||
/** This class converts formulas: Either as MathML, as an image or as plain text (StarMath or LaTeX format)
|
||||
*/
|
||||
public class MathConverter extends ConverterHelper {
|
||||
|
||||
private StarMathConverter smc = null;
|
||||
//private StarMathConverter smc = null;
|
||||
|
||||
private boolean bSupportMathML;
|
||||
private boolean bUseImage;
|
||||
|
@ -60,7 +60,7 @@ public class MathConverter extends ConverterHelper {
|
|||
this.bUseImage = config.formulas()==XhtmlConfig.IMAGE_LATEX || config.formulas()==XhtmlConfig.IMAGE_STARMATH;
|
||||
this.bUseLaTeX = config.formulas()==XhtmlConfig.IMAGE_LATEX || config.formulas()==XhtmlConfig.LATEX;
|
||||
|
||||
if (bUseLaTeX) { smc = new StarMathConverter(); }
|
||||
// if (bUseLaTeX) { smc = new StarMathConverter(); }
|
||||
}
|
||||
|
||||
/** Convert a formula
|
||||
|
@ -143,7 +143,7 @@ public class MathConverter extends ConverterHelper {
|
|||
sAnnotation+=child.getNodeValue();
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
if (bUseLaTeX) { sAnnotation = smc.convert(sAnnotation); }
|
||||
// if (bUseLaTeX) { sAnnotation = smc.convert(sAnnotation); }
|
||||
|
||||
// Next insert the image if required and available
|
||||
if (bUseImage) {
|
||||
|
|
Loading…
Add table
Reference in a new issue