]> git.lyx.org Git - lyx.git/blobdiff - src/graphics/PreviewLoader.cpp
Fix comparing a pointer with a char
[lyx.git] / src / graphics / PreviewLoader.cpp
index 622d5289a2ef6d5684435bffa057e989210730fa..b4d78e0ab5b68503d21445c7a2b652ecda124d90 100644 (file)
 #include "GraphicsCache.h"
 
 #include "Buffer.h"
+#include "BufferParams.h"
 #include "Converter.h"
-#include "debug.h"
+#include "Encoding.h"
 #include "Format.h"
 #include "InsetIterator.h"
-#include "LColor.h"
+#include "LaTeXFeatures.h"
 #include "LyXRC.h"
+#include "output.h"
 #include "OutputParams.h"
-#include "Paragraph.h"
+#include "TexRow.h"
 
 #include "frontends/Application.h" // hexName
 
 #include "insets/Inset.h"
 
+#include "support/convert.h"
+#include "support/debug.h"
+#include "support/FileName.h"
 #include "support/filetools.h"
-#include "support/forkedcall.h"
-#include "support/forkedcontr.h"
+#include "support/ForkedCalls.h"
 #include "support/lstrings.h"
-#include "support/lyxlib.h"
-#include "support/convert.h"
 
-#include <boost/bind.hpp>
+#include "support/bind.h"
 
 #include <sstream>
 #include <fstream>
 #include <iomanip>
 
-using lyx::support::FileName;
-
-using std::endl;
-using std::find;
-using std::fill;
-using std::find_if;
-using std::make_pair;
-
-using boost::bind;
+using namespace std;
+using namespace lyx::support;
 
-using std::ifstream;
-using std::list;
-using std::map;
-using std::ostringstream;
-using std::pair;
-using std::vector;
-using std::string;
 
 
 namespace {
@@ -75,17 +63,15 @@ string const unique_filename(string const & bufferpath)
 {
        static int theCounter = 0;
        string const filename = lyx::convert<string>(theCounter++) + "lyxpreview";
-       return lyx::support::addName(bufferpath, filename);
+       return addName(bufferpath, filename);
 }
 
 
-lyx::Converter const * setConverter()
+lyx::Converter const * setConverter(string const from)
 {
-       string const from = "lyxpreview";
-
        typedef vector<string> FmtList;
        typedef lyx::graphics::Cache GCache;
-       FmtList const loadableFormats = GCache::get().loadableFormats();
+       FmtList const loadableFormats = GCache::get().loadableFormats();
        FmtList::const_iterator it = loadableFormats.begin();
        FmtList::const_iterator const end = loadableFormats.end();
 
@@ -102,10 +88,8 @@ lyx::Converter const * setConverter()
        static bool first = true;
        if (first) {
                first = false;
-               lyx::lyxerr << "PreviewLoader::startLoading()\n"
-                      << "No converter from \"lyxpreview\" format has been "
-                       "defined."
-                      << endl;
+               LYXERR0("PreviewLoader::startLoading()\n"
+                       << "No converter from \"" << from << "\" format has been defined.");
        }
        return 0;
 }
@@ -122,9 +106,8 @@ void setAscentFractions(vector<double> & ascent_fractions,
 
        ifstream in(metrics_file.toFilesystemEncoding().c_str());
        if (!in.good()) {
-               lyx::lyxerr[lyx::Debug::GRAPHICS]
-                       << "setAscentFractions(" << metrics_file << ")\n"
-                       << "Unable to open file!" << endl;
+               LYXERR(lyx::Debug::GRAPHICS, "setAscentFractions(" << metrics_file << ")\n"
+                       << "Unable to open file!");
                return;
        }
 
@@ -157,20 +140,17 @@ void setAscentFractions(vector<double> & ascent_fractions,
        }
 
        if (error) {
-               lyx::lyxerr[lyx::Debug::GRAPHICS]
-                       << "setAscentFractions(" << metrics_file << ")\n"
-                       << "Error reading file!\n" << endl;
+               LYXERR(lyx::Debug::GRAPHICS, "setAscentFractions(" << metrics_file << ")\n"
+                       << "Error reading file!\n");
        }
 }
 
 
-class FindFirst : public std::unary_function<SnippetPair, bool> {
+class FindFirst
+{
 public:
        FindFirst(string const & comp) : comp_(comp) {}
-       bool operator()(SnippetPair const & sp) const
-       {
-               return sp.first == comp_;
-       }
+       bool operator()(SnippetPair const & sp) const { return sp.first == comp_; }
 private:
        string const comp_;
 };
@@ -207,7 +187,6 @@ typedef InProgressProcesses::value_type InProgressProcess;
 
 
 namespace lyx {
-
 namespace graphics {
 
 class PreviewLoader::Impl : public boost::signals::trackable {
@@ -224,8 +203,9 @@ public:
        void add(string const & latex_snippet);
        ///
        void remove(string const & latex_snippet);
-       ///
-       void startLoading();
+       /// \p wait whether to wait for the process to complete or, instead,
+       /// to do it in the background.
+       void startLoading(bool wait = false);
 
        /// Emit this signal when an image is ready for display.
        boost::signal<void(PreviewImage const &)> imageReady;
@@ -233,17 +213,17 @@ public:
        Buffer const & buffer() const { return buffer_; }
 
 private:
-       /// Called by the Forkedcall process that generated the bitmap files.
+       /// Called by the ForkedCall process that generated the bitmap files.
        void finishedGenerating(pid_t, int);
        ///
-       void dumpPreamble(odocstream &) const;
+       void dumpPreamble(otexstream &) const;
        ///
        void dumpData(odocstream &, BitmapFile const &) const;
 
        /** cache_ allows easy retrieval of already-generated images
         *  using the LaTeX snippet as the identifier.
         */
-       typedef boost::shared_ptr<PreviewImage> PreviewImagePtr;
+       typedef shared_ptr<PreviewImage> PreviewImagePtr;
        ///
        typedef map<string, PreviewImagePtr> Cache;
        ///
@@ -264,8 +244,6 @@ private:
        PreviewLoader & parent_;
        ///
        Buffer const & buffer_;
-       ///
-       double font_scaling_factor_;
 
        /// We don't own this
        static lyx::Converter const * pconverter_;
@@ -285,7 +263,9 @@ PreviewLoader::PreviewLoader(Buffer const & b)
 
 
 PreviewLoader::~PreviewLoader()
-{}
+{
+       delete pimpl_;
+}
 
 
 PreviewImage const * PreviewLoader::preview(string const & latex_snippet) const
@@ -312,9 +292,9 @@ void PreviewLoader::remove(string const & latex_snippet) const
 }
 
 
-void PreviewLoader::startLoading() const
+void PreviewLoader::startLoading(bool wait) const
 {
-       pimpl_->startLoading();
+       pimpl_->startLoading(wait);
 }
 
 
@@ -371,14 +351,14 @@ InProgress::InProgress(string const & filename_base,
                       PendingSnippets const & pending,
                       string const & to_format)
        : pid(0),
-         metrics_file(FileName(filename_base + ".metrics")),
+         metrics_file(filename_base + ".metrics"),
          snippets(pending.size())
 {
        PendingSnippets::const_iterator pit  = pending.begin();
        PendingSnippets::const_iterator pend = pending.end();
        BitmapFile::iterator sit = snippets.begin();
 
-       std::transform(pit, pend, sit,
+       transform(pit, pend, sit,
                       IncrementedFileName(to_format, filename_base));
 }
 
@@ -386,16 +366,16 @@ InProgress::InProgress(string const & filename_base,
 void InProgress::stop() const
 {
        if (pid)
-               lyx::support::ForkedcallsController::get().kill(pid, 0);
+               ForkedCallsController::kill(pid, 0);
 
        if (!metrics_file.empty())
-               lyx::support::unlink(metrics_file);
+               metrics_file.removeFile();
 
        BitmapFile::const_iterator vit  = snippets.begin();
        BitmapFile::const_iterator vend = snippets.end();
        for (; vit != vend; ++vit) {
                if (!vit->second.empty())
-                       lyx::support::unlink(vit->second);
+                       vit->second.removeFile();
        }
 }
 
@@ -406,16 +386,10 @@ namespace lyx {
 namespace graphics {
 
 PreviewLoader::Impl::Impl(PreviewLoader & p, Buffer const & b)
-       : parent_(p), buffer_(b), font_scaling_factor_(0.0)
+       : parent_(p), buffer_(b)
 {
-       font_scaling_factor_ = 0.01 * lyxrc.dpi * lyxrc.zoom *
-               convert<double>(lyxrc.preview_scale_factor);
-
-       LYXERR(Debug::GRAPHICS) << "The font scaling factor is "
-                               << font_scaling_factor_ << endl;
-
        if (!pconverter_)
-               pconverter_ = setConverter();
+               pconverter_ = setConverter("lyxpreview");
 }
 
 
@@ -424,9 +398,8 @@ PreviewLoader::Impl::~Impl()
        InProgressProcesses::iterator ipit  = in_progress_.begin();
        InProgressProcesses::iterator ipend = in_progress_.end();
 
-       for (; ipit != ipend; ++ipit) {
+       for (; ipit != ipend; ++ipit)
                ipit->second.stop();
-       }
 }
 
 
@@ -440,7 +413,7 @@ PreviewLoader::Impl::preview(string const & latex_snippet) const
 
 namespace {
 
-class FindSnippet : public std::unary_function<InProgressProcess, bool> {
+class FindSnippet {
 public:
        FindSnippet(string const & s) : snippet_(s) {}
        bool operator()(InProgressProcess const & process) const
@@ -487,11 +460,11 @@ void PreviewLoader::Impl::add(string const & latex_snippet)
        if (!pconverter_ || status(latex_snippet) != NotFound)
                return;
 
-       string const snippet = support::trim(latex_snippet);
+       string const snippet = trim(latex_snippet);
        if (snippet.empty())
                return;
 
-       LYXERR(Debug::GRAPHICS) << "adding snippet:\n" << snippet << endl;
+       LYXERR(Debug::GRAPHICS, "adding snippet:\n" << snippet);
 
        pending_.push_back(snippet);
 }
@@ -534,7 +507,7 @@ void PreviewLoader::Impl::remove(string const & latex_snippet)
        InProgressProcesses::iterator ipit  = in_progress_.begin();
        InProgressProcesses::iterator ipend = in_progress_.end();
 
-       std::for_each(ipit, ipend, EraseSnippet(latex_snippet));
+       for_each(ipit, ipend, EraseSnippet(latex_snippet));
 
        while (ipit != ipend) {
                InProgressProcesses::iterator curr = ipit++;
@@ -544,16 +517,16 @@ void PreviewLoader::Impl::remove(string const & latex_snippet)
 }
 
 
-void PreviewLoader::Impl::startLoading()
+void PreviewLoader::Impl::startLoading(bool wait)
 {
        if (pending_.empty() || !pconverter_)
                return;
 
        // Only start the process off after the buffer is loaded from file.
-       if (!buffer_.fully_loaded())
+       if (!buffer_.isFullyLoaded())
                return;
 
-       LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()" << endl;
+       LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()");
 
        // As used by the LaTeX file and by the resulting image files
        string const directory = buffer_.temppath();
@@ -570,45 +543,101 @@ void PreviewLoader::Impl::startLoading()
        // Output the LaTeX file.
        FileName const latexfile(filename_base + ".tex");
 
-       // FIXME UNICODE
-       // This creates an utf8 encoded file, but the proper inputenc
-       // command is missing.
-       odocfstream of(latexfile.toFilesystemEncoding().c_str());
+       // we use the encoding of the buffer
+       Encoding const & enc = buffer_.params().encoding();
+       ofdocstream of;
+       try { of.reset(enc.iconvName()); }
+       catch (iconv_codecvt_facet_exception const & e) {
+               LYXERR0("Caught iconv exception: " << e.what()
+                       << "\nUnable to create LaTeX file: " << latexfile);
+               return;
+       }
+
+       TexRow texrow;
+       otexstream os(of, texrow);
+       OutputParams runparams(&enc);
+       LaTeXFeatures features(buffer_, buffer_.params(), runparams);
+
+       if (!openFileWrite(of, latexfile))
+               return;
+
        if (!of) {
-               LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n"
-                                       << "Unable to create LaTeX file\n"
-                                       << latexfile << endl;
+               LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
+                                       << "Unable to create LaTeX file\n" << latexfile);
                return;
        }
        of << "\\batchmode\n";
-       dumpPreamble(of);
+       dumpPreamble(os);
+       // handle inputenc etc.
+       buffer_.params().writeEncodingPreamble(os, features);
        of << "\n\\begin{document}\n";
        dumpData(of, inprogress.snippets);
        of << "\n\\end{document}\n";
        of.close();
+       if (of.fail()) {
+               LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
+                                        << "File was not closed properly.");
+               return;
+       }
 
+       double const font_scaling_factor = 
+               buffer_.isExporting() ? 75.0 * buffer_.params().html_math_img_scale 
+                       : 0.01 * lyxrc.dpi * lyxrc.zoom * lyxrc.preview_scale_factor;
+       
        // The conversion command.
        ostringstream cs;
-       cs << pconverter_->command << ' ' << pconverter_->to << ' '
-          << support::quoteName(latexfile.toFilesystemEncoding()) << ' '
-          << int(font_scaling_factor_) << ' '
-          << theApp()->hexName(LColor::preview) << ' '
-          << theApp()->hexName(LColor::background);
+       cs << pconverter_->command
+          << " " << quoteName(latexfile.toFilesystemEncoding())
+          << " --dpi " << int(font_scaling_factor);
+
+       // FIXME XHTML 
+       // The colors should be customizable.
+       if (!buffer_.isExporting()) {
+               ColorCode const fg = PreviewLoader::foregroundColor();
+               ColorCode const bg = PreviewLoader::backgroundColor();
+               cs << " --fg " << theApp()->hexName(fg) 
+                  << " --bg " << theApp()->hexName(bg);
+       }
 
-       string const command = support::libScriptSearch(cs.str());
+       // FIXME what about LuaTeX?
+       if (buffer_.params().useNonTeXFonts)
+               cs << " --latex=xelatex";
+       if (buffer_.params().encoding().package() == Encoding::japanese)
+               cs << " --latex=platex";
+       if (buffer_.params().bibtex_command != "default")
+               cs << " --bibtex=" << quoteName(buffer_.params().bibtex_command);
+       else if (buffer_.params().encoding().package() == Encoding::japanese)
+               cs << " --bibtex=" << quoteName(lyxrc.jbibtex_command);
+       else
+               cs << " --bibtex=" << quoteName(lyxrc.bibtex_command);
+       if (buffer_.params().bufferFormat() == "lilypond-book")
+               cs << " --lilypond";
+
+       string const command = libScriptSearch(cs.str());
+
+       if (wait) {
+               ForkedCall call(buffer_.filePath());
+               int ret = call.startScript(ForkedProcess::Wait, command);
+               static int fake = (2^20) + 1;
+               int pid = fake++;
+               inprogress.pid = pid;
+               inprogress.command = command;
+               in_progress_[pid] = inprogress;
+               finishedGenerating(pid, ret);
+               return;
+       }
 
        // Initiate the conversion from LaTeX to bitmap images files.
-       support::Forkedcall::SignalTypePtr
-               convert_ptr(new support::Forkedcall::SignalType);
+       ForkedCall::SignalTypePtr
+               convert_ptr(new ForkedCall::SignalType);
        convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
 
-       support::Forkedcall call;
-       int ret = call.startscript(command, convert_ptr);
+       ForkedCall call(buffer_.filePath());
+       int ret = call.startScript(command, convert_ptr);
 
        if (ret != 0) {
-               LYXERR(Debug::GRAPHICS) << "PreviewLoader::startLoading()\n"
-                                       << "Unable to start process\n"
-                                       << command << endl;
+               LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
+                                       << "Unable to start process\n" << command);
                return;
        }
 
@@ -631,9 +660,9 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval)
 
        string const command = git->second.command;
        string const status = retval > 0 ? "failed" : "succeeded";
-       LYXERR(Debug::GRAPHICS) << "PreviewLoader::finishedInProgress("
+       LYXERR(Debug::GRAPHICS, "PreviewLoader::finishedInProgress("
                                << retval << "): processing " << status
-                               << " for " << command << endl;
+                               << " for " << command);
        if (retval > 0)
                return;
 
@@ -646,7 +675,7 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval)
        BitmapFile::const_iterator it  = git->second.snippets.begin();
        BitmapFile::const_iterator end = git->second.snippets.end();
 
-       std::list<PreviewImagePtr> newimages;
+       list<PreviewImagePtr> newimages;
 
        int metrics_counter = 0;
        for (; it != end; ++it, ++metrics_counter) {
@@ -654,19 +683,23 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval)
                FileName const & file = it->second;
                double af = ascent_fractions[metrics_counter];
 
-               PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af));
-               cache_[snip] = ptr;
+               // Add the image to the cache only if it's actually present
+               if (file.isReadableFile()) {
+                       PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af));
+                       cache_[snip] = ptr;
+
+                       newimages.push_back(ptr);
+               }
 
-               newimages.push_back(ptr);
        }
 
        // Remove the item from the list of still-executing processes.
        in_progress_.erase(git);
 
        // Tell the outside world
-       std::list<PreviewImagePtr>::const_reverse_iterator
+       list<PreviewImagePtr>::const_reverse_iterator
                nit  = newimages.rbegin();
-       std::list<PreviewImagePtr>::const_reverse_iterator
+       list<PreviewImagePtr>::const_reverse_iterator
                nend = newimages.rend();
        for (; nit != nend; ++nit) {
                imageReady(*nit->get());
@@ -674,19 +707,19 @@ void PreviewLoader::Impl::finishedGenerating(pid_t pid, int retval)
 }
 
 
-void PreviewLoader::Impl::dumpPreamble(odocstream & os) const
+void PreviewLoader::Impl::dumpPreamble(otexstream & os) const
 {
-       // Why on earth is Buffer::makeLaTeXFile a non-const method?
-       Buffer & tmp = const_cast<Buffer &>(buffer_);
        // Dump the preamble only.
-       // We don't need an encoding for runparams since it is not used by
-       // the preamble.
-       OutputParams runparams(0);
-       runparams.flavor = OutputParams::LATEX;
+       OutputParams runparams(&buffer_.params().encoding());
+       if (buffer_.params().useNonTeXFonts)
+               runparams.flavor = OutputParams::XETEX;
+       else
+               runparams.flavor = OutputParams::LATEX;
        runparams.nice = true;
        runparams.moving_arg = true;
        runparams.free_spacing = true;
-       tmp.writeLaTeXSource(os, buffer_.filePath(), runparams, true, false);
+       runparams.is_child = buffer_.parent();
+       buffer_.writeLaTeXSource(os, buffer_.filePath(), runparams, Buffer::OnlyPreamble);
 
        // FIXME! This is a HACK! The proper fix is to control the 'true'
        // passed to WriteStream below:
@@ -701,15 +734,6 @@ void PreviewLoader::Impl::dumpPreamble(odocstream & os) const
           << "\\def\\lyxlock{}\n"
           << "\n";
 
-       // Loop over the insets in the buffer and dump all the math-macros.
-       InsetBase & inset = buffer_.inset();
-       InsetIterator it = inset_iterator_begin(inset);
-       InsetIterator const end = inset_iterator_end(inset);
-
-       for (; it != end; ++it)
-               if (it->lyxCode() == InsetBase::MATHMACRO_CODE)
-                       it->latex(buffer_, os, runparams);
-
        // All equation labels appear as "(#)" + preview.sty's rendering of
        // the label name
        if (lyxrc.preview_hashed_labels)
@@ -717,8 +741,10 @@ void PreviewLoader::Impl::dumpPreamble(odocstream & os) const
 
        // Use the preview style file to ensure that each snippet appears on a
        // fresh page.
+       // Also support PDF output (automatically generated e.g. when
+       // \usepackage[pdftex]{hyperref} is used and XeTeX.
        os << "\n"
-          << "\\usepackage[active,delayed,dvips,showlabels,lyx]{preview}\n"
+          << "\\usepackage[active,delayed,showlabels,lyx]{preview}\n"
           << "\n";
 }
 
@@ -742,4 +768,3 @@ void PreviewLoader::Impl::dumpData(odocstream & os,
 
 } // namespace graphics
 } // namespace lyx
-