Package net.sf.latexdraw.glib.views.latex

Source Code of net.sf.latexdraw.glib.views.latex.LaTeXGenerator

package net.sf.latexdraw.glib.views.latex;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import net.sf.latexdraw.badaboom.BadaboomCollector;
import net.sf.latexdraw.filters.EPSFilter;
import net.sf.latexdraw.filters.PDFFilter;
import net.sf.latexdraw.filters.TeXFilter;
import net.sf.latexdraw.glib.models.interfaces.shape.IDrawing;
import net.sf.latexdraw.glib.models.interfaces.shape.IPoint;
import net.sf.latexdraw.glib.views.pst.PSTCodeGenerator;
import net.sf.latexdraw.glib.views.synchroniser.ViewsSynchroniserHandler;
import net.sf.latexdraw.util.LFileUtils;
import net.sf.latexdraw.util.LResources;
import net.sf.latexdraw.util.LSystem;
import net.sf.latexdraw.util.LSystem.OperatingSystem;

import org.malai.mapping.ActiveUnary;
import org.malai.mapping.IUnary;
import org.malai.properties.Modifiable;

/**
* Defines an abstract LaTeX generator.<br>
* <br>
* This file is part of LaTeXDraw.<br>
* Copyright (c) 2005-2014 Arnaud BLOUIN<br>
* <br>
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* <br>
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.<br>
* <br>
* 05/23/2010<br>
* @author Arnaud BLOUIN
* @since 3.0
*/
public abstract class LaTeXGenerator implements Modifiable {

  /** Defines the number of characters added at the beginning
   * of each lines of the comment (these characters are "% "). */
  public static final int LGTH_START_LINE_COMMENT = 2;

  /**
   * The latex packages used when exporting using latex.
   * These packages are defined for the current document but not for all documents.
   */
  protected static final IUnary<String> PACKAGES = new ActiveUnary<>(""); //$NON-NLS-1$



  /**
   * @param packages the packages to set.
   * @since 3.0
   */
  public static void setPackages(final String packages) {
    if(packages!=null && !packages.equals(getPackages()))
      LaTeXGenerator.PACKAGES.setValue(packages);
  }


  /**
   * @return the packages.
   * @since 3.0
   */
  public static String getPackages() {
    return PACKAGES.getValue();
  }


  /**
   * @return The unary relation that contains the packages value.
   * @since 3.0
   */
  public static IUnary<String> getPackagesUnary() {
    return PACKAGES;
  }


  /**
   * The different vertical positions.
   */
  public enum VerticalPosition {
    TOP {
      @Override
      public String getToken() { return "t"; }//$NON-NLS-1$
    }, BOTTOM {
      @Override
      public String getToken() { return "b"; }//$NON-NLS-1$
    }, FLOATS_PAGE {
      @Override
      public String getToken() { return "p"; }//$NON-NLS-1$
    }, HERE {
      @Override
      public String getToken() { return "h"; }//$NON-NLS-1$
    }, HERE_HERE {
      @Override
      public String getToken() { return "H"; }//$NON-NLS-1$
    }, NONE {
      @Override
      public String getToken() { return ""; }//$NON-NLS-1$
    };


    @Override
    public String toString() {
      return getToken();
    }

    /**
     * @return The token corresponding to the placement.
     * @since 3.0
     */
    public abstract String getToken();


    /**
     * @param pos The position token to check.
     * @return The corresponding vertical position.
     * @since 3.0
     */
    public static VerticalPosition getPosition(final String pos) {
      if(pos==null)
        return null;

      if(pos.equals(TOP.getToken()))
        return TOP;

      if(pos.equals(BOTTOM.getToken()))
        return BOTTOM;

      if(pos.equals(FLOATS_PAGE.getToken()))
        return FLOATS_PAGE;

      if(pos.equals(HERE.getToken()))
        return HERE;

      if(pos.equals(HERE_HERE.getToken()))
        return HERE_HERE;

      if(pos.equals(NONE.getToken()))
        return NONE;

      return null;
    }
  }


  /** The comment of the drawing. */
  protected String comment;

  /** The label of the drawing. */
  protected String label;

  /** The caption of the drawing. */
  protected String caption;

  /** The token of the position of the drawing */
  protected VerticalPosition positionVertToken;

  /** The horizontal position of the drawing */
  protected boolean positionHoriCentre;

  /** Defined if the instrument has been modified. */
  protected boolean modified;

