]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Get rid of all-insets-toggle and explain how to replace it with inset-forall.
[lyx.git] / src / Buffer.cpp
index 7aa037a580107408d659cd31f0c7745c8bdc2ffb..a28a458f9695018fa2234a81ea90c87fe6578197 100644 (file)
@@ -126,7 +126,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 377; // uwestoehr: support for multirows
+int const LYX_FORMAT = 385; // uwestoehr: support to change the shaded box color
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -278,7 +278,8 @@ public:
        }
        ///
        void setParent(Buffer const * pb) {
-               if (parent_buffer && pb && parent_buffer != pb)
+               if (!cloned_buffer_ 
+                   && parent_buffer && pb && parent_buffer != pb)
                        LYXERR0("Warning: a buffer should not have two parents!");
                parent_buffer = pb;
        }
@@ -667,6 +668,15 @@ int Buffer::readHeader(Lexer & lex)
        params().pdfoptions().clear();
        params().indiceslist().clear();
        params().backgroundcolor = lyx::rgbFromHexName("#ffffff");
+       params().isbackgroundcolor = false;
+       params().fontcolor = lyx::rgbFromHexName("#000000");
+       params().isfontcolor = false;
+       params().notefontcolor = lyx::rgbFromHexName("#cccccc");
+       lyx::dispatch(FuncRequest(LFUN_SET_COLOR,
+               from_utf8("greyedouttext #cccccc")));
+       params().boxbgcolor = lyx::rgbFromHexName("#ff0000");
+       lyx::dispatch(FuncRequest(LFUN_SET_COLOR,
+               from_utf8("shaded #ff0000")));
 
        for (int i = 0; i < 4; ++i) {
                params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
@@ -930,7 +940,7 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
                        << ' ' << quoteName(lyx2lyx.toFilesystemEncoding())
                        << " -t " << convert<string>(LYX_FORMAT)
                        << " -o " << quoteName(tmpfile.toFilesystemEncoding())
-                       << ' ' << quoteName(filename.toFilesystemEncoding());
+                       << ' ' << quoteName(filename.toSafeFilesystemEncoding());
                string const command_str = command.str();
 
                LYXERR(Debug::INFO, "Running '" << command_str << '\'');
@@ -974,11 +984,20 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
 // Should probably be moved to somewhere else: BufferView? GuiView?
 bool Buffer::save() const
 {
+       // ask if the disk file has been externally modified (use checksum method)
+       if (fileName().exists() && isExternallyModified(checksum_method)) {
+               docstring const file = makeDisplayPath(absFileName(), 20);
+               docstring text = bformat(_("Document %1$s has been externally modified. Are you sure "
+                                                            "you want to overwrite this file?"), file);
+               int const ret = Alert::prompt(_("Overwrite modified file?"),
+                       text, 1, 1, _("&Overwrite"), _("&Cancel"));
+               if (ret == 1)
+                       return false;
+       }
+
        // We don't need autosaves in the immediate future. (Asger)
        resetAutosaveTimers();
 
-       string const encodedFilename = d->filename.toFilesystemEncoding();
-
        FileName backupName;
        bool madeBackup = false;
 
@@ -991,7 +1010,7 @@ bool Buffer::save() const
                        backupName = FileName(addName(lyxrc.backupdir_path,
                                                      mangledName));
                }
-               if (fileName().copyTo(backupName)) {
+               if (fileName().moveTo(backupName)) {
                        madeBackup = true;
                } else {
                        Alert::error(_("Backup failure"),
@@ -1002,17 +1021,6 @@ bool Buffer::save() const
                }
        }
 
-       // ask if the disk file has been externally modified (use checksum method)
-       if (fileName().exists() && isExternallyModified(checksum_method)) {
-               docstring const file = makeDisplayPath(absFileName(), 20);
-               docstring text = bformat(_("Document %1$s has been externally modified. Are you sure "
-                                                            "you want to overwrite this file?"), file);
-               int const ret = Alert::prompt(_("Overwrite modified file?"),
-                       text, 1, 1, _("&Overwrite"), _("&Cancel"));
-               if (ret == 1)
-                       return false;
-       }
-
        if (writeFile(d->filename)) {
                markClean();
                return true;
@@ -1036,11 +1044,13 @@ bool Buffer::writeFile(FileName const & fname) const
                makeDisplayPath(fname.absFilename()));
        message(str);
 
+       string const encoded_fname = fname.toSafeFilesystemEncoding(os::CREATE);
+
        if (params().compressed) {
-               gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+               gz::ogzstream ofs(encoded_fname.c_str(), ios::out|ios::trunc);
                retval = ofs && write(ofs);
        } else {
-               ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+               ofstream ofs(encoded_fname.c_str(), ios::out|ios::trunc);
                retval = ofs && write(ofs);
        }
 
@@ -1049,7 +1059,8 @@ bool Buffer::writeFile(FileName const & fname) const
                return false;
        }
 
-       removeAutosaveFile();
+       // see bug 6587
+       // removeAutosaveFile();
 
        saveCheckSum(d->filename);
        message(str + _(" done."));
@@ -1308,14 +1319,41 @@ void Buffer::writeLaTeXSource(odocstream & os,
                if (!original_path.empty()) {
                        // FIXME UNICODE
                        // We don't know the encoding of inputpath
-                       docstring const inputpath = from_utf8(latex_path(original_path));
-                       os << "\\makeatletter\n"
-                          << "\\def\\input@path{{"
-                          << inputpath << "/}}\n"
-                          << "\\makeatother\n";
-                       d->texrow.newline();
-                       d->texrow.newline();
-                       d->texrow.newline();
+                       docstring const inputpath = from_utf8(support::latex_path(original_path));
+                       docstring uncodable_glyphs;
+                       Encoding const * const enc = runparams.encoding;
+                       if (enc) {
+                               for (size_t n = 0; n < inputpath.size(); ++n) {
+                                       docstring const glyph =
+                                               docstring(1, inputpath[n]);
+                                       if (enc->latexChar(inputpath[n], true) != glyph) {
+                                               LYXERR0("Uncodable character '"
+                                                       << glyph
+                                                       << "' in input path!");
+                                               uncodable_glyphs += glyph;
+                                       }
+                               }
+                       }
+
+                       // warn user if we found uncodable glyphs.
+                       if (!uncodable_glyphs.empty()) {
+                               frontend::Alert::warning(_("Uncodable character in file path"),
+                                               support::bformat(_("The path of your document\n"
+                                                 "(%1$s)\n"
+                                                 "contains glyphs that are unknown in the\n"
+                                                 "current document encoding (namely %2$s).\n"
+                                                 "This will likely result in incomplete output.\n\n"
+                                                 "Choose an appropriate document encoding (such as utf8)\n"
+                                                 "or change the file path name."), inputpath, uncodable_glyphs));
+                       } else {
+                               os << "\\makeatletter\n"
+                                  << "\\def\\input@path{{"
+                                  << inputpath << "/}}\n"
+                                  << "\\makeatother\n";
+                               d->texrow.newline();
+                               d->texrow.newline();
+                               d->texrow.newline();
+                       }
                }
 
                // get parent macros (if this buffer has a parent) which will be
@@ -1523,26 +1561,31 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
 {
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
-       updateLabels(UpdateMaster, OutputUpdate);
+       updateBuffer(UpdateMaster, OutputUpdate);
        checkBibInfoCache();
        d->bibinfo_.makeCitationLabels(*this);
        updateMacros();
        updateMacroInstances();
 
        if (!only_body) {
-               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\">\n";
-               os << "<head>\n";
-               // FIXME Presumably need to set this right
-               os << "<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n";
-               os << "<title>" << features.htmlTitle() << "</title>\n";
+               os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                  << "<!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.
+                  << "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+                  << "<head>\n"
+                  << "<meta name=\"GENERATOR\" content=\"" << PACKAGE_STRING << "\" />\n"
+                  // FIXME Presumably need to set this right
+                  << "<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n";
+
+               docstring const & doctitle = features.htmlTitle();
+               os << "<title>"
+                  << (doctitle.empty() ? from_ascii("LyX Document") : doctitle)
+                  << "</title>\n";
 
                os << "\n<!-- Text Class Preamble -->\n"
-                       << features.getTClassHTMLPreamble()
-                       << "\n<!-- Premable Snippets -->\n"
-                       << from_utf8(features.getPreambleSnippets());
+                  << features.getTClassHTMLPreamble()
+                  << "\n<!-- Premable Snippets -->\n"
+                  << from_utf8(features.getPreambleSnippets());
 
                os << "\n<!-- Layout-provided Styles -->\n";
                docstring const styleinfo = features.getTClassHTMLStyles();
@@ -1580,6 +1623,7 @@ int Buffer::runChktex()
        OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
        runparams.nice = false;
+       runparams.linelen = lyxrc.plaintext_linelen;
        makeLaTeXFile(FileName(name), org_path, runparams);
 
        TeXErrors terr;
@@ -1866,7 +1910,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
        case LFUN_BUFFER_EXPORT: {
                bool success = doExport(argument, false, false);
-               dr.setError(success);
+               dr.setError(!success);
                if (!success)
                        dr.setMessage(bformat(_("Error exporting to format: %1$s."), 
                                              func.argument()));
@@ -2185,6 +2229,9 @@ std::set<Language const *> Buffer::getLanguages() const
 void Buffer::getLanguages(std::set<Language const *> & languages) const
 {
        ParConstIterator end = par_iterator_end();
+       // add the buffer language, even if it's not actively used
+       languages.insert(language());
+       // iterate over the paragraphs
        for (ParConstIterator it = par_iterator_begin(); it != end; ++it)
                it->getLanguages(languages);
        // also children
@@ -2434,18 +2481,16 @@ void Buffer::getChildren(std::vector<Buffer *> & clist, bool grand_children) con
                clist.push_back(child);
                if (grand_children) {
                        // there might be grandchildren
-                       std::vector<Buffer *> glist = child->getChildren();
-                       for (vector<Buffer *>::const_iterator git = glist.begin();
-                                git != glist.end(); ++git)
-                               clist.push_back(*git);
+                       vector<Buffer *> glist = child->getChildren();
+                       clist.insert(clist.end(), glist.begin(), glist.end());
                }
        }
 }
 
 
-std::vector<Buffer *> Buffer::getChildren(bool grand_children) const
+vector<Buffer *> Buffer::getChildren(bool grand_children) const
 {
-       std::vector<Buffer *> v;
+       vector<Buffer *> v;
        getChildren(v, grand_children);
        return v;
 }
@@ -2941,11 +2986,11 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin,
 ErrorList & Buffer::errorList(string const & type) const
 {
        static ErrorList emptyErrorList;
-       map<string, ErrorList>::iterator I = d->errorLists.find(type);
-       if (I == d->errorLists.end())
+       map<string, ErrorList>::iterator it = d->errorLists.find(type);
+       if (it == d->errorLists.end())
                return emptyErrorList;
 
-       return I->second;
+       return it->second;
 }
 
 
@@ -3122,8 +3167,10 @@ void Buffer::removeAutosaveFile() const
 void Buffer::moveAutosaveFile(support::FileName const & oldauto) const
 {
        FileName const newauto = getAutosaveFilename();
-       if (!(oldauto == newauto || oldauto.moveTo(newauto)))
-               LYXERR0("Unable to remove autosave file `" << oldauto << "'!");
+       oldauto.refresh();
+       if (newauto != oldauto && oldauto.exists())
+               if (!oldauto.moveTo(newauto))
+                       LYXERR0("Unable to move autosave file `" << oldauto << "'!");
 }
 
 
@@ -3236,6 +3283,21 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        // HTML backend
        else if (backend_format == "xhtml") {
                runparams.flavor = OutputParams::HTML;
+               switch (params().html_math_output) {
+               case BufferParams::MathML: 
+                       runparams.math_flavor = OutputParams::MathAsMathML; 
+                       break;
+               case BufferParams::HTML: 
+                       runparams.math_flavor = OutputParams::MathAsHTML; 
+                       break;
+               case BufferParams::Images:
+                       runparams.math_flavor = OutputParams::MathAsImages; 
+                       break;
+               case BufferParams::LaTeX:
+                       runparams.math_flavor = OutputParams::MathAsLaTeX; 
+                       break;                                                                                  
+               }
+               
                makeLyXHTMLFile(FileName(filename), runparams);
        }       else if (backend_format == "lyx")
                writeFile(FileName(filename));
@@ -3268,17 +3330,26 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        bool const success = theConverters().convert(this, FileName(filename),
                tmp_result_file, FileName(absFileName()), backend_format, format,
                error_list);
-       // Emit the signal to show the error list.
+
+       // Emit the signal to show the error list or copy it back to the
+       // cloned Buffer so that it cab be emitted afterwards.
        if (format != backend_format) {
-               errors(error_type);
+               if (d->cloned_buffer_) {
+                       d->cloned_buffer_->d->errorLists[error_type] = 
+                               d->errorLists[error_type];
+               } else 
+                       errors(error_type);
                // also to the children, in case of master-buffer-view
                std::vector<Buffer *> clist = getChildren();
                for (vector<Buffer *>::const_iterator cit = clist.begin();
-                    cit != clist.end(); ++cit)
-                       (*cit)->errors(error_type, true);
+                       cit != clist.end(); ++cit) {
+                       if (d->cloned_buffer_) {
+                               (*cit)->d->cloned_buffer_->d->errorLists[error_type] = 
+                                       (*cit)->d->errorLists[error_type];
+                       } else
+                               (*cit)->errors(error_type, true);
+               }
        }
-       if (!success)
-               return false;
 
        if (d->cloned_buffer_) {
                // Enable reverse dvi or pdf to work by copying back the texrow
@@ -3286,8 +3357,13 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                // FIXME: There is a possibility of concurrent access to texrow
                // here from the main GUI thread that should be securized.
                d->cloned_buffer_->d->texrow = d->texrow;
+               string const error_type = bufferFormat();
+               d->cloned_buffer_->d->errorLists[error_type] = d->errorLists[error_type];
        }
 
+       if (!success)
+               return false;
+
        if (put_in_tempdir) {
                result_file = tmp_result_file.absFilename();
                return true;
@@ -3431,7 +3507,7 @@ bool Buffer::readFileHelper(FileName const & s)
                        else
                                str = _("Document was NOT successfully recovered.");
                        str += "\n\n" + bformat(_("Remove emergency file now?\n(%1$s)"),
-                                               from_utf8(e.absFilename()));
+                                               makeDisplayPath(e.absFilename()));
 
                        if (!Alert::prompt(_("Delete emergency file?"), str, 1, 1,
                                        _("&Remove"), _("&Keep it"))) {
@@ -3494,7 +3570,7 @@ bool Buffer::loadLyXFile(FileName const & s)
                // InsetInfo needs to know if file is under VCS
                lyxvc().file_found_hook(s);
                if (readFileHelper(s)) {
-                       setReadonly(!s.isWritable());
+                       d->read_only = !s.isWritable();
                        return true;
                }
        }
@@ -3532,7 +3608,7 @@ void Buffer::setBuffersForInsets() const
 }
 
 
-void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
+void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
 {
        // Use the master text class also for child documents
        Buffer const * const master = masterBuffer();
@@ -3550,7 +3626,7 @@ void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
                // If this is a child document start with the master
                if (master != this) {
                        bufToUpdate.insert(this);
-                       master->updateLabels(UpdateMaster, utype);
+                       master->updateBuffer(UpdateMaster, utype);
                        // 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->d->gui_)
@@ -3578,7 +3654,7 @@ void Buffer::updateLabels(UpdateScope scope, UpdateType utype) const
 
        // do the real work
        ParIterator parit = cbuf.par_iterator_begin();
-       updateLabels(parit, utype);
+       updateBuffer(parit, utype);
 
        if (master != this)
                // TocBackend update will be done later.
@@ -3789,7 +3865,7 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
 }
 
 
-void Buffer::updateLabels(ParIterator & parit, UpdateType utype) const
+void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
 {
        LASSERT(parit.pit() == 0, /**/);
 
@@ -3822,7 +3898,7 @@ void Buffer::updateLabels(ParIterator & parit, UpdateType utype) const
                InsetList::const_iterator end = parit->insetList().end();
                for (; iit != end; ++iit) {
                        parit.pos() = iit->pos;
-                       iit->inset->updateLabels(parit, utype);
+                       iit->inset->updateBuffer(parit, utype);
                }
        }
 }
@@ -3867,13 +3943,15 @@ int Buffer::spellCheck(DocIterator & from, DocIterator & to,
 bool Buffer::reload()
 {
        setBusy(true);
+       // c.f. bug 6587
+       removeAutosaveFile();
        // e.g., read-only status could have changed due to version control
        d->filename.refresh();
        docstring const disp_fn = makeDisplayPath(d->filename.absFilename());
 
        bool const success = loadLyXFile(d->filename);
        if (success) {
-               updateLabels();
+               updateBuffer();
                changed(true);
                markClean();
                message(bformat(_("Document %1$s reloaded."), disp_fn));
@@ -3881,9 +3959,49 @@ bool Buffer::reload()
                message(bformat(_("Could not reload document %1$s."), disp_fn));
        }       
        setBusy(false);
+       thePreviews().removeLoader(*this);
+       if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
+               thePreviews().generateBufferPreviews(*this);
        errors("Parse");
        return success;
 }
 
 
+// FIXME We could do better here, but it is complicated. What would be
+// nice is to offer either (a) to save the child buffer to an appropriate
+// location, so that it would "move with the master", or else (b) to update
+// the InsetInclude so that it pointed to the same file. But (a) is a bit
+// complicated, because the code for this lives in GuiView.
+void Buffer::checkChildBuffers()
+{
+       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
+       Impl::BufferPositionMap::iterator const en = d->children_positions.end();
+       for (; it != en; ++it) {
+               DocIterator dit = it->second;
+               Buffer * cbuf = const_cast<Buffer *>(it->first);
+               if (!cbuf || !theBufferList().isLoaded(cbuf))
+                       continue;
+               Inset * inset = dit.nextInset();
+               LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue);
+               InsetInclude * inset_inc = static_cast<InsetInclude *>(inset);
+               docstring const & incfile = inset_inc->getParam("filename");
+               string oldloc = cbuf->absFileName();
+               string newloc = makeAbsPath(to_utf8(incfile),
+                               onlyPath(absFileName())).absFilename();
+               if (oldloc == newloc)
+                       continue;
+               // the location of the child file is incorrect.
+               Alert::warning(_("Included File Invalid"),
+                               bformat(_("Saving this document to a new location has made the file:\n"
+                               "  %1$s\n"
+                               "inaccessible. You will need to update the included filename."),
+                               from_utf8(oldloc)));
+               cbuf->setParent(0);
+               inset_inc->setChildBuffer(0);
+       }
+       // invalidate cache of children
+       d->children_positions.clear();
+       d->position_to_children.clear();
+}
+
 } // namespace lyx