#include <config.h>
#include "GuiView.h"
-#include "Dialog.h"
+#include "Dialog.h"
+#include "frontends/FileDialog.h"
#include "GuiApplication.h"
#include "GuiWorkArea.h"
#include "GuiKeySymbol.h"
#include "GuiMenubar.h"
#include "GuiToolbar.h"
#include "GuiToolbars.h"
+#include "GuiProgress.h"
#include "qt_helpers.h"
+#include "frontends/alert.h"
+
#include "buffer_funcs.h"
#include "Buffer.h"
#include "BufferList.h"
#include "BufferParams.h"
#include "BufferView.h"
#include "Cursor.h"
-#include "debug.h"
+#include "support/debug.h"
#include "ErrorList.h"
#include "FuncRequest.h"
-#include "gettext.h"
+#include "support/gettext.h"
#include "Intl.h"
#include "Layout.h"
#include "Lexer.h"
#include "ToolbarBackend.h"
#include "version.h"
+#include "support/FileFilterList.h"
#include "support/FileName.h"
+#include "support/filetools.h"
#include "support/lstrings.h"
#include "support/os.h"
+#include "support/Package.h"
#include "support/Timeout.h"
#include <QAction>
namespace frontend {
+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 {
~GuiViewPrivate()
{
delete splitter_;
- delete stack_widget_;
delete bg_widget_;
+ delete stack_widget_;
delete menubar_;
delete toolbars_;
}
// 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;
}
string const file = support::os::internal_path(fromqstr(
files.at(i).toLocalFile()));
if (!file.empty())
- dispatch(FuncRequest(LFUN_FILE_OPEN, file));
+ lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
}
}
}
-void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
+void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
{
- BOOST_ASSERT(work_area);
+ BOOST_ASSERT(wa);
// Changing work area can result from opening a file so
// update the toc in any case.
updateToc();
- GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
d.current_work_area_ = wa;
for (int i = 0; i != d.splitter_->count(); ++i) {
if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
}
-void GuiView::removeWorkArea(GuiWorkArea * work_area)
+void GuiView::removeWorkArea(GuiWorkArea * wa)
{
- BOOST_ASSERT(work_area);
- GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
- if (gwa == d.current_work_area_) {
+ BOOST_ASSERT(wa);
+ if (wa == d.current_work_area_) {
disconnectBuffer();
disconnectBufferView();
hideBufferDependent();
d.current_work_area_ = 0;
}
- // removing a work area often results from closing a file so
- // update the toc in any case.
- updateToc();
-
for (int i = 0; i != d.splitter_->count(); ++i) {
TabWorkArea * twa = d.tabWorkArea(i);
- if (!twa->removeWorkArea(gwa))
+ if (!twa->removeWorkArea(wa))
// Not found in this tab group.
continue;
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;
}
}
else if (name == "latexlog")
- enable = FileName(buf->logName()).isFileReadable();
+ enable = FileName(buf->logName()).isReadableFile();
else if (name == "spellchecker")
#if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
enable = !buf->isReadonly();
}
-void GuiView::dispatch(FuncRequest const & cmd)
+static FileName selectTemplateFile()
+{
+ FileDialog dlg(_("Select template file"));
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
+
+ FileDialog::Result result =
+ dlg.open(from_utf8(lyxrc.template_path),
+ FileFilterList(_("LyX Documents (*.lyx)")),
+ docstring());
+
+ if (result.first == FileDialog::Later)
+ return FileName();
+ if (result.second.empty())
+ return FileName();
+ return FileName(to_utf8(result.second));
+}
+
+
+void GuiView::newDocument(string const & filename, bool from_template)
{
- // By default we won't need any new update.
- Update::flags update_flags = Update::None;
+ FileName initpath(lyxrc.document_path);
+ Buffer * buf = buffer();
+ if (buf) {
+ FileName const trypath(buf->filePath());
+ // If directory is writeable, use this as default.
+ if (trypath.isDirWritable())
+ initpath = trypath;
+ }
+
+ string templatefile = from_template ?
+ selectTemplateFile().absFilename() : string();
+ Buffer * b;
+ if (filename.empty())
+ b = newUnnamedFile(templatefile, initpath);
+ else
+ b = newFile(filename, templatefile, true);
+
+ if (b)
+ setBuffer(b);
+}
+
+
+void GuiView::insertLyXFile(docstring const & fname)
+{
+ BufferView * bv = view();
+ if (!bv)
+ return;
+
+ // FIXME UNICODE
+ FileName filename(to_utf8(fname));
+
+ if (!filename.empty()) {
+ bv->insertLyXFile(filename);
+ return;
+ }
+
+ // Launch a file browser
+ // FIXME UNICODE
+ string initpath = lyxrc.document_path;
+ string const trypath = bv->buffer().filePath();
+ // If directory is writeable, use this as default.
+ if (FileName(trypath).isDirWritable())
+ initpath = trypath;
+
+ // FIXME UNICODE
+ FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton2(_("Examples|#E#e"),
+ from_utf8(addPath(package().system_support().absFilename(),
+ "examples")));
+
+ FileDialog::Result result =
+ dlg.open(from_utf8(initpath),
+ FileFilterList(_("LyX Documents (*.lyx)")),
+ docstring());
+
+ if (result.first == FileDialog::Later)
+ return;
+
+ // FIXME UNICODE
+ filename.set(to_utf8(result.second));
+
+ // check selected filename
+ if (filename.empty()) {
+ // emit message signal.
+ message(_("Canceled."));
+ return;
+ }
+
+ bv->insertLyXFile(filename);
+}
+
+
+void GuiView::insertPlaintextFile(docstring const & fname,
+ bool asParagraph)
+{
+ BufferView * bv = view();
+ if (!bv)
+ return;
+
+ // FIXME UNICODE
+ FileName filename(to_utf8(fname));
+
+ if (!filename.empty()) {
+ bv->insertPlaintextFile(filename, asParagraph);
+ return;
+ }
+
+ FileDialog dlg(_("Select file to insert"), (asParagraph ?
+ LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
+
+ FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
+ FileFilterList(), docstring());
+
+ if (result.first == FileDialog::Later)
+ return;
+
+ // FIXME UNICODE
+ filename.set(to_utf8(result.second));
+
+ // check selected filename
+ if (filename.empty()) {
+ // emit message signal.
+ message(_("Canceled."));
+ return;
+ }
+
+ bv->insertPlaintextFile(filename, asParagraph);
+}
+
+
+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();
+ // By default we won't need any update.
+ if (bv)
+ bv->cursor().updateFlags(Update::None);
switch(cmd.action) {
case LFUN_BUFFER_SWITCH:
setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
break;
+ case LFUN_BUFFER_NEXT:
+ setBuffer(theBufferList().next(buffer()));
+ break;
+
+ case LFUN_BUFFER_PREVIOUS:
+ setBuffer(theBufferList().previous(buffer()));
+ break;
+
case LFUN_COMMAND_EXECUTE: {
bool const show_it = cmd.argument() != "off";
d.toolbars_->showCommandBuffer(show_it);
d.menubar_->openByName(toqstr(cmd.argument()));
break;
+ case LFUN_FILE_INSERT:
+ insertLyXFile(cmd.argument());
+ break;
+ case LFUN_FILE_INSERT_PLAINTEXT_PARA:
+ insertPlaintextFile(cmd.argument(), true);
+ break;
+
+ case LFUN_FILE_INSERT_PLAINTEXT:
+ 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);
bool const allowauto = cmd.getArg(1) == "allowauto";
if (inset) {
FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
inset->dispatch(view()->cursor(), fr);
- // ideally, the update flag should be set by the insets,
- // but this is not possible currently
- update_flags = Update::Force | Update::FitCursor;
} else {
FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
lyx::dispatch(fr);
}
default:
- theLyXFunc().setLyXView(this);
- lyx::dispatch(cmd);
+ return false;
}
- if (view())
- view()->cursor().updateFlags(update_flags);
+ return true;
}
"thesaurus",
#endif
-"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
+"texinfo", "toc", "href", "view-source", "latex-progress", "vspace", "wrap", "listings" };
char const * const * const end_dialognames =
dialognames + (sizeof(dialognames) / sizeof(char *));
Dialog * const dialog = it->second.get();
if (dialog->isVisibleView())
- dialog->hide();
+ dialog->hideView();
d.open_insets_[name] = 0;
}
std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
for(; it != end; ++it)
- it->second->hide();
+ it->second->hideView();
}
for(; it != end; ++it) {
Dialog * dialog = it->second.get();
if (dialog->isBufferDependent())
- dialog->hide();
+ dialog->hideView();
}
}
for(; it != end; ++it) {
Dialog * dialog = it->second.get();
+ if (!dialog->isVisibleView())
+ continue;
if (switched && dialog->isBufferDependent()) {
- if (dialog->isVisibleView() && dialog->initialiseParams(""))
+ if (dialog->initialiseParams(""))
dialog->updateView();
else
- dialog->hide();
+ dialog->hideView();
} else {
// A bit clunky, but the dialog will request
// that the kernel provides it with the necessary
Dialog * createGuiHyperlink(GuiView & lv);
Dialog * createGuiVSpace(GuiView & lv);
Dialog * createGuiViewSource(GuiView & lv);
+Dialog * createGuiProgress(GuiView & lv);
Dialog * createGuiWrap(GuiView & lv);
return createGuiLog(*this);
if (name == "view-source")
return createGuiViewSource(*this);
+ if (name == "latex-progress")
+ return createGuiProgress(*this);
if (name == "mathdelimiter")
return createGuiDelimiter(*this);
if (name == "mathmatrix")