  /** The scale of the drawing. */
  protected double scale;


  /**
   * Initialises the abstract generator.
   * @since 3.0
   */
    protected LaTeXGenerator() {
    super();

    modified= false;
    comment = ""; //$NON-NLS-1$
    label   = ""; //$NON-NLS-1$
    caption = ""; //$NON-NLS-1$
    positionHoriCentre = false;
    positionVertToken  = VerticalPosition.NONE;
    scale = 1.;
  }


  /**
   * @return the scale of the drawing.
   * @since 3.0
   */
  public double getScale() {
    return scale;
  }



  /**
   * @param scale the scale to set.
   * @since 3.0
   */
  public void setScale(final double scale) {
    if(scale>=0.1)
      this.scale = scale;
  }




  /**
   * @return the comment.
   * @since 3.0
   */
  public String getComment() {
    return comment;
  }



  /**
   * @return The comments without any characters like "%"
   * at the start of each lines. (these characters are used like comment symbol by LaTeX).
   */
  public String getCommentsWithoutTag() {
    int i=0;
        int j=0;
        final int lgth = comment.length();
        final char[] buffer = new char[lgth];
    boolean eol   = true;

    while(i<lgth) {
      if(eol && comment.charAt(i)=='%') {
        i+=LGTH_START_LINE_COMMENT;
        eol = false;
      }
      else {
        if(comment.charAt(i)=='\n')
          eol = true;

        buffer[j++] = comment.charAt(i);
        i++;
      }
    }

    final String str = String.valueOf(buffer, 0, j);

    return str.length()>1 ? str.substring(0, str.length()-LResources.EOL.length()) : str;
  }


  @Override
  public boolean isModified() {
    return modified;
  }

  @Override
  public void setModified(final boolean modified) {
    this.modified = modified;
  }


  /**
   * @param newComments the comment to set.
   * @since 3.0
   */
  public void setComment(final String newComments) {
    if(newComments!=null && !newComments.isEmpty()) {
      int i;
            int j=0;
            final int lgth = newComments.length();
            final char[] buffer = new char[lgth*3];
      boolean eol = true;

      for(i=0; i<newComments.length(); i++) {
        if(eol) {
          buffer[j++] = '%';
          buffer[j++] = ' ';
          eol = false;
        }

        if(newComments.charAt(i)=='\n')
          eol = true;

        buffer[j++] = newComments.charAt(i);
      }

      comment = String.valueOf(buffer, 0, j);
      comment+=LResources.EOL;
      setModified(true);
    }
  }



  /**
   * @return The latex token corresponding to the specified vertical position.
   * @since 3.0
   */
  public VerticalPosition getPositionVertToken() {
    return positionVertToken;
  }



  /**
   * @param positionVertToken The new vertical position token. Must not be null.
   * @since 3.0
   */
  public void setPositionVertToken(final VerticalPosition positionVertToken) {
    if(positionVertToken!=null) {
      this.positionVertToken = positionVertToken;
      setModified(true);
    }
  }



  /**
   * @return True: the latex drawing will be horizontally centred.
   * @since 3.0
   */
  public boolean isPositionHoriCentre() {
    return positionHoriCentre;
  }



  /**
   * @return the label of the latex drawing.
   * @since 3.0
   */
  public String getLabel() {
    return label;
  }



  /**
   * @param label the new label of the drawing. Must not be null.
   * @since 3.0
   */
  public void setLabel(final String label) {
    if(label!=null) {
      this.label = label;
      setModified(true);
    }
  }



  /**
   * @return the caption of the drawing.
   * @since 3.0
   */
  public String getCaption() {
    return caption;
  }



  /**
   * @param caption the new caption of the drawing. Must not be null.
   * @since 3.0
   */
  public void setCaption(final String caption) {
    if(caption!=null) {
      this.caption = caption;
      setModified(true);
    }
  }



  /**
   * @param positionHoriCentre True: the latex drawing will be horizontally centred.
   * @since 3.0
   */
  public void setPositionHoriCentre(final boolean positionHoriCentre) {
    if(this.positionHoriCentre!=positionHoriCentre) {
      this.positionHoriCentre = positionHoriCentre;
      setModified(true);
    }
  }



  /**
   * Updates the code cache.
   * @since 3.0
   */
  public abstract void update();


