]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
prepare Qt 5.6 builds
[lyx.git] / src / Buffer.cpp
index 0f37edd9dcb1868dbad7bce1159a87a1172b8e60..37dcbca01475f44539f97ec4a5b3f3e1b8808340 100644 (file)
@@ -204,6 +204,13 @@ public:
         */
        bool file_fully_loaded;
 
+       /// original format of loaded file
+       int file_format;
+
+       /// if the file was originally loaded from an older format, do
+       /// we need to back it up still?
+       bool need_format_backup;
+
        /// Ignore the parent (e.g. when exporting a child standalone)?
        bool ignore_parent;
 
@@ -405,11 +412,11 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        Buffer const * cloned_buffer)
        : owner_(owner), lyx_clean(true), bak_clean(true), unnamed(false),
          internal_buffer(false), read_only(readonly_), filename(file),
-         file_fully_loaded(false), ignore_parent(false), toc_backend(owner),
-         macro_lock(false), timestamp_(0), checksum_(0), wa_(0), gui_(0),
-         undo_(*owner), bibinfo_cache_valid_(false), bibfile_cache_valid_(false),
-         cite_labels_valid_(false), inset(0), preview_loader_(0),
-         cloned_buffer_(cloned_buffer), clone_list_(0),
+         file_fully_loaded(false), file_format(LYX_FORMAT), need_format_backup(false),
+         ignore_parent(false),  toc_backend(owner), macro_lock(false), timestamp_(0),
+         checksum_(0), wa_(0),  gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
+         bibfile_cache_valid_(false), cite_labels_valid_(false), inset(0),
+         preview_loader_(0), cloned_buffer_(cloned_buffer), clone_list_(0),
          doing_export(false), parent_buffer(0),
          word_count_(0), char_count_(0), blank_count_(0)
 {
@@ -510,8 +517,12 @@ Buffer::~Buffer()
                Impl::BufferPositionMap::iterator end = d->children_positions.end();
                for (; it != end; ++it) {
                        Buffer * child = const_cast<Buffer *>(it->first);
-                       if (theBufferList().isLoaded(child))
-                               theBufferList().releaseChild(this, child);
+                       if (theBufferList().isLoaded(child)) { 
+                        if (theBufferList().isOthersChild(this, child))
+                                child->setParent(0);
+                        else
+                               theBufferList().release(child);
+                       }
                }
 
                if (!isClean()) {
@@ -526,8 +537,7 @@ Buffer::~Buffer()
                d->position_to_children.clear();
 
                if (!d->temppath.destroyDirectory()) {
-                       Alert::warning(_("Could not remove temporary directory"),
-                               bformat(_("Could not remove the temporary directory %1$s"),
+                       LYXERR0(bformat(_("Could not remove the temporary directory %1$s"),
                                from_utf8(d->temppath.absFileName())));
                }
                removePreviews();
@@ -1023,7 +1033,10 @@ bool Buffer::readDocument(Lexer & lex)
        params().indiceslist().addDefault(B_("Index"));
 
        // read main text
-       d->old_position = originFilePath();
+       if (FileName::isAbsolute(params().origin))
+               d->old_position = params().origin;
+       else
+               d->old_position = filePath();
        bool const res = text().read(lex, errorList, d->inset);
        d->old_position.clear();
 
@@ -1133,10 +1146,15 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn)
 
        if (file_format != LYX_FORMAT) {
                FileName tmpFile;
-               ReadStatus const ret_clf = convertLyXFormat(fn, tmpFile, file_format);
+               ReadStatus ret_clf = convertLyXFormat(fn, tmpFile, file_format);
                if (ret_clf != ReadSuccess)
                        return ret_clf;
-               return readFile(tmpFile);
+               ret_clf = readFile(tmpFile);
+               if (ret_clf == ReadSuccess) {
+                       d->file_format = file_format;
+                       d->need_format_backup = true;
+               }
+               return ret_clf;
        }
 
        // FIXME: InsetInfo needs to know whether the file is under VCS
@@ -1295,6 +1313,41 @@ Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn,
 }
 
 
+FileName Buffer::getBackupName() const {
+       FileName const & fn = fileName();
+       string const fname = fn.onlyFileNameWithoutExt();
+       string const fext  = fn.extension();
+       string const fpath = lyxrc.backupdir_path.empty() ?
+               fn.onlyPath().absFileName() :
+               lyxrc.backupdir_path;
+       string const fform = convert<string>(d->file_format);
+       string const backname = fname + "-" + fform;
+       FileName backup(addName(fpath, addExtension(backname, fext)));
+
+       // limit recursion, just in case
+       int v = 1;
+       unsigned long orig_checksum = 0;
+       while (backup.exists() && v < 100) {
+               if (orig_checksum == 0)
+                       orig_checksum = fn.checksum();
+               unsigned long new_checksum = backup.checksum();
+               if (orig_checksum == new_checksum) {
+                       LYXERR(Debug::FILES, "Not backing up " << fn <<
+                              "since " << backup << "has the same checksum.");
+                       // a bit of a hack, but we have to check this anyway
+                       // below, and setting this is simpler than introducing
+                       // a special boolean for this purpose.
+                       v = 1000;
+                       break;
+               }
+               string const newbackname = backname + "-" + convert<string>(v);
+               backup.set(addName(fpath, addExtension(newbackname, fext)));
+               v++;
+       }
+       return v < 100 ? backup : FileName();
+}
+
+
 // Should probably be moved to somewhere else: BufferView? GuiView?
 bool Buffer::save() const
 {
@@ -1354,13 +1407,22 @@ bool Buffer::save() const
        // we will set this to false if we fail
        bool made_backup = true;
 
-       FileName backupName(absFileName() + '~');
-       if (lyxrc.make_backup) {
-               if (!lyxrc.backupdir_path.empty()) {
-                       string const mangledName =
-                               subst(subst(backupName.absFileName(), '/', '!'), ':', '!');
-                       backupName = FileName(addName(lyxrc.backupdir_path,
-                                                     mangledName));
+       FileName backupName;
+       bool const needBackup = lyxrc.make_backup || d->need_format_backup;
+       if (needBackup) {
+               if (d->need_format_backup)
+                       backupName = getBackupName();
+
+               // If we for some reason failed to find a backup name in case of
+               // a format change, this will still set one. It's the best we can
+               // do in this case.
+               if (backupName.empty()) {
+                       backupName.set(fileName().absFileName() + "~");
+                       if (!lyxrc.backupdir_path.empty()) {
+                               string const mangledName =
+                                       subst(subst(backupName.absFileName(), '/', '!'), ':', '!');
+                               backupName.set(addName(lyxrc.backupdir_path, mangledName));
+                       }
                }
 
                LYXERR(Debug::FILES, "Backing up original file to " <<
@@ -1377,6 +1439,10 @@ bool Buffer::save() const
                                               "Please check whether the directory exists and is writable."),
                                             from_utf8(backupName.absFileName())));
                        //LYXERR(Debug::DEBUG, "Fs error: " << fe.what());
+               } else if (d->need_format_backup) {
+                       // the original file has been backed up successfully, so we
+                       // will not need to do that again
+                       d->need_format_backup = false;
                }
        }
 
@@ -1393,12 +1459,15 @@ bool Buffer::save() const
                // time stamp is invalidated by copying/moving
                saveCheckSum();
                markClean();
+               if (d->file_format != LYX_FORMAT)
+                       // the file associated with this buffer is now in the current format
+                       d->file_format = LYX_FORMAT;
                return true;
        }
        // else we saved the file, but failed to move it to the right location.
 
-       if (lyxrc.make_backup && made_backup && !symlink) {
-               // the original file was moved to filename.lyx~, so it will look
+       if (needBackup && made_backup && !symlink) {
+               // the original file was moved to some new location, so it will look
                // to the user as if it was deleted. (see bug #9234.) we could try
                // to restore it, but that would basically mean trying to do again
                // what we just failed to do. better to leave things as they are.
@@ -1586,10 +1655,10 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 {
        OutputParams runparams = runparams_in;
 
-       // This is necessary for LuaTeX/XeTeX with tex fonts.
-       // See FIXME in BufferParams::encoding()
-       if (runparams.isFullUnicode())
-               runparams.encoding = encodings.fromLyXName("utf8-plain");
+       // XeTeX with TeX fonts is only safe with ASCII encoding,
+       // but the "flavor" is not known in BufferParams::encoding().
+       if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX))
+               runparams.encoding = encodings.fromLyXName("ascii");
 
        string const encoding = runparams.encoding->iconvName();
        LYXERR(Debug::LATEX, "makeLaTeXFile encoding: " << encoding << ", fname=" << fname.realPath());
@@ -1673,10 +1742,13 @@ void Buffer::writeLaTeXSource(otexstream & os,
 
        OutputParams runparams = runparams_in;
 
-       // This is necessary for LuaTeX/XeTeX with tex fonts.
-       // See FIXME in BufferParams::encoding()
-       if (runparams.isFullUnicode())
-               runparams.encoding = encodings.fromLyXName("utf8-plain");
+       // XeTeX with TeX fonts is only safe with ASCII encoding,
+       // but the "flavor" is not known in BufferParams::encoding().
+       if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX))
+               runparams.encoding = encodings.fromLyXName("ascii");
+       // FIXME: when only the current paragraph is shown, this is ignored
+       //        (or not reached) and characters encodable in the current
+       //        encoding are not converted to ASCII-representation.
 
        // If we are compiling a file standalone, even if this is the
        // child of some other buffer, let's cut the link here, so the
@@ -1842,14 +1914,7 @@ void Buffer::writeLaTeXSource(otexstream & os,
        }
        runparams_in.encoding = runparams.encoding;
 
-       // Just to be sure. (Asger)
-       os.texrow().newline();
-
-       //for (int i = 0; i<d->texrow.rows(); i++) {
-       // int id,pos;
-       // if (d->texrow.getIdFromRow(i+1,id,pos) && id>0)
-       //      lyxerr << i+1 << ":" << id << ":" << getParFromID(id).paragraph().asString()<<"\n";
-       //}
+       os.texrow().finalize();
 
        LYXERR(Debug::INFO, "Finished making LaTeX file.");
        LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.');
@@ -1886,7 +1951,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname,
        LaTeXFeatures features(*this, params(), runparams);
        validate(features);
 
-       d->texrow.reset();
+       d->texrow.reset(false);
 
        DocumentClass const & tclass = params().documentClass();
        string const & top_element = tclass.latexname();
@@ -2447,9 +2512,29 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        case LFUN_BUFFER_VIEW_CACHE:
                (d->preview_file_).refresh();
-               enable = (d->preview_file_).exists();
+               enable = (d->preview_file_).exists() && !(d->preview_file_).isFileEmpty();
+               break;
+
+       case LFUN_CHANGES_TRACK:
+               flag.setEnabled(true);
+               flag.setOnOff(params().track_changes);
                break;
 
+       case LFUN_CHANGES_OUTPUT:
+               flag.setEnabled(true);
+               flag.setOnOff(params().output_changes);
+               break;
+
+       case LFUN_BUFFER_TOGGLE_COMPRESSION: {
+               flag.setOnOff(params().compressed);
+               break;
+       }
+
+       case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: {
+               flag.setOnOff(params().output_sync);
+               break;
+       }
+
        default:
                return false;
        }
@@ -2679,6 +2764,48 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        dr.setMessage(_("Error viewing the output file."));
                break;
 
+       case LFUN_CHANGES_TRACK:
+               if (params().save_transient_properties)
+                       undo().recordUndoBufferParams(CursorData());
+               params().track_changes = !params().track_changes;
+               break;
+
+       case LFUN_CHANGES_OUTPUT:
+               if (params().save_transient_properties)
+                       undo().recordUndoBufferParams(CursorData());
+               params().output_changes = !params().output_changes;
+               if (params().output_changes) {
+                       bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
+                       bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
+                                         LaTeXFeatures::isAvailable("xcolor");
+
+                       if (!dvipost && !xcolorulem) {
+                               Alert::warning(_("Changes not shown in LaTeX output"),
+                                              _("Changes will not be highlighted in LaTeX output, "
+                                                "because neither dvipost nor xcolor/ulem are installed.\n"
+                                                "Please install these packages or redefine "
+                                                "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
+                       } else if (!xcolorulem) {
+                               Alert::warning(_("Changes not shown in LaTeX output"),
+                                              _("Changes will not be highlighted in LaTeX output "
+                                                "when using pdflatex, because xcolor and ulem are not installed.\n"
+                                                "Please install both packages or redefine "
+                                                "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
+                       }
+               }
+               break;
+
+       case LFUN_BUFFER_TOGGLE_COMPRESSION:
+               // turn compression on/off
+               undo().recordUndoBufferParams(CursorData());
+               params().compressed = !params().compressed;
+               break;
+
+       case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC:
+               undo().recordUndoBufferParams(CursorData());
+               params().output_sync = !params().output_sync;
+               break;
+
        default:
                dispatched = false;
                break;
@@ -2907,12 +3034,21 @@ string Buffer::filePath() const
 }
 
 
-string Buffer::originFilePath() const
+DocFileName Buffer::getReferencedFileName(string const & fn) const
 {
-       if (FileName::isAbsolute(params().origin))
-               return params().origin;
+       DocFileName result;
+       if (FileName::isAbsolute(fn) || !FileName::isAbsolute(params().origin))
+               result.set(fn, filePath());
+       else {
+               // filePath() ends with a path separator
+               FileName const test(filePath() + fn);
+               if (test.exists())
+                       result.set(fn, filePath());
+               else
+                       result.set(fn, params().origin);
+       }
 
-       return filePath();
+       return result;
 }
 
 
@@ -3442,7 +3578,7 @@ Buffer::References & Buffer::getReferenceCache(docstring const & label)
                return it->second.second;
 
        static InsetLabel const * dummy_il = 0;
-       static References const dummy_refs;
+       static References const dummy_refs = References();
        it = d->ref_cache_.insert(
                make_pair(label, make_pair(dummy_il, dummy_refs))).first;
        return it->second.second;
@@ -3570,7 +3706,6 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os, string const & format,
                        params().validate(features);
                        runparams.use_polyglossia = features.usePolyglossia();
                        texrow.reset(new TexRow());
-                       texrow->reset();
                        texrow->newline();
                        texrow->newline();
                        // latex or literate
@@ -3578,6 +3713,7 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os, string const & format,
 
                        // the real stuff
                        latexParagraphs(*this, text(), ots, runparams);
+                       texrow->finalize();
 
                        // Restore the parenthood
                        if (!master)
@@ -3613,13 +3749,13 @@ auto_ptr<TexRow> Buffer::getSourceCode(odocstream & os, string const & format,
                } else {
                        // latex or literate
                        texrow.reset(new TexRow());
-                       texrow->reset();
                        texrow->newline();
                        texrow->newline();
                        otexstream ots(os, *texrow);
                        if (master)
                                runparams.is_child = true;
                        writeLaTeXSource(ots, string(), runparams, output);
+                       texrow->finalize();
                }
        }
        return texrow;
@@ -4462,7 +4598,7 @@ void Buffer::updateBuffer(UpdateScope scope, UpdateType utype) const
        d->bibinfo_cache_valid_ = true;
        d->cite_labels_valid_ = true;
        /// FIXME: Perf
-       cbuf.tocBackend().update(utype == OutputUpdate);
+       cbuf.tocBackend().update(true, utype);
        if (scope == UpdateMaster)
                cbuf.structureChanged();
 }
@@ -4949,13 +5085,23 @@ void Buffer::checkMasterBuffer()
 
 string Buffer::includedFilePath(string const & name, string const & ext) const
 {
+       if (d->old_position.empty() ||
+           equivalent(FileName(d->old_position), FileName(filePath())))
+               return name;
+
        bool isabsolute = FileName::isAbsolute(name);
-       // old_position already contains a trailing path separator
-       string const absname = isabsolute ? name : d->old_position + name;
+       // both old_position and filePath() end with a path separator
+       string absname = isabsolute ? name : d->old_position + name;
+
+       // if old_position is set to origin, we need to do the equivalent of
+       // getReferencedFileName() (see readDocument())
+       if (!isabsolute && d->old_position == params().origin) {
+               FileName const test(addExtension(filePath() + name, ext));
+               if (test.exists())
+                       absname = filePath() + name;
+       }
 
-       if (d->old_position.empty()
-           || equivalent(FileName(d->old_position), FileName(filePath()))
-           || !FileName(addExtension(absname, ext)).exists())
+       if (!FileName(addExtension(absname, ext)).exists())
                return name;
 
        if (isabsolute)