git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@26 f0f2a975-2e09-46c8-9428-3b39399b9f3c

This commit is contained in:
henrikjust 2009-07-03 08:28:43 +00:00
parent 574e550311
commit 9e78c8fc3d
11 changed files with 932 additions and 34 deletions

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2009-05-01)
* Version 1.2 (2009-06-19)
*
*/
@ -268,7 +268,7 @@ public final class ConfigurationDialog
externalApps.setApplication(ExternalApps.DVIPS, "dvips", "%s");
externalApps.setApplication(ExternalApps.BIBTEX, "bibtex", "%s");
externalApps.setApplication(ExternalApps.MAKEINDEX, "makeindex", "%s");
externalApps.setApplication(ExternalApps.MK4HT, "mk4ht", "oolatex %s");
externalApps.setApplication(ExternalApps.MK4HT, "mk4ht", "%c %s");
externalApps.setApplication(ExternalApps.DVIVIEWER, "yap", "--single-instance %s");
// And assume gsview for pdf and ps
// gsview32 may not be in the path, but at least this helps a bit
@ -282,7 +282,7 @@ public final class ConfigurationDialog
configureApp(ExternalApps.DVIPS, "dvips", "%s");
configureApp(ExternalApps.BIBTEX, "bibtex", "%s");
configureApp(ExternalApps.MAKEINDEX, "makeindex", "%s");
configureApp(ExternalApps.MK4HT, "mk4ht", "oolatex %s");
configureApp(ExternalApps.MK4HT, "mk4ht", "%c %s");
// We have several possible viewers
String[] sDviViewers = {"evince", "okular", "xdvi"};
configureApp(ExternalApps.DVIVIEWER, sDviViewers, "%s");

View file

@ -0,0 +1,221 @@
/************************************************************************
*
* DeTeXtive.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2009 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.2 (2009-06-19)
*
*/
package org.openoffice.da.comp.writer4latex;
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;
}
}
}

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2009-03-30)
* Version 1.2 (2009-06-19)
*
*/
@ -95,7 +95,7 @@ public class ExternalApps {
public String[] getApplication(String sAppName) {
return apps.get(sAppName);
}
/** Execute an external application
* @param sAppName the name of the application to execute
* @param sFileName the file name to use
@ -104,6 +104,18 @@ public class ExternalApps {
* @return error code
*/
public int execute(String sAppName, String sFileName, File workDir, boolean bWaitFor) {
return execute(sAppName, "", sFileName, workDir, bWaitFor);
}
/** 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 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, boolean bWaitFor) {
// Assemble the command
String[] sApp = getApplication(sAppName);
if (sApp==null) { return 1; }
@ -113,19 +125,13 @@ public class ExternalApps {
command.add(sApp[0]);
String[] sArguments = sApp[1].split(" ");
for (String s : sArguments) {
command.add(s.replace("%s",sFileName));
command.add(s.replace("%c",sCommand).replace("%s",sFileName));
}
ProcessBuilder pb = new ProcessBuilder(command);
//Map<String, String> env = pb.environment();
//env.put("VAR1", "myValue");
pb.directory(workDir);
Process proc = pb.start();
//Runtime rt = Runtime.getRuntime();
//Process proc = rt.exec(sCommand, new String[0], workDir);
// Gobble the error stream of the application
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");

View file

@ -20,25 +20,33 @@
*
* All Rights Reserved.
*
* Version 1.2 (2009-05-20)
* Version 1.2 (2009-06-19)
*
*/
package org.openoffice.da.comp.writer4latex;
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.task.XStatusIndicator;
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 {
public class TeXDetectService extends WeakBase implements XExtendedFilterDetection, XServiceInfo {
// Constants
@ -47,17 +55,40 @@ public class TeXDetectService extends WeakBase implements XExtendedFilterDetecti
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.writer4latex.LaTeX_File";
private static final String XELATEX_FILE = "org.openoffice.da.writer4latex.XeLaTeX_File";
// From constructor+initialization
private final XComponentContext m_xContext;
private final XComponentContext m_xContext;
/** Construct a new <code>TeXDetectService</code>
*
* @param xContext The Component Context
*/
public TeXDetectService( XComponentContext xContext ) {
m_xContext = 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
@ -80,10 +111,66 @@ public class TeXDetectService extends WeakBase implements XExtendedFilterDetecti
}
}
if ("org.openoffice.da.writer4latex.LaTeX_File".equals(sTypeName)) {
return sTypeName;
// If there's no URL, we cannot verify the type (this should never happen on proper use of the service)
if (sURL==null) {
System.out.println("No URL given!");
return "";
}
else {
System.out.println("Asked to verify the type "+sTypeName);
// 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)
System.out.println("Failed to get SFA service");
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
System.out.println("Failed to get input stream");
return "";
}
catch (com.sun.star.uno.Exception e) {
// Failed to create input stream, cannot verify the type
System.out.println("Failed to get input stream");
return "";
}
// Ask the deTeXtive
DeTeXtive deTeXtive = new DeTeXtive();
try {
String sType = deTeXtive.deTeXt(is);
System.out.println("The DeTeXtive returned the type "+sType);
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
System.out.println("Failed to read the input stream");
return "";
}

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2009-05-19)
* Version 1.2 (2009-06-19)
*
*/
@ -32,6 +32,7 @@ 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;
@ -48,7 +49,7 @@ 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 {
public class TeXImportFilter extends WeakBase implements XInitialization, XNamed, XImporter, XFilter, XServiceInfo {
// Constants
@ -282,7 +283,15 @@ public class TeXImportFilter extends WeakBase implements XInitialization, XNamed
if (xStatus!=null) { xStatus.setValue(++nStep); }
externalApps.execute(ExternalApps.MK4HT, file.getName(), file.getParentFile(), true);
// Default is the filter org.openoffice.da.writer4latex.latex
String sCommand = "oolatex";
if ("org.openoffice.da.writer4latex.xelatex".equals(m_sFilterName)) {
sCommand = "ooxelatex";
}
System.out.println("Executing tex4ht with command "+sCommand+" on file "+file.getName());
externalApps.execute(ExternalApps.MK4HT, sCommand, file.getName(), file.getParentFile(), true);
if (xStatus!=null) { nStep+=5; xStatus.setValue(nStep); }

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2009-05-18)
* Version 1.2 (2009-06-19)
*
*/
@ -505,17 +505,78 @@ public final class Writer4LaTeX extends WeakBase
String sResult = "";
for (int i=0; i<sArgument.length(); i++) {
char c = sArgument.charAt(i);
if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='-' || c=='.') {
if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) {
sResult += Character.toString(c);
}
// TODO: Create replacement table for other latin characters..
else if (c==' ') { sResult += "-"; }
else if (c=='\u00c6') { sResult += "AE"; }
else if (c=='\u00d8') { sResult += "OE"; }
else if (c=='\u00c5') { sResult += "AA"; }
else if (c=='\u00e6') { sResult += "ae"; }
else if (c=='\u00f8') { sResult += "oe"; }
else if (c=='\u00e5') { sResult += "aa"; }
else {
switch (c) {
case '.': sResult += "."; break;
case '-': sResult += "-"; break;
case ' ' : sResult += "-"; break;
case '_' : sResult += "-"; break;
// Replace accented and national characters
case '\u00c0' : sResult += "A"; break;
case '\u00c1' : sResult += "A"; break;
case '\u00c2' : sResult += "A"; break;
case '\u00c3' : sResult += "A"; break;
case '\u00c4' : sResult += "AE"; break;
case '\u00c5' : sResult += "AA"; break;
case '\u00c6' : sResult += "AE"; break;
case '\u00c7' : sResult += "C"; break;
case '\u00c8' : sResult += "E"; break;
case '\u00c9' : sResult += "E"; break;
case '\u00ca' : sResult += "E"; break;
case '\u00cb' : sResult += "E"; break;
case '\u00cc' : sResult += "I"; break;
case '\u00cd' : sResult += "I"; break;
case '\u00ce' : sResult += "I"; break;
case '\u00cf' : sResult += "I"; break;
case '\u00d0' : sResult += "D"; break;
case '\u00d1' : sResult += "N"; break;
case '\u00d2' : sResult += "O"; break;
case '\u00d3' : sResult += "O"; break;
case '\u00d4' : sResult += "O"; break;
case '\u00d5' : sResult += "O"; break;
case '\u00d6' : sResult += "OE"; break;
case '\u00d8' : sResult += "OE"; break;
case '\u00d9' : sResult += "U"; break;
case '\u00da' : sResult += "U"; break;
case '\u00db' : sResult += "U"; break;
case '\u00dc' : sResult += "UE"; break;
case '\u00dd' : sResult += "Y"; break;
case '\u00df' : sResult += "sz"; break;
case '\u00e0' : sResult += "a"; break;
case '\u00e1' : sResult += "a"; break;
case '\u00e2' : sResult += "a"; break;
case '\u00e3' : sResult += "a"; break;
case '\u00e4' : sResult += "ae"; break;
case '\u00e5' : sResult += "aa"; break;
case '\u00e6' : sResult += "ae"; break;
case '\u00e7' : sResult += "c"; break;
case '\u00e8' : sResult += "e"; break;
case '\u00e9' : sResult += "e"; break;
case '\u00ea' : sResult += "e"; break;
case '\u00eb' : sResult += "e"; break;
case '\u00ec' : sResult += "i"; break;
case '\u00ed' : sResult += "i"; break;
case '\u00ee' : sResult += "i"; break;
case '\u00ef' : sResult += "i"; break;
case '\u00f0' : sResult += "d"; break;
case '\u00f1' : sResult += "n"; break;
case '\u00f2' : sResult += "o"; break;
case '\u00f3' : sResult += "o"; break;
case '\u00f4' : sResult += "o"; break;
case '\u00f5' : sResult += "o"; break;
case '\u00f6' : sResult += "oe"; break;
case '\u00f8' : sResult += "oe"; break;
case '\u00f9' : sResult += "u"; break;
case '\u00fa' : sResult += "u"; break;
case '\u00fb' : sResult += "u"; break;
case '\u00fc' : sResult += "ue"; break;
case '\u00fd' : sResult += "y"; break;
case '\u00ff' : sResult += "y"; break;
}
}
}
if (sResult.length()==0) { return "writer4latex"; }
else { return sResult; }