  /**
   * Generates a latex code of the drawing only (ie no begin{document} and co).
   * @param pstGen The PST generator to use.
   * @return The latex code.
   * @since 3.0
   */
  public static String getLatexDrawing(final PSTCodeGenerator pstGen) {
    pstGen.updateFull();
    return pstGen.getCache().toString();
  }


  /**
   * Generates a latex document that contains the pstricks code of the given canvas.
   * @param drawing The shapes to export.
   * @param synchronizer The object that synchronises the view and the model.
   * @param pstGen The PST generator to use.
   * @return The latex document or an empty string.
   * @since 3.0
   */
  public static String getLatexDocument(final IDrawing drawing, final ViewsSynchroniserHandler synchronizer, final PSTCodeGenerator pstGen) {
    if(drawing==null || synchronizer==null)
      return ""; //$NON-NLS-1$

    final StringBuilder doc = new StringBuilder();
    final IPoint bl      = synchronizer.getBottomLeftDrawingPoint();
    final IPoint tr      = synchronizer.getTopRightDrawingPoint();
    final float ppc      = synchronizer.getPPCDrawing();
    final float scale    = (float)pstGen.getScale();

    pstGen.updateFull();
    doc.append("\\documentclass{article}").append(LResources.EOL).append("\\pagestyle{empty}").append(LResources.EOL).append(getPackages()).append(LResources.EOL).append( //$NON-NLS-1$ //$NON-NLS-2$
    "\\usepackage[left=0cm,top=0.1cm,right=0cm,bottom=0cm,nohead,nofoot,paperwidth=").append( //$NON-NLS-1$
    tr.getX()/ppc*scale).append("cm,paperheight=").append( //$NON-NLS-1$
    bl.getY()/ppc*scale+0.2).append("cm]{geometry}").append( //$NON-NLS-1$
    LResources.EOL).append("\\usepackage[usenames,dvipsnames]{pstricks}").append(//$NON-NLS-1$
    LResources.EOL).append("\\usepackage{epsfig}").append(//$NON-NLS-1$
    LResources.EOL).append("\\usepackage{pst-grad}").append(LResources.EOL).append("\\usepackage{pst-plot}").append(LResources.EOL).append(//$NON-NLS-1$//$NON-NLS-2$
    "\\begin{document}").append(LResources.EOL).append( //$NON-NLS-1$
    "\\addtolength{\\oddsidemargin}{-0.2in}").append(LResources.EOL).append("\\addtolength{\\evensidemargin}{-0.2in}").append( //$NON-NLS-1$ //$NON-NLS-2$
    LResources.EOL).append(pstGen.getCache()).append(LResources.EOL).append("\\end{document}");//$NON-NLS-1$

    return doc.toString();
  }



  /**
   * Creates a latex file that contains the pstricks code of the given canvas.
   * @param drawing The shapes to export.
   * @param pathExportTex The location where the file must be created.
   * @param synchronizer The object that synchronises the view and the model.
   * @param pstGen The PST generator to use.
   * @return The latex file or null.
   * @since 3.0
   */
  public static File createLatexFile(final IDrawing drawing, final String pathExportTex, final ViewsSynchroniserHandler synchronizer, final PSTCodeGenerator pstGen) {
    if(drawing==null || pathExportTex==null)
      return null;

    boolean ok = true;

    try {
      try(FileOutputStream fos = new FileOutputStream(pathExportTex);
        OutputStreamWriter osw = new OutputStreamWriter(fos)){
        osw.append(getLatexDocument(drawing, synchronizer, pstGen));
      }
    } catch(final IOException ex) { ok = false; }

    return ok ? new File(pathExportTex) : null;
  }



  /**
   * Create a .ps file that corresponds to the compiled latex document containing
   * the pstricks drawing.
   * @param drawing The shapes to export.
   * @param pathExportPs The path of the .ps file to create (MUST ends with .ps).
   * @param synchronizer The object that synchronises the view and the model.
   * @param pstGen The PST generator to use.
   * @return The create file or null.
   * @since 3.0
   */
  public static File createPSFile(final IDrawing drawing, final String pathExportPs, final ViewsSynchroniserHandler synchronizer, final PSTCodeGenerator pstGen){
    return createPSFile(drawing, pathExportPs, synchronizer, null, pstGen);
  }


  /**
   * Create an .eps file that corresponds to the compiled latex document containing the pstricks drawing.
   * @param drawing The shapes to export.
   * @param pathExportEPS The path of the .eps file to create (MUST ends with .eps).
   * @param synchronizer The object that synchronises the view and the model.
   * @param pstGen The PST generator to use.
   * @return The create file or null.
   * @since 3.0
   */
  public static File createEPSFile(final IDrawing drawing, final String pathExportEPS, final ViewsSynchroniserHandler synchronizer, final PSTCodeGenerator pstGen){
    final File tmpDir = LFileUtils.INSTANCE.createTempDir();
    final File psFile = createPSFile(drawing, tmpDir.getAbsolutePath() + LResources.FILE_SEP + "tmpPSFile.ps", synchronizer, tmpDir, pstGen); //$NON-NLS-1$
    final File finalFile = new File(pathExportEPS);
    final File fileEPS = new File(psFile.getAbsolutePath().replace(".ps", EPSFilter.EPS_EXTENSION)); //$NON-NLS-1$
    final String[] paramsLatex = {LSystem.INSTANCE.getSystem().getPS2EPSBinPath(), psFile.getAbsolutePath(), fileEPS.getAbsolutePath()};

    final String log = LSystem.INSTANCE.execute(paramsLatex, tmpDir);
    if(!fileEPS.exists()) {
      BadaboomCollector.INSTANCE.add(new IllegalAccessException(getLatexDocument(drawing, synchronizer, pstGen) + LResources.EOL + log));
      return null;
    }
    LFileUtils.INSTANCE.copy(fileEPS, finalFile);
    psFile.delete();
    fileEPS.delete();
    if(!finalFile.exists()) {
      BadaboomCollector.INSTANCE.add(new IllegalAccessException("Cannot create the EPS file at this location: " + finalFile.getAbsolutePath())); //$NON-NLS-1$
      return null;
    }
    return finalFile;
  }



  /**
   * Create a .ps file that corresponds to the compiled latex document containing
   * the pstricks drawing.
   * @param drawing The shapes to export.
   * @param pathExportPs The path of the .ps file to create (MUST ends with .ps).
   * @param synchronizer The object that synchronises the view and the model.
   * @param tmpDir The temporary directory used for the compilation.
   * @param pstGen The PST generator to use.
   * @return The create file or null.
   * @since 3.0
   */
  public static File createPSFile(final IDrawing drawing, final String pathExportPs, final ViewsSynchroniserHandler synchronizer, final File tmpDir,
      final PSTCodeGenerator pstGen) {
    if(pathExportPs==null)
      return null;

    final int lastSep      = pathExportPs.lastIndexOf(LResources.FILE_SEP)+1;
    final String name      = pathExportPs.substring(lastSep==-1 ? 0 : lastSep, pathExportPs.lastIndexOf(".ps")); //$NON-NLS-1$
    final File tmpDir2    = tmpDir==null ? LFileUtils.INSTANCE.createTempDir() : tmpDir;
    final float scale  = (float)pstGen.getScale();

    if(tmpDir2==null) {
      BadaboomCollector.INSTANCE.add(new FileNotFoundException("Cannot create a temporary folder.")); //$NON-NLS-1$
      return null;
    }

    final String path    = tmpDir2.getAbsolutePath() + LResources.FILE_SEP;
    final File texFile    = createLatexFile(drawing, path + name + TeXFilter.TEX_EXTENSION, synchronizer, pstGen);
    String log;
    File finalPS;
    final IPoint tr    = synchronizer.getTopRightDrawingPoint();
    final IPoint bl    = synchronizer.getBottomLeftDrawingPoint();
    final int ppc      = synchronizer.getPPCDrawing();
    final float dec    = 0.2f;
    final OperatingSystem os = LSystem.INSTANCE.getSystem();

    if(texFile==null || !texFile.exists())
      return null;

    final String[] paramsLatex = {os.getLatexBinPath(), "--interaction=nonstopmode", "--output-directory=" + tmpDir2.getAbsolutePath(),//$NON-NLS-1$//$NON-NLS-2$
        texFile.getAbsolutePath()};
    log    = LSystem.INSTANCE.execute(paramsLatex, tmpDir2);
    final File dviFile = new File(tmpDir2.getAbsolutePath() + LResources.FILE_SEP + name + ".dvi"); //$NON-NLS-1$
    final boolean dviRenamed = dviFile.renameTo(new File(tmpDir2.getAbsolutePath() + LResources.FILE_SEP + name));

    final String[] paramsDvi = {os.getDvipsBinPath(), "-Pdownload35", "-T", //$NON-NLS-1$ //$NON-NLS-2$
        (tr.getX()-bl.getX())/ppc*scale+dec+"cm,"+((bl.getY()-tr.getY())/ppc*scale+dec)+"cm", //$NON-NLS-1$ //$NON-NLS-2$
            name, "-o", pathExportPs}; //$NON-NLS-1$
    log   += LSystem.INSTANCE.execute(paramsDvi, tmpDir2);

    texFile.delete();
    new File(path + name + (dviRenamed ? "" : ".div")).delete()//$NON-NLS-1$ //$NON-NLS-2$
    new File(path + name + ".log").delete();            //$NON-NLS-1$
    new File(path + name + ".aux").delete();            //$NON-NLS-1$

    finalPS = new File(pathExportPs);

    if(!finalPS.exists()) {
      BadaboomCollector.INSTANCE.add(new IllegalAccessException(getLatexDocument(drawing, synchronizer, pstGen) + LResources.EOL + log));
      finalPS = null;
    }

    if(tmpDir==null)
      tmpDir2.delete();

    return finalPS;
  }



  /**
   * Create a .pdf file that corresponds to the compiled latex document containing
   * the pstricks drawing.
   * @param drawing The shapes to export.
   * @param pathExportPdf The path of the .pdf file to create (MUST ends with .pdf).
   * @param synchronizer The object that synchronises the view and the model.
   * @param pstGen The PST generator to use.
   * @return The create file or null.
   * @param crop if true, the output document will be cropped.
   * @since 3.0
   */
  public static File createPDFFile(final IDrawing drawing, final String pathExportPdf, final ViewsSynchroniserHandler synchronizer, final boolean crop,
      final PSTCodeGenerator pstGen) {
    if(pathExportPdf==null)
      return null;

    final File tmpDir = LFileUtils.INSTANCE.createTempDir();

    if(tmpDir==null) {
      BadaboomCollector.INSTANCE.add(new FileNotFoundException("Cannot create a temporary folder.")); //$NON-NLS-1$
      return null;
    }

    final String name = pathExportPdf.substring(pathExportPdf.lastIndexOf(LResources.FILE_SEP)+1, pathExportPdf.lastIndexOf(PDFFilter.PDF_EXTENSION));
    final File psFile = createPSFile(drawing, tmpDir.getAbsolutePath() + LResources.FILE_SEP + name + ".ps", synchronizer, tmpDir, pstGen); //$NON-NLS-1$
    String log;
    File pdfFile;
    final OperatingSystem os = LSystem.INSTANCE.getSystem();

    if(psFile==null)
      return null;

    // On windows, an option must be defined using this format:
    // -optionName#valueOption Thus, the classical = character must be replaced by a # when latexdraw runs on Windows.
    final String optionEmbed = "-dEmbedAllFonts" + (LSystem.INSTANCE.isWindows() ? "#" : "=") + "true"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

    log = LSystem.INSTANCE.execute(new String[] {os.getPs2pdfBinPath(), optionEmbed, psFile.getAbsolutePath(),
              crop ? name + PDFFilter.PDF_EXTENSION : pathExportPdf}, tmpDir);

    if(crop) {
      pdfFile = new File(tmpDir.getAbsolutePath() + LResources.FILE_SEP + name + PDFFilter.PDF_EXTENSION);
      log   = LSystem.INSTANCE.execute(new String[] {os.getPdfcropBinPath(), pdfFile.getAbsolutePath(), pdfFile.getAbsolutePath()}, tmpDir);
      // JAVA7: test pdfFile.toPath().move(pathExportPdf)
      // the renameto method is weak and fails sometimes.
      if(!pdfFile.renameTo(new File(pathExportPdf)) && !LFileUtils.INSTANCE.copy(pdfFile, new File(pathExportPdf)))
        log += " The final pdf document cannot be moved to its final destination. If you use Windows, you must have a Perl interpretor installed, such as strawberryPerl (http://strawberryperl.com/)"; //$NON-NLS-1$
      pdfFile.delete();
    }

    pdfFile = new File(pathExportPdf);
    psFile.delete();

    if(!pdfFile.exists()) {
      BadaboomCollector.INSTANCE.add(new IllegalAccessException(getLatexDocument(drawing, synchronizer, pstGen) + LResources.EOL + log));
      pdfFile = null;
    }

    tmpDir.delete();

    return pdfFile;
  }
}
TOP

Related Classes of net.sf.latexdraw.glib.views.latex.LaTeXGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.