]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
More notes.
[lyx.git] / src / Buffer.cpp
index e2618b43dcd8328539ed2850e9f76c397352c6d8..bd7305701785929e0afe9bc9cb65aa89cb375e28 100644 (file)
@@ -127,7 +127,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 370; // uwestoehr: option to suppress default date
+int const LYX_FORMAT = 374; // rgheck: HTML output options
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -147,7 +147,7 @@ class BufferSet : public std::set<Buffer const *> {};
 class Buffer::Impl
 {
 public:
-       Impl(Buffer & parent, FileName const & file, bool readonly);
+       Impl(Buffer & parent, FileName const & file, bool readonly, Buffer const * cloned_buffer);
 
        ~Impl()
        {
@@ -258,9 +258,15 @@ public:
                        LYXERR0("Warning: a buffer should not have two parents!");
                parent_buffer = pb;
        }
+
+       /// If non zero, this buffer is a clone of existing buffer \p cloned_buffer_
+       /// This one is useful for preview detached in a thread.
+       Buffer const * cloned_buffer_;
+
 private:
        /// So we can force access via the accessors.
        mutable Buffer const * parent_buffer;
+
 };
 
 
@@ -283,26 +289,36 @@ static FileName createBufferTmpDir()
 }
 
 
-Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
+Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_,
+       Buffer const * cloned_buffer)
        : lyx_clean(true), bak_clean(true), unnamed(false),
          read_only(readonly_), filename(file), file_fully_loaded(false),
          toc_backend(&parent), macro_lock(false), timestamp_(0),
          checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false),
-         parent_buffer(0)
+         cloned_buffer_(cloned_buffer), parent_buffer(0)
 {
-       temppath = createBufferTmpDir();
-       lyxvc.setBuffer(&parent);
-       if (use_gui)
-               wa_ = new frontend::WorkAreaManager;
+       if (!cloned_buffer_) {
+               temppath = createBufferTmpDir();
+               lyxvc.setBuffer(&parent);
+               if (use_gui)
+                       wa_ = new frontend::WorkAreaManager;
+               return;
+       }
+       temppath = cloned_buffer_->d->temppath;
+       file_fully_loaded = true;
+       params = cloned_buffer_->d->params;
 }
 
 
-Buffer::Buffer(string const & file, bool readonly)
-       : d(new Impl(*this, FileName(file), readonly)), gui_(0)
+Buffer::Buffer(string const & file, bool readonly, Buffer const * cloned_buffer)
+       : d(new Impl(*this, FileName(file), readonly, cloned_buffer)), gui_(0)
 {
        LYXERR(Debug::INFO, "Buffer::Buffer()");
-
-       d->inset = new InsetText(*this);
+       if (cloned_buffer) {
+               d->inset = static_cast<InsetText *>(cloned_buffer->d->inset->clone());
+               d->inset->setBuffer(*this);
+       } else 
+               d->inset = new InsetText(this);
        d->inset->setAutoBreakRows(true);
        d->inset->getText(0)->setMacrocontextPosition(par_iterator_begin());
 }
@@ -336,14 +352,14 @@ Buffer::~Buffer()
        if (!isClean()) {
                docstring msg = _("LyX attempted to close a document that had unsaved changes!\n");
                msg += emergencyWrite();
-               frontend::Alert::warning(_("Attempting to close changed document!"), msg);
+               Alert::warning(_("Attempting to close changed document!"), msg);
        }
                
        // clear references to children in macro tables
        d->children_positions.clear();
        d->position_to_children.clear();
 
-       if (!d->temppath.destroyDirectory()) {
+       if (!d->cloned_buffer_ && !d->temppath.destroyDirectory()) {
                Alert::warning(_("Could not remove temporary directory"),
                        bformat(_("Could not remove the temporary directory %1$s"),
                        from_utf8(d->temppath.absFilename())));
@@ -356,6 +372,18 @@ Buffer::~Buffer()
 }
 
 
+Buffer * Buffer::clone() const
+{
+       return new Buffer(fileName().absFilename(), false, this);
+}
+
+
+bool Buffer::isClone() const
+{
+       return d->cloned_buffer_;
+}
+
+
 void Buffer::changed() const
 {
        if (d->wa_)
@@ -705,6 +733,7 @@ bool Buffer::readDocument(Lexer & lex)
        // read main text
        bool const res = text().read(lex, errorList, d->inset);
 
+       usermacros.clear();
        updateMacros();
        updateMacroInstances();
        return res;
@@ -1416,14 +1445,15 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 {
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
+       updateLabels(UpdateMaster, true);
 
        d->texrow.reset();
 
        if (!only_body) {
-               os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" <<
-                       " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
+               os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+               os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\">\n";
                // FIXME Language should be set properly.
-               os << "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n";
+               os << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
                // FIXME Header
                os << "<head>\n";
                // FIXME Presumably need to set this right
@@ -1431,21 +1461,24 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
                // FIXME Get this during validation? What about other meta-data?
                os << "<title>TBA</title>\n";
 
-               os << features.getTClassHTMLPreamble();
-
-               os << '\n';
+               os << "\n<!-- Text Class Preamble -->\n"
+                       << features.getTClassHTMLPreamble()
+                       << "\n<!-- Premable Snippets -->\n"
+                       << from_utf8(features.getPreambleSnippets());
 
+               os << "\n<!-- Layout-provided Styles -->\n";
                docstring const styleinfo = features.getTClassHTMLStyles();
                if (!styleinfo.empty()) {
-                       os << "<style type='text/css'>\n";
-                       os << styleinfo;
-                       os << "</style>\n";
+                       os << "<style type='text/css'>\n"
+                               << styleinfo
+                               << "</style>\n";
                }
                os << "</head>\n<body>\n";
        }
 
+       XHTMLStream xs(os);
        params().documentClass().counters().reset();
-       xhtmlParagraphs(text(), *this, os, runparams);
+       xhtmlParagraphs(text(), *this, xs, runparams);
        if (!only_body)
                os << "</body>\n</html>\n";
 }
@@ -1636,6 +1669,21 @@ void Buffer::markDepClean(string const & name)
 }
 
 
+bool Buffer::isExportableFormat(string const & format) const
+{
+               typedef vector<Format const *> Formats;
+               Formats formats;
+               formats = exportableFormats(true);
+               Formats::const_iterator fit = formats.begin();
+               Formats::const_iterator end = formats.end();
+               for (; fit != end ; ++fit) {
+                       if ((*fit)->name() == format)
+                               return true;
+               }
+               return false;
+}
+
+
 bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
        if (isInternal()) {
@@ -1671,27 +1719,6 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        break;
                }
 
-               case LFUN_MASTER_BUFFER_UPDATE:
-               case LFUN_MASTER_BUFFER_VIEW: 
-                       enable = parent() != 0;
-                       break;
-               case LFUN_BUFFER_UPDATE:
-               case LFUN_BUFFER_VIEW: {
-                       string format = to_utf8(cmd.argument());
-                       if (cmd.argument().empty())
-                               format = getDefaultOutputFormat();
-                       typedef vector<Format const *> Formats;
-                       Formats formats;
-                       formats = exportableFormats(true);
-                       Formats::const_iterator fit = formats.begin();
-                       Formats::const_iterator end = formats.end();
-                       enable = false;
-                       for (; fit != end ; ++fit) {
-                               if ((*fit)->name() == format)
-                                       enable = true;
-                       }
-                       break;
-               }
                case LFUN_BUFFER_CHKTEX:
                        enable = isLatex() && !lyxrc.chktex_command.empty();
                        break;
@@ -1757,11 +1784,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
 
        case LFUN_BUFFER_EXPORT: {
-               if (argument == "custom") {
-                       lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
-                       break;
-               }
-               doExport(argument, false);
                bool success = doExport(argument, false);
                dr.setError(success);
                if (!success)
@@ -1770,38 +1792,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
-       case LFUN_BUFFER_UPDATE: {
-               string format = argument;
-               if (argument.empty())
-                       format = getDefaultOutputFormat();
-               doExport(format, true);
-               break;
-       }
-
-       case LFUN_BUFFER_VIEW: {
-               string format = argument;
-               if (argument.empty())
-                       format = getDefaultOutputFormat();
-               preview(format);
-               break;
-       }
-
-       case LFUN_MASTER_BUFFER_UPDATE: {
-               string format = argument;
-               if (argument.empty())
-                       format = masterBuffer()->getDefaultOutputFormat();
-               masterBuffer()->doExport(format, true);
-               break;
-       }
-
-       case LFUN_MASTER_BUFFER_VIEW: {
-               string format = argument;
-               if (argument.empty())
-                       format = masterBuffer()->getDefaultOutputFormat();
-               masterBuffer()->preview(format);
-               break;
-       }
-
        case LFUN_BUILD_PROGRAM:
                doExport("program", true);
                break;
@@ -2341,9 +2331,8 @@ DocIterator Buffer::firstChildPosition(Buffer const * child)
 }
 
 
-std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
+void Buffer::getChildren(std::vector<Buffer *> & clist, bool grand_children) const
 {
-       std::vector<Buffer *> clist;
        // loop over children
        Impl::BufferPositionMap::iterator it = d->children_positions.begin();
        Impl::BufferPositionMap::iterator end = d->children_positions.end();
@@ -2358,7 +2347,14 @@ std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
                                clist.push_back(*git);
                }
        }
-       return clist;
+}
+
+
+std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
+{
+       std::vector<Buffer *> v;
+       getChildren(v, grand_children);
+       return v;
 }
 
 
@@ -2651,14 +2647,11 @@ void Buffer::updateMacroInstances() const
        LYXERR(Debug::MACROS, "updateMacroInstances for "
                << d->filename.onlyFileName());
        DocIterator it = doc_iterator_begin(this);
-       DocIterator end = doc_iterator_end(this);
-       for (; it != end; it.forwardPos()) {
-               // look for MathData cells in InsetMathNest insets
-               Inset * inset = it.nextInset();
-               if (!inset)
-                       continue;
-
-               InsetMath * minset = inset->asInsetMath();
+       it.forwardInset();
+       DocIterator const end = doc_iterator_end(this);
+       for (; it != end; it.forwardInset()) {
+               // look for MathData cells in InsetMathNest insets
+               InsetMath * minset = it.nextInset()->asInsetMath();
                if (!minset)
                        continue;
 
@@ -2963,6 +2956,15 @@ private:
 
 int AutoSaveBuffer::generateChild()
 {
+#if defined(__APPLE__)
+       /* FIXME fork() is not usable for autosave on Mac OS X 10.6 (snow leopard) 
+        *   We should use something else like threads.
+        *
+        * Since I do not know how to determine at run time what is the OS X
+        * version, I just disable forking altogether for now (JMarc)
+        */
+       pid_t const pid = -1;
+#else
        // tmp_ret will be located (usually) in /tmp
        // will that be a problem?
        // Note that this calls ForkedCalls::fork(), so it's
@@ -2972,6 +2974,7 @@ int AutoSaveBuffer::generateChild()
        // you should set pid to -1, and comment out the fork.
        if (pid != 0 && pid != -1)
                return pid;
+#endif
 
        // pid = -1 signifies that lyx was unable
        // to fork. But we will do the save
@@ -3110,14 +3113,18 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                                path = p;
                        }
                }
-               if (!path.empty())
-                       runparams.flavor = theConverters().getFlavor(path);
-               else {
-                       Alert::error(_("Couldn't export file"),
-                               bformat(_("No information for exporting the format %1$s."),
-                                  formats.prettyName(format)));
+               if (path.empty()) {
+                       if (!put_in_tempdir) {
+                               // Only show this alert if this is an export to a non-temporary
+                               // file (not for previewing).
+                               Alert::error(_("Couldn't export file"), bformat(
+                                       _("No information for exporting the format %1$s."),
+                                       formats.prettyName(format)));
+                       }
                        return false;
                }
+               runparams.flavor = theConverters().getFlavor(path);
+
        } else {
                backend_format = format;
                // FIXME: Don't hardcode format names here, but use a flag
@@ -3134,8 +3141,10 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        updateMacroInstances();
 
        // Plain text backend
-       if (backend_format == "text")
+       if (backend_format == "text") {
+               runparams.flavor = OutputParams::TEXT;
                writePlaintextFile(*this, FileName(filename), runparams);
+       }
        // HTML backend
        else if (backend_format == "xhtml") {
                runparams.flavor = OutputParams::HTML;
@@ -3252,7 +3261,7 @@ bool Buffer::isExportable(string const & format) const
 
 vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
 {
-       vector<string> backs = backends();
+       vector<string> const backs = backends();
        vector<Format const *> result =
                theConverters().getReachable(backs[0], only_viewable, true);
        for (vector<string>::const_iterator it = backs.begin() + 1;
@@ -3268,14 +3277,12 @@ vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
 vector<string> Buffer::backends() const
 {
        vector<string> v;
-       if (params().baseClass()->isTeXClassAvailable()) {
-               v.push_back(bufferFormat());
-               // FIXME: Don't hardcode format names here, but use a flag
-               if (v.back() == "latex")
-                       v.push_back("pdflatex");
-       }
-       v.push_back("text");
+       v.push_back(bufferFormat());
+       // FIXME: Don't hardcode format names here, but use a flag
+       if (v.back() == "latex")
+               v.push_back("pdflatex");
        v.push_back("xhtml");
+       v.push_back("text");
        v.push_back("lyx");
        return v;
 }
@@ -3429,7 +3436,7 @@ void Buffer::setBuffersForInsets() const
 }
 
 
-void Buffer::updateLabels(UpdateScope scope) const
+void Buffer::updateLabels(UpdateScope scope, bool out) const
 {
        // Use the master text class also for child documents
        Buffer const * const master = masterBuffer();
@@ -3443,7 +3450,7 @@ void Buffer::updateLabels(UpdateScope scope) const
                // If this is a child document start with the master
                if (master != this) {
                        bufToUpdate.insert(this);
-                       master->updateLabels();
+                       master->updateLabels(UpdateMaster, out);
                        // Do this here in case the master has no gui associated with it. Then, 
                        // the TocModel is not updated and TocModel::toc_ is invalid (bug 5699).
                        if (!master->gui_)
@@ -3471,7 +3478,7 @@ void Buffer::updateLabels(UpdateScope scope) const
 
        // do the real work
        ParIterator parit = cbuf.par_iterator_begin();
-       updateLabels(parit);
+       updateLabels(parit, out);
 
        if (master != this)
                // TocBackend update will be done later.
@@ -3553,9 +3560,9 @@ static bool needEnumCounterReset(ParIterator const & it)
 
 
 // set the label of a paragraph. This includes the counters.
-static void setLabel(Buffer const & buf, ParIterator & it)
+void Buffer::setLabel(ParIterator & it) const
 {
-       BufferParams const & bp = buf.masterBuffer()->params();
+       BufferParams const & bp = this->masterBuffer()->params();
        DocumentClass const & textclass = bp.documentClass();
        Paragraph & par = it.paragraph();
        Layout const & layout = par.layout();
@@ -3563,7 +3570,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
 
        if (par.params().startOfAppendix()) {
                // FIXME: only the counter corresponding to toplevel
-               // sectionning should be reset
+               // sectioning should be reset
                counters.reset();
                counters.appendix(true);
        }
@@ -3651,9 +3658,9 @@ static void setLabel(Buffer const & buf, ParIterator & it)
                string const & type = counters.current_float();
                docstring full_label;
                if (type.empty())
-                       full_label = buf.B_("Senseless!!! ");
+                       full_label = this->B_("Senseless!!! ");
                else {
-                       docstring name = buf.B_(textclass.floats().getType(type).name());
+                       docstring name = this->B_(textclass.floats().getType(type).name());
                        if (counters.hasCounter(from_utf8(type))) {
                                string const & lang = par.getParLanguage(bp)->code();
                                counters.step(from_utf8(type));
@@ -3682,7 +3689,7 @@ static void setLabel(Buffer const & buf, ParIterator & it)
 }
 
 
-void Buffer::updateLabels(ParIterator & parit) const
+void Buffer::updateLabels(ParIterator & parit, bool out) const
 {
        LASSERT(parit.pit() == 0, /**/);
 
@@ -3700,14 +3707,14 @@ void Buffer::updateLabels(ParIterator & parit) const
                maxdepth = parit->getMaxDepthAfter();
 
                // set the counter for this paragraph
-               setLabel(*this, parit);
+               setLabel(parit);
 
                // Now the insets
                InsetList::const_iterator iit = parit->insetList().begin();
                InsetList::const_iterator end = parit->insetList().end();
                for (; iit != end; ++iit) {
                        parit.pos() = iit->pos;
-                       iit->inset->updateLabels(parit);
+                       iit->inset->updateLabels(parit, out);
                }
        }
 }
@@ -3724,15 +3731,26 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
        DocIterator const end = doc_iterator_end(this);
        for (; from != end; from.forwardPos()) {
                // We are only interested in text so remove the math CursorSlice.
-               while (from.inMathed())
-                       from.forwardInset();
+               while (from.inMathed()) {
+                       from.pop_back();
+                       from.pos()++;
+               }
+               // If from is at the end of the document (which is possible
+               // when leaving the mathed) LyX will crash later.
+               if (from == end)
+                       break;
                to = from;
                if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) {
                        word_lang = wl;
                        break;
                }
-               from = to;
-               ++progress;
+
+               // Do not increase progress when from == to, otherwise the word
+               // count will be wrong.
+               if (from != to) {
+                       from = to;
+                       ++progress;
+               }
        }
        return progress;
 }