]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
prepare Qt 5.6 builds
[lyx.git] / src / Buffer.cpp
index 847b0292afab5f955f68ce07974cc697c30d462b..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.
@@ -1587,7 +1656,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
        OutputParams runparams = runparams_in;
 
        // XeTeX with TeX fonts is only safe with ASCII encoding,
-       // See #9740 and FIXME in BufferParams::encoding()
+       // but the "flavor" is not known in BufferParams::encoding().
        if (!params().useNonTeXFonts && (runparams.flavor == OutputParams::XETEX))
                runparams.encoding = encodings.fromLyXName("ascii");
 
@@ -1674,11 +1743,12 @@ void Buffer::writeLaTeXSource(otexstream & os,
        OutputParams runparams = runparams_in;
 
        // XeTeX with TeX fonts is only safe with ASCII encoding,
-       // See #9740 and FIXME in BufferParams::encoding()
-       // FIXME: when only the current paragraph is shown, this seems to be ignored:
-       //   characters encodable in the current encoding are not converted to ASCII-representation.
+       // 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
@@ -2445,6 +2515,26 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                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;
        }
@@ -2674,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;
@@ -2902,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;
 }
 
 
@@ -4944,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)