mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 10:58:52 +00:00
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
This commit is contained in:
parent
2ac7c35667
commit
ac08e89095
155
src/Buffer.cpp
155
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) {
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<Buffer *> BufferStorage;
|
||||
|
||||
/// storage of all buffers
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user