From ac08e89095af413817b08b538a4ed8cb0eabbfdd Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Tue, 4 Dec 2007 22:21:25 +0000 Subject: [PATCH] Sanitize the way Buffers are saved, renamed and closed. * LyXFunc: Transfer and simplify LFUN_BUFFER_WRITE, LFUN_BUFFER_WRITE_AS and LFUN_BUFFER_WRITE_ALL to GuiView. * BufferList: Transfer quitWriteAll() and close() to GuiView. * Buffer: Transfer writeAs() and menuWrite() functionalities to GuiView. * LyXView::closeBuffer(): new pure virtual method. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21960 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Buffer.cpp | 155 ++++--------------- src/Buffer.h | 4 - src/BufferList.cpp | 115 +------------- src/BufferList.h | 9 -- src/LyXFunc.cpp | 99 ++++-------- src/buffer_funcs.cpp | 8 +- src/frontends/LyXView.h | 2 + src/frontends/qt4/GuiApplication.cpp | 6 +- src/frontends/qt4/GuiView.cpp | 216 ++++++++++++++++++++++++++- src/frontends/qt4/GuiView.h | 26 ++++ src/insets/InsetInclude.cpp | 4 +- 11 files changed, 311 insertions(+), 333 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 40f439de28..71b58902ee 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -73,7 +73,6 @@ #include "frontends/alert.h" #include "frontends/Delegates.h" #include "frontends/WorkAreaManager.h" -#include "frontends/FileDialog.h" #include "graphics/Previews.h" @@ -874,8 +873,6 @@ bool Buffer::save() const if (writeFile(d->filename)) { markClean(); - removeAutosaveFile(absFileName()); - saveCheckSum(d->filename); return true; } else { // Saving failed, so backup is not backup @@ -899,27 +896,40 @@ bool Buffer::writeFile(FileName const & fname) const content = FileName(addName(temppath(), "content.lyx")); else content = fname; - + + docstring const str = bformat(_("Saving document %1$s..."), + makeDisplayPath(content.absFilename())); + message(str); + if (params().compressed) { gz::ogzstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc); - if (!ofs) - return false; - - retval = write(ofs); + retval = ofs && write(ofs); } else { ofstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc); - if (!ofs) - return false; - - retval = write(ofs); + retval = ofs && write(ofs); } - if (retval && params().embedded) { - // write file.lyx and all the embedded files to the zip file fname - // if embedding is enabled - return d->embedded_files.writeFile(fname); + if (!retval) { + message(str + _(" could not write file!.")); + return false; } - return retval; + + removeAutosaveFile(d->filename.absFilename()); + saveCheckSum(d->filename); + message(str + _(" done.")); + + if (!params().embedded) + return true; + + message(str + _(" writing embedded files!.")); + // if embedding is enabled, write file.lyx and all the embedded files + // to the zip file fname. + if (!d->embedded_files.writeFile(fname)) { + message(str + _(" could not write embedded files!.")); + return false; + } + message(str + _(" error while writing embedded files.")); + return true; } @@ -2082,7 +2092,7 @@ void Buffer::autoSave() const // create autosave filename string fname = filePath(); fname += '#'; - fname += onlyFilename(absFileName()); + fname += d->filename.onlyFileName(); fname += '#'; AutoSaveBuffer autosave(*this, FileName(fname)); @@ -2093,115 +2103,6 @@ void Buffer::autoSave() const } -/** Write a buffer to a new file name and rename the buffer - according to the new file name. - - This function is e.g. used by menu callbacks and - LFUN_BUFFER_WRITE_AS. - - If 'newname' is empty (the default), the user is asked via a - dialog for the buffer's new name and location. - - If 'newname' is non-empty and has an absolute path, that is used. - Otherwise the base directory of the buffer is used as the base - for any relative path in 'newname'. -*/ - -bool Buffer::writeAs(string const & newname) -{ - string fname = absFileName(); - string const oldname = fname; - - if (newname.empty()) { /// No argument? Ask user through dialog - - // FIXME UNICODE - FileDialog dlg(_("Choose a filename to save document as"), - LFUN_BUFFER_WRITE_AS); - dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path)); - dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path)); - - if (!support::isLyXFilename(fname)) - fname += ".lyx"; - - support::FileFilterList const filter(_("LyX Documents (*.lyx)")); - - FileDialog::Result result = - dlg.save(from_utf8(onlyPath(fname)), - filter, - from_utf8(onlyFilename(fname))); - - if (result.first == FileDialog::Later) - return false; - - fname = to_utf8(result.second); - - if (fname.empty()) - return false; - - // Make sure the absolute filename ends with appropriate suffix - fname = makeAbsPath(fname).absFilename(); - if (!support::isLyXFilename(fname)) - fname += ".lyx"; - - } else - fname = makeAbsPath(newname, onlyPath(oldname)).absFilename(); - - if (FileName(fname).exists()) { - docstring const file = makeDisplayPath(fname, 30); - docstring text = bformat(_("The document %1$s already " - "exists.\n\nDo you want to " - "overwrite that document?"), - file); - int const ret = Alert::prompt(_("Overwrite document?"), - text, 0, 1, _("&Overwrite"), _("&Cancel")); - - if (ret == 1) - return false; - } - - // Ok, change the name of the buffer - setFileName(fname); - markDirty(); - bool unnamed = isUnnamed(); - setUnnamed(false); - saveCheckSum(FileName(fname)); - - if (!menuWrite()) { - setFileName(oldname); - setUnnamed(unnamed); - saveCheckSum(FileName(oldname)); - return false; - } - - removeAutosaveFile(oldname); - return true; -} - - -bool Buffer::menuWrite() -{ - if (save()) { - LyX::ref().session().lastFiles().add(FileName(absFileName())); - return true; - } - - // FIXME: we don't tell the user *WHY* the save failed !! - - docstring const file = makeDisplayPath(absFileName(), 30); - - docstring text = bformat(_("The document %1$s could not be saved.\n\n" - "Do you want to rename the document and " - "try again?"), file); - int const ret = Alert::prompt(_("Rename and save?"), - text, 0, 1, _("&Rename"), _("&Cancel")); - - if (ret != 0) - return false; - - return writeAs(); -} - - void Buffer::resetChildDocuments(bool close_them) const { for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { diff --git a/src/Buffer.h b/src/Buffer.h index 2430ee75a7..944530d338 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -418,10 +418,6 @@ public: /// void autoSave() const; /// - bool writeAs(std::string const & newname = std::string()); - /// - bool menuWrite(); - /// void loadChildDocuments() const; /// void resetChildDocuments(bool close_them) const; diff --git a/src/BufferList.cpp b/src/BufferList.cpp index 5fc0a36ad4..c33d64f21f 100644 --- a/src/BufferList.cpp +++ b/src/BufferList.cpp @@ -95,78 +95,6 @@ BufferList::const_iterator BufferList::end() const } -bool BufferList::quitWriteBuffer(Buffer * buf) -{ - BOOST_ASSERT(buf); - - docstring file; - - // FIXME: Unicode? - if (buf->isUnnamed()) - file = from_utf8(buf->fileName().onlyFileName()); - else - file = buf->fileName().displayName(30); - - docstring const text = - bformat(_("The document %1$s has unsaved changes.\n\n" - "Do you want to save the document or discard the changes?"), - file); - int const ret = Alert::prompt(_("Save changed document?"), - text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel")); - - if (ret == 0) { - // FIXME: WriteAs can be asynch ! - // but not right now...maybe we should remove that - - bool succeeded; - - if (buf->isUnnamed()) - succeeded = buf->writeAs(); - else - succeeded = buf->menuWrite(); - - if (!succeeded) - return false; - } else if (ret == 1) { - // if we crash after this we could - // have no autosave file but I guess - // this is really inprobable (Jug) - if (buf->isUnnamed()) - removeAutosaveFile(buf->absFileName()); - - } else { - return false; - } - - return true; -} - - -bool BufferList::quitWriteAll() -{ - BufferStorage::iterator it = bstore.begin(); - BufferStorage::iterator end = bstore.end(); - for (; it != end; ++it) { - if ((*it)->isClean()) - continue; - - if (!quitWriteBuffer(*it)) - return false; - } - // now, all buffers have been written sucessfully - // save file names to .lyx/session - it = bstore.begin(); - for (; it != end; ++it) { - // if master/slave are both open, do not save slave since it - // will be automatically loaded when the master is loaded - if ((*it)->masterBuffer() == (*it)) - LyX::ref().session().lastOpened().add(FileName((*it)->absFileName())); - } - - return true; -} - - void BufferList::release(Buffer * buf) { BOOST_ASSERT(buf); @@ -193,47 +121,8 @@ Buffer * BufferList::newBuffer(string const & s, bool const ronly) void BufferList::closeAll() { - while (!bstore.empty()) { - close(bstore.front(), false); - } -} - - -bool BufferList::close(Buffer * buf, bool const ask) -{ - BOOST_ASSERT(buf); - - if (!ask || buf->isClean() || buf->paragraphs().empty()) { - release(buf); - return true; - } - - docstring fname; - if (buf->isUnnamed()) - fname = from_utf8(onlyFilename(buf->absFileName())); - else - fname = makeDisplayPath(buf->absFileName(), 30); - - docstring const text = - bformat(_("The document %1$s has unsaved changes.\n\n" - "Do you want to save the document or discard the changes?"), - fname); - int const ret = Alert::prompt(_("Save changed document?"), - text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel")); - - if (ret == 0) { - if (buf->isUnnamed()) { - if (!buf->writeAs()) - return false; - } else if (!buf->menuWrite()) - return false; - } else if (ret == 2) - return false; - - removeAutosaveFile(buf->absFileName()); - - release(buf); - return true; + while (!bstore.empty()) + release(bstore.front()); } diff --git a/src/BufferList.h b/src/BufferList.h index 179cc358bc..eb61069079 100644 --- a/src/BufferList.h +++ b/src/BufferList.h @@ -40,9 +40,6 @@ public: iterator end(); const_iterator end() const; - /// write all buffers, asking the user, returns false if cancelled - bool quitWriteAll(); - /// create a new buffer Buffer * newBuffer(std::string const & s, bool ronly = false); @@ -61,9 +58,6 @@ public: /// emergency save for all buffers void emergencyWriteAll(); - /// close buffer. Returns false if cancelled by user - bool close(Buffer * buf, bool ask); - /// return true if no buffers loaded bool empty() const; @@ -108,9 +102,6 @@ private: BufferList(BufferList const &); void operator=(BufferList const &); - /// ask to save a buffer on quit, returns false if should cancel - bool quitWriteBuffer(Buffer * buf); - typedef std::vector BufferStorage; /// storage of all buffers diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 62db7bd67a..69ddb58c0f 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -531,17 +531,21 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const bool enable = true; switch (cmd.action) { + // FIXME: these cases should be hidden in GuiApplication::getStatus(). case LFUN_WINDOW_CLOSE: if (theApp()) return theApp()->getStatus(cmd); enable = false; break; + // FIXME: these cases should be hidden in GuiView::getStatus(). case LFUN_DIALOG_TOGGLE: case LFUN_DIALOG_SHOW: case LFUN_DIALOG_UPDATE: case LFUN_TOOLBAR_TOGGLE: case LFUN_INSET_APPLY: + case LFUN_BUFFER_WRITE: + case LFUN_BUFFER_WRITE_AS: if (lyx_view_) return lyx_view_->getStatus(cmd); enable = false; @@ -594,33 +598,33 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const enable = getStatus(fr).enabled(); break; } - - case LFUN_BUFFER_WRITE: { - enable = lyx_view_->buffer()->isUnnamed() - || !lyx_view_->buffer()->isClean(); + + // This could be used for the no-GUI version. The GUI version is handled in + // LyXView::getStatus(). + /* + case LFUN_BUFFER_WRITE: + case LFUN_BUFFER_WRITE_AS: { + Buffer * b = theBufferList().getBuffer(cmd.getArg(0)); + enable = b && (b->isUnnamed() || !b->isClean()); break; } - + */ case LFUN_BUFFER_WRITE_ALL: { - // We enable the command only if there are some modified buffers + // We enable the command only if there are some modified buffers Buffer * first = theBufferList().first(); - bool modified = false; - if (first) { - Buffer * b = first; - + enable = false; + if (!first) + break; + Buffer * b = first; // We cannot use a for loop as the buffer list is a cycle. - do { - if (!b->isClean()) { - modified = true; - break; - } - b = theBufferList().next(b); - } while (b != first); - } - - enable = modified; - + do { + if (!b->isClean()) { + enable = true; + break; + } + b = theBufferList().next(b); + } while (b != first); break; } @@ -670,7 +674,6 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case LFUN_CANCEL: case LFUN_META_PREFIX: case LFUN_BUFFER_CLOSE: - case LFUN_BUFFER_WRITE_AS: case LFUN_BUFFER_UPDATE: case LFUN_BUFFER_VIEW: case LFUN_MASTER_BUFFER_UPDATE: @@ -912,50 +915,6 @@ void LyXFunc::dispatch(FuncRequest const & cmd) updateFlags = Update::None; break; - case LFUN_BUFFER_WRITE: - BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); - if (!lyx_view_->buffer()->isUnnamed()) { - docstring const str = bformat(_("Saving document %1$s..."), - makeDisplayPath(lyx_view_->buffer()->absFileName())); - lyx_view_->message(str); - lyx_view_->buffer()->menuWrite(); - lyx_view_->message(str + _(" done.")); - } else { - lyx_view_->buffer()->writeAs(); - } - updateFlags = Update::None; - break; - - case LFUN_BUFFER_WRITE_AS: - BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); - lyx_view_->buffer()->writeAs(argument); - updateFlags = Update::None; - break; - - case LFUN_BUFFER_WRITE_ALL: { - Buffer * first = theBufferList().first(); - if (first) { - Buffer * b = first; - lyx_view_->message(_("Saving all documents...")); - - // We cannot use a for loop as the buffer list cycles. - do { - if (!b->isClean()) { - if (!b->isUnnamed()) { - b->menuWrite(); - LYXERR(Debug::ACTION, "Saved " << b->absFileName()); - } else - b->writeAs(); - } - b = theBufferList().next(b); - } while (b != first); - lyx_view_->message(_("All documents saved.")); - } - - updateFlags = Update::None; - break; - } - case LFUN_BUFFER_RELOAD: { BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20); @@ -2116,8 +2075,10 @@ void LyXFunc::doImport(string const & argument) FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx")); // Check if the document already is open - if (use_gui && theBufferList().exists(lyxfile.absFilename())) { - if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) { + Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename()); + if (use_gui && buf) { + lyx_view_->setBuffer(buf); + if (!lyx_view_->closeBuffer()) { lyx_view_->message(_("Canceled.")); return; } @@ -2151,7 +2112,7 @@ void LyXFunc::closeBuffer() for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) gotoBookmark(i+1, false, false); - theBufferList().close(lyx_view_->buffer(), true); + lyx_view_->closeBuffer(); } diff --git a/src/buffer_funcs.cpp b/src/buffer_funcs.cpp index e73a689cfd..04d0e3a9ac 100644 --- a/src/buffer_funcs.cpp +++ b/src/buffer_funcs.cpp @@ -82,11 +82,9 @@ Buffer * checkAndLoadLyXFile(FileName const & filename) return checkBuffer; // FIXME: should be LFUN_REVERT - if (theBufferList().close(checkBuffer, false)) - // Load it again. - return checkAndLoadLyXFile(filename); - // The file could not be closed. - return 0; + theBufferList().release(checkBuffer); + // Load it again. + return checkAndLoadLyXFile(filename); } if (filename.isReadableFile()) { diff --git a/src/frontends/LyXView.h b/src/frontends/LyXView.h index cca2ce99a9..61f8e4a202 100644 --- a/src/frontends/LyXView.h +++ b/src/frontends/LyXView.h @@ -65,6 +65,8 @@ public: virtual Buffer const * buffer() const = 0; /// set a buffer to the current workarea. virtual void setBuffer(Buffer * b) = 0; ///< \c Buffer to set. + /// + virtual bool closeBuffer() = 0; //@} diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 654ad68e2d..9cf2d707a4 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -250,7 +250,7 @@ bool GuiApplication::dispatch(FuncRequest const & cmd) for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) theLyXFunc().gotoBookmark(i+1, false, false); // ask the user for saving changes or cancel quit - if (!theBufferList().quitWriteAll()) + if (!current_view_->quitWriteAll()) break; current_view_->close(); break; @@ -259,7 +259,7 @@ bool GuiApplication::dispatch(FuncRequest const & cmd) // quitting is triggered by the gui code // (leaving the event loop). current_view_->message(from_utf8(N_("Exiting."))); - if (theBufferList().quitWriteAll()) + if (current_view_->quitWriteAll()) closeAllViews(); break; @@ -526,7 +526,7 @@ void GuiApplication::commitData(QSessionManager & sm) /// visible top level widgets when session managment allows /// interaction. /// We are changing that to write all unsaved buffers... - if (sm.allowsInteraction() && !theBufferList().quitWriteAll()) + if (sm.allowsInteraction() && !current_view_->quitWriteAll()) sm.cancel(); } diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 0788bebcab..0e16d88a56 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -26,6 +26,8 @@ #include "qt_helpers.h" +#include "frontends/alert.h" + #include "buffer_funcs.h" #include "Buffer.h" #include "BufferList.h" @@ -104,7 +106,10 @@ using support::addPath; using support::bformat; using support::FileFilterList; using support::FileName; +using support::makeAbsPath; +using support::makeDisplayPath; using support::package; +using support::removeAutosaveFile; using support::trim; namespace { @@ -393,7 +398,7 @@ void GuiView::closeEvent(QCloseEvent * close_event) // we may have been called through the close window button // which bypasses the LFUN machinery. if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) { - if (!theBufferList().quitWriteAll()) { + if (!quitWriteAll()) { close_event->ignore(); return; } @@ -937,6 +942,14 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd) buf = 0; switch(cmd.action) { + case LFUN_BUFFER_WRITE: + enable = buf && (buf->isUnnamed() || !buf->isClean()); + break; + + case LFUN_BUFFER_WRITE_AS: + enable = buf; + break; + case LFUN_TOOLBAR_TOGGLE: flag.setOnOff(d.toolbars_->visible(cmd.getArg(0))); break; @@ -1108,6 +1121,180 @@ void GuiView::insertPlaintextFile(docstring const & fname, } +bool GuiView::renameBuffer(Buffer & b, docstring const & newname) +{ + FileName fname = b.fileName(); + FileName const oldname = fname; + + if (!newname.empty()) { + // FIXME UNICODE + fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename()); + } else { + // Switch to this Buffer. + setBuffer(&b); + + /// No argument? Ask user through dialog. + // FIXME UNICODE + FileDialog dlg(_("Choose a filename to save document as"), + LFUN_BUFFER_WRITE_AS); + dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path)); + dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path)); + + if (!support::isLyXFilename(fname.absFilename())) + fname.changeExtension(".lyx"); + + support::FileFilterList const filter(_("LyX Documents (*.lyx)")); + + FileDialog::Result result = + dlg.save(from_utf8(fname.onlyPath().absFilename()), + filter, + from_utf8(fname.onlyFileName())); + + if (result.first == FileDialog::Later) + return false; + + fname.set(to_utf8(result.second)); + + if (fname.empty()) + return false; + + if (!support::isLyXFilename(fname.absFilename())) + fname.changeExtension(".lyx"); + } + + if (FileName(fname).exists()) { + docstring const file = makeDisplayPath(fname.absFilename(), 30); + docstring text = bformat(_("The document %1$s already " + "exists.\n\nDo you want to " + "overwrite that document?"), + file); + int const ret = Alert::prompt(_("Overwrite document?"), + text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel")); + switch (ret) { + case 0: break; + case 1: return renameBuffer(b, docstring()); + case 2: return false; + } + } + + // Ok, change the name of the buffer + b.setFileName(fname.absFilename()); + b.markDirty(); + bool unnamed = b.isUnnamed(); + b.setUnnamed(false); + b.saveCheckSum(fname); + + if (!saveBuffer(b)) { + b.setFileName(oldname.absFilename()); + b.setUnnamed(unnamed); + b.saveCheckSum(oldname); + return false; + } + + return true; +} + + +bool GuiView::saveBuffer(Buffer & b) +{ + if (b.isUnnamed()) + return renameBuffer(b, docstring()); + + if (b.save()) { + LyX::ref().session().lastFiles().add(b.fileName()); + return true; + } + + // Switch to this Buffer. + setBuffer(&b); + + // FIXME: we don't tell the user *WHY* the save failed !! + docstring const file = makeDisplayPath(b.absFileName(), 30); + docstring text = bformat(_("The document %1$s could not be saved.\n\n" + "Do you want to rename the document and " + "try again?"), file); + int const ret = Alert::prompt(_("Rename and save?"), + text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel")); + switch (ret) { + case 0: + if (!renameBuffer(b, docstring())) + return false; + break; + case 1: + return false; + case 2: + break; + } + + return saveBuffer(b); +} + + +bool GuiView::closeBuffer() +{ + Buffer * buf = buffer(); + return buf && closeBuffer(*buf); +} + + +bool GuiView::closeBuffer(Buffer & buf) +{ + if (buf.isClean() || buf.paragraphs().empty()) { + theBufferList().release(&buf); + return true; + } + // Switch to this Buffer. + setBuffer(&buf); + + docstring file; + // FIXME: Unicode? + if (buf.isUnnamed()) + file = from_utf8(buf.fileName().onlyFileName()); + else + file = buf.fileName().displayName(30); + + docstring const text = bformat(_("The document %1$s has unsaved changes." + "\n\nDo you want to save the document or discard the changes?"), file); + int const ret = Alert::prompt(_("Save changed document?"), + text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel")); + + switch (ret) { + case 0: + if (!saveBuffer(buf)) + return false; + break; + case 1: + // if we crash after this we could + // have no autosave file but I guess + // this is really improbable (Jug) + removeAutosaveFile(buf.absFileName()); + break; + case 2: + return false; + } + + // save file names to .lyx/session + // if master/slave are both open, do not save slave since it + // will be automatically loaded when the master is loaded + if (buf.masterBuffer() == &buf) + LyX::ref().session().lastOpened().add(buf.fileName()); + + theBufferList().release(&buf); + return true; +} + + +bool GuiView::quitWriteAll() +{ + while (!theBufferList().empty()) { + Buffer * b = theBufferList().first(); + if (!closeBuffer(*b)) + return false; + } + return true; +} + + bool GuiView::dispatch(FuncRequest const & cmd) { BufferView * bv = view(); @@ -1153,6 +1340,33 @@ bool GuiView::dispatch(FuncRequest const & cmd) insertPlaintextFile(cmd.argument(), false); break; + case LFUN_BUFFER_WRITE: + if (bv) + saveBuffer(bv->buffer()); + break; + + case LFUN_BUFFER_WRITE_AS: + if (bv) + renameBuffer(bv->buffer(), cmd.argument()); + break; + + case LFUN_BUFFER_WRITE_ALL: { + Buffer * first = theBufferList().first(); + if (!first) + break; + message(_("Saving all documents...")); + // We cannot use a for loop as the buffer list cycles. + Buffer * b = first; + do { + if (b->isClean()) + continue; + saveBuffer(*b); + LYXERR(Debug::ACTION, "Saved " << b->absFileName()); + b = theBufferList().next(b); + } while (b != first); + message(_("All documents saved.")); + break; + } case LFUN_TOOLBAR_TOGGLE: { string const name = cmd.getArg(0); diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h index 91f6eab076..e87f66f265 100644 --- a/src/frontends/qt4/GuiView.h +++ b/src/frontends/qt4/GuiView.h @@ -87,6 +87,10 @@ public: Buffer const * buffer() const; /// set a buffer to the current workarea. void setBuffer(Buffer * b); ///< \c Buffer to set. + /// + bool closeBuffer(); + /// write all buffers, asking the user, returns false if cancelled + bool quitWriteAll(); /// GuiBufferDelegate. ///@{ @@ -238,6 +242,28 @@ private: /// void insertPlaintextFile(docstring const & fname, bool asParagraph); + + /// Save a buffer as a new file. + /** + Write a buffer to a new file name and rename the buffer + according to the new file name. + + This function is e.g. used by menu callbacks and + LFUN_BUFFER_WRITE_AS. + + If 'newname' is empty, the user is asked via a + dialog for the buffer's new name and location. + + If 'newname' is non-empty and has an absolute path, that is used. + Otherwise the base directory of the buffer is used as the base + for any relative path in 'newname'. + */ + bool renameBuffer(Buffer & b, docstring const & newname); + /// + bool saveBuffer(Buffer & b); + /// + bool closeBuffer(Buffer & buf); + /// Inset * getOpenInset(std::string const & name) const; diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index 4099175314..ba1207c283 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -338,7 +338,7 @@ Buffer * loadIfNeeded(Buffer const & parent, InsetCommandParams const & params) child = theBufferList().newBuffer(included_file.absFilename()); if (!child->loadLyXFile(included_file)) { //close the buffer we just opened - theBufferList().close(child, false); + theBufferList().release(child); return 0; } } @@ -372,7 +372,7 @@ void resetParentBuffer(Buffer const * parent, InsetCommandParams const & params, //close the buffer. child->setParent(0); if (close_it) - theBufferList().close(child, false); + theBufferList().release(child); else updateLabels(*child); }