#include "GuiKeySymbol.h"
#include "GuiToc.h"
#include "GuiToolbar.h"
+#include "LayoutBox.h"
#include "Menus.h"
#include "TocModel.h"
#include "BufferView.h"
#include "Converter.h"
#include "Cursor.h"
+#include "CutAndPaste.h"
#include "Encoding.h"
#include "ErrorList.h"
#include "Format.h"
#include "LyXRC.h"
#include "LyXVC.h"
#include "Paragraph.h"
+#include "SpellChecker.h"
#include "TextClass.h"
#include "Text.h"
#include "Toolbars.h"
* FIXME: replace that with a proper model so that we are not limited
* to only one dialog.
*/
- GuiLayoutBox * layout_;
+ LayoutBox * layout_;
///
map<string, Inset *> open_insets_;
if (!settings.contains(icon_key))
return false;
+ //code below is skipped when when ~/.config/LyX is (re)created
setIconSize(settings.value(icon_key).toSize());
#ifdef Q_WS_X11
QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
resize(size);
move(pos);
#else
- if (!restoreGeometry(settings.value("geometry").toByteArray()))
- setGeometry(50, 50, 690, 510);
+ // Work-around for bug #6034: the window ends up in an undetermined
+ // state when trying to restore a maximized window when it is
+ // already maximized.
+ if (!(windowState() & Qt::WindowMaximized))
+ if (!restoreGeometry(settings.value("geometry").toByteArray()))
+ setGeometry(50, 50, 690, 510);
#endif
// Make sure layout is correctly oriented.
setLayoutDirection(qApp->layoutDirection());
// Allow the toc and view-source dock widget to be restored if needed.
- Dialog *d;
- if ((d = findOrBuild("toc", true)))
- // see bug 5082
- d->showView();
- if ((d = findOrBuild("view-source", true)))
- d->showView();
+ Dialog * dialog;
+ if ((dialog = findOrBuild("toc", true)))
+ // see bug 5082. At least setup title and enabled state.
+ // Visibility will be adjusted by restoreState below.
+ dialog->prepareView();
+ if ((dialog = findOrBuild("view-source", true)))
+ dialog->prepareView();
if (!restoreState(settings.value("layout").toByteArray(), 0))
initToolbars();
for (; it != d.toolbars_.end(); ++it)
delete it->second;
d.toolbars_.clear();
- d.layout_ = 0;
+
+ // I don't like doing this here, but the standard toolbar
+ // destroys this object when it's destroyed itself (vfr)
+ d.layout_ = new LayoutBox(*this);
+ d.stack_widget_->addWidget(d.layout_);
+ d.layout_->move(0,0);
// extracts the toolbars from the backend
Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
closing_ = true;
+ writeSession();
+
// it can happen that this event arrives without selecting the view,
// e.g. when clicking the close button on a background window.
setFocus();
- setCurrentWorkArea(currentMainWorkArea());
- while (GuiWorkArea * wa = currentMainWorkArea()) {
- Buffer * b = &wa->bufferView().buffer();
- if (b->parent()) {
- // This is a child document, just close the tab
- // after saving but keep the file loaded.
- if (!closeBuffer(*b, true)) {
- closing_ = false;
- close_event->ignore();
- return;
- }
- continue;
- }
-
- vector<Buffer *> clist = b->getChildren();
- for (vector<Buffer *>::const_iterator it = clist.begin();
- it != clist.end(); ++it) {
- if ((*it)->isClean())
- continue;
- Buffer * c = *it;
- // If a child is dirty, do not close
- // without user intervention
- if (!closeBuffer(*c, false)) {
- closing_ = false;
- close_event->ignore();
- return;
- }
- }
-
- QList<int> const ids = guiApp->viewIds();
- for (int i = 0; i != ids.size(); ++i) {
- if (id_ == ids[i])
- continue;
- if (guiApp->view(ids[i]).workArea(*b)) {
- // FIXME 1: should we put an alert box here that the buffer
- // is viewed elsewhere?
- // FIXME 2: should we try to save this buffer in any case?
- //saveBuffer(b);
-
- // This buffer is also opened in another view, so
- // close the associated work area...
- removeWorkArea(wa);
- // ... but don't close the buffer.
- b = 0;
- break;
- }
- }
- // closeBuffer() needs buffer workArea still alive and set as currrent one, and destroys it
- if (b && !closeBuffer(*b, true)) {
- closing_ = false;
- close_event->ignore();
- return;
- }
+ if (!closeWorkAreaAll()) {
+ closing_ = false;
+ close_event->ignore();
+ return;
}
- // Make sure that nothing will use this close to be closed View.
+ // Make sure that nothing will use this to be closed View.
guiApp->unregisterView(this);
if (isFullScreen()) {
case QEvent::ShortcutOverride: {
-#ifndef Q_WS_X11
- // FIXME bug 4888
+// See bug 4888
+#if (!defined Q_WS_X11) || (QT_VERSION >= 0x040500)
if (isFullScreen() && menuBar()->isHidden()) {
QKeyEvent * ke = static_cast<QKeyEvent*>(e);
// FIXME: we should also try to detect special LyX shortcut such as
if (old_gwa == wa)
return;
+ if (view())
+ cap::saveSelection(view()->cursor());
+
theGuiApp()->setCurrentView(this);
d.current_work_area_ = wa;
for (int i = 0; i != d.splitter_->count(); ++i) {
}
-void GuiView::setLayoutDialog(GuiLayoutBox * layout)
+LayoutBox * GuiView::getLayoutDialog() const
{
- d.layout_ = layout;
+ return d.layout_;
}
void GuiView::disconnectBuffer()
{
if (d.current_work_area_)
- d.current_work_area_->bufferView().setGuiDelegate(0);
+ d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
}
}
-void GuiView::errors(string const & error_type)
+void GuiView::errors(string const & error_type, bool from_master)
{
- ErrorList & el = buffer()->errorList(error_type);
+ ErrorList & el = from_master ?
+ buffer()->masterBuffer()->errorList(error_type)
+ : buffer()->errorList(error_type);
+ string data = error_type;
+ if (from_master)
+ data = "from_master|" + error_type;
if (!el.empty())
- showDialog("errorlist", error_type);
+ showDialog("errorlist", data);
}
bool enable = true;
Buffer * buf = buffer();
- /* In LyX/Mac, when a dialog is open, the menus of the
- application can still be accessed without giving focus to
- the main window. In this case, we want to disable the menu
- entries that are buffer-related.
-
- Note that this code is not perfect, as bug 1941 attests:
- http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
- */
- if (cmd.origin == FuncRequest::MENU && !hasFocus())
- buf = 0;
-
if (cmd.origin == FuncRequest::TOC) {
- //FIXME: dispatch this to the toc
+ GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
+ FuncStatus fs;
+ if (toc->getStatus(view()->cursor(), cmd, fs))
+ flag |= fs;
+ else
+ flag.setEnabled(false);
return true;
}
enable = buf;
break;
+ case LFUN_BUFFER_CLOSE_ALL:
+ enable = theBufferList().last() != theBufferList().first();
+ break;
+
case LFUN_SPLIT_VIEW:
if (cmd.getArg(0) == "vertical")
enable = buf && (d.splitter_->count() == 1 ||
else if (name == "print")
enable = buf->isExportable("dvi")
&& lyxrc.print_command != "none";
- else if (name == "character") {
- if (!view())
+ else if (name == "character" || name == "symbols") {
+ if (buf->isReadonly() || !view() || !view()->cursor().inTexted())
enable = false;
else {
- InsetCode ic = view()->cursor().inset().lyxCode();
- enable = ic != ERT_CODE && ic != LISTINGS_CODE;
- }
- }
- else if (name == "symbols") {
- if (!view() || view()->cursor().inMathed())
- enable = false;
- else {
- InsetCode ic = view()->cursor().inset().lyxCode();
- enable = ic != ERT_CODE && ic != LISTINGS_CODE;
+ // FIXME we should consider passthru
+ // paragraphs too.
+ Inset const & in = view()->cursor().inset();
+ enable = !in.getLayout().isPassThru();
}
}
else if (name == "latexlog")
enable = FileName(buf->logName()).isReadableFile();
else if (name == "spellchecker")
-#if defined (USE_ASPELL)
- enable = !buf->isReadonly();
-#else
- enable = false;
-#endif
+ enable = theSpellChecker() && !buf->isReadonly();
else if (name == "vclog")
enable = buf->lyxvc().inUse();
break;
if (!fullname.onlyPath().isDirectory()) {
Alert::warning(_("Invalid filename"),
- bformat(_("The directory in the given path\n%1$s\ndoes not exists."),
+ bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
from_utf8(fullname.absFilename())));
return;
}
if (!bv)
return;
+ if (!fname.empty() && !FileName::isAbsolute(to_utf8(fname))) {
+ message(_("Absolute filename expected."));
+ return;
+ }
+
// FIXME UNICODE
FileName filename(to_utf8(fname));
}
}
+ FileName oldauto = b.getAutosaveFilename();
+
// Ok, change the name of the buffer
b.setFileName(fname.absFilename());
b.markDirty();
b.setUnnamed(false);
b.saveCheckSum(fname);
+ // bring the autosave file with us, just in case.
+ b.moveAutosaveFile(oldauto);
+
if (!saveBuffer(b)) {
+ oldauto = b.getAutosaveFilename();
b.setFileName(oldname.absFilename());
b.setUnnamed(unnamed);
b.saveCheckSum(oldname);
+ b.moveAutosaveFile(oldauto);
return false;
}
}
+bool GuiView::hideWorkArea(GuiWorkArea * wa)
+{
+ return closeWorkArea(wa, false);
+}
+
+
+bool GuiView::closeWorkArea(GuiWorkArea * wa)
+{
+ Buffer & buf = wa->bufferView().buffer();
+ return closeWorkArea(wa, !buf.parent());
+}
+
+
bool GuiView::closeBuffer()
{
- Buffer * buf = buffer();
- return buf && closeBuffer(*buf);
+ GuiWorkArea * wa = currentMainWorkArea();
+ Buffer & buf = wa->bufferView().buffer();
+ return wa && closeWorkArea(wa, !buf.parent());
+}
+
+
+void GuiView::writeSession() const {
+ GuiWorkArea const * active_wa = currentMainWorkArea();
+ for (int i = 0; i < d.splitter_->count(); ++i) {
+ TabWorkArea * twa = d.tabWorkArea(i);
+ for (int j = 0; j < twa->count(); ++j) {
+ GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
+ Buffer & buf = wa->bufferView().buffer();
+ theSession().lastOpened().add(buf.fileName(), wa == active_wa);
+ }
+ }
+}
+
+
+bool GuiView::closeBufferAll()
+{
+ // Close the workareas in all other views
+ QList<int> const ids = guiApp->viewIds();
+ for (int i = 0; i != ids.size(); ++i) {
+ if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
+ return false;
+ }
+
+ // Close our own workareas
+ if (!closeWorkAreaAll())
+ return false;
+
+ // Now close the hidden buffers. We prevent hidden buffers from being
+ // dirty, so we can just close them.
+ theBufferList().closeAll();
+ return true;
+}
+
+
+bool GuiView::closeWorkAreaAll()
+{
+ // To write in the session file which workarea was active.
+ GuiWorkArea * active_wa = currentMainWorkArea();
+ setCurrentWorkArea(active_wa);
+
+ // We might be in a situation that there is still a tabWorkArea, but
+ // there are no tabs anymore. This can happen when we get here after a
+ // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
+ // many TabWorkArea's have no documents anymore.
+ int empty_twa = 0;
+
+ // We have to call count() each time, because it can happen that
+ // more than one splitter will disappear in one iteration (bug 5998).
+ for (; d.splitter_->count() > empty_twa; ) {
+ TabWorkArea * twa = d.tabWorkArea(empty_twa);
+
+ if (twa->count() == 0)
+ ++empty_twa;
+ else {
+ setCurrentWorkArea(twa->currentWorkArea());
+ if (!closeTabWorkArea(twa, active_wa))
+ return false;
+ }
+ }
+ return true;
}
-bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
+bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer,
+ bool is_active)
{
+ Buffer & buf = wa->bufferView().buffer();
+
+ // If we are in a close_event all children will be closed in some time,
+ // so no need to do it here. This will ensure that the children end up
+ // in the session file in the correct order. If we close the master
+ // buffer, we can close or release the child buffers here too.
+ if (close_buffer && !closing_) {
+ vector<Buffer *> clist = buf.getChildren();
+ for (vector<Buffer *>::const_iterator it = clist.begin();
+ it != clist.end(); ++it) {
+ // If a child is dirty, do not close
+ // without user intervention
+ //FIXME: should we look in other tabworkareas?
+ Buffer * child_buf = *it;
+ GuiWorkArea * child_wa = workArea(*child_buf);
+ if (child_wa) {
+ if (!closeWorkArea(child_wa, true))
+ return false;
+ } else
+ theBufferList().releaseChild(&buf, child_buf);
+ }
+ }
// goto bookmark to update bookmark pit.
//FIXME: we should update only the bookmarks related to this buffer!
LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
theLyXFunc().gotoBookmark(i+1, false, false);
- if (buf.isClean() || buf.paragraphs().empty()) {
+ // if we are only hiding the buffer and there are multiple views
+ // of the buffer, then we do not need to ensure a clean buffer.
+ bool const allow_dirty = inMultiTabs(wa) && !close_buffer;
+
+ if (allow_dirty || saveBufferIfNeeded(buf, !close_buffer)) {
// save in sessions if requested
// do not save childs if their master
// is opened as well
- if (tolastopened)
- theSession().lastOpened().add(buf.fileName());
- if (buf.parent())
- // Don't close child documents.
- removeWorkArea(currentMainWorkArea());
+ if (closing_)
+ theSession().lastOpened().add(buf.fileName(), is_active);
+ if (!close_buffer)
+ removeWorkArea(wa);
else
theBufferList().release(&buf);
return true;
}
+ return false;
+}
+
+
+bool GuiView::closeTabWorkArea(TabWorkArea * twa, GuiWorkArea * main_work_area)
+{
+ while (twa == d.currentTabWorkArea()) {
+ twa->setCurrentIndex(twa->count()-1);
+
+ GuiWorkArea * wa = twa->currentWorkArea();
+ bool const is_active_wa = main_work_area == wa;
+ Buffer & b = wa->bufferView().buffer();
+
+ // We only want to close the buffer if the same buffer is not visible
+ // in another view, and if this is not a child and if we are closing
+ // a view (not a tabgroup).
+ bool const close_buffer =
+ !inMultiViews(wa) && !b.parent() && closing_;
+
+ if (!closeWorkArea(wa, close_buffer, is_active_wa))
+ return false;
+ }
+ return true;
+}
+
+
+bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
+{
+ if (buf.isClean() || buf.paragraphs().empty())
+ return true;
+
// Switch to this Buffer.
setBuffer(&buf);
raise();
activateWindow();
- 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"));
+ int ret;
+ if (hiding && buf.isUnnamed()) {
+ docstring const text = bformat(_("The document %1$s has not been "
+ "saved yet.\n\nDo you want to save "
+ "the document?"), file);
+ ret = Alert::prompt(_("Save new document?"),
+ text, 0, 1, _("&Save"), _("&Cancel"));
+ if (ret == 1)
+ ++ret;
+ } else {
+ docstring const text = bformat(_("The document %1$s has unsaved changes."
+ "\n\nDo you want to save the document or discard the changes?"), file);
+ ret = Alert::prompt(_("Save changed document?"),
+ text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
+ }
switch (ret) {
case 0:
// have no autosave file but I guess
// this is really improbable (Jug)
buf.removeAutosaveFile();
+ if (hiding)
+ // revert all changes
+ buf.loadLyXFile(buf.fileName());
+ buf.markClean();
break;
case 2:
return false;
}
+ return true;
+}
- // save file names to .lyx/session
- if (tolastopened)
- theSession().lastOpened().add(buf.fileName());
- if (buf.parent())
- // Don't close child documents.
- removeWorkArea(currentMainWorkArea());
- else
- theBufferList().release(&buf);
+bool GuiView::inMultiTabs(GuiWorkArea * wa)
+{
+ Buffer & buf = wa->bufferView().buffer();
- return true;
+ for (int i = 0; i != d.splitter_->count(); ++i) {
+ GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
+ if (wa_ && wa_ != wa)
+ return true;
+ }
+ return inMultiViews(wa);
+}
+
+
+bool GuiView::inMultiViews(GuiWorkArea * wa)
+{
+ QList<int> const ids = guiApp->viewIds();
+ Buffer & buf = wa->bufferView().buffer();
+
+ int found_twa = 0;
+ for (int i = 0; i != ids.size() && found_twa <= 1; ++i) {
+ if (id_ == ids[i])
+ continue;
+
+ if (guiApp->view(ids[i]).workArea(buf))
+ return true;
+ }
+ return false;
}
importDocument(to_utf8(cmd.argument()));
break;
- case LFUN_BUFFER_SWITCH: {
- Buffer * buffer =
- theBufferList().getBuffer(FileName(to_utf8(cmd.argument())));
- if (buffer)
- setBuffer(buffer);
- else
- bv->cursor().message(_("Document not loaded"));
+ case LFUN_BUFFER_SWITCH:
+ if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
+ Buffer * buffer =
+ theBufferList().getBuffer(FileName(to_utf8(cmd.argument())));
+ if (buffer)
+ setBuffer(buffer);
+ else
+ bv->cursor().message(_("Document not loaded"));
+ }
break;
- }
case LFUN_BUFFER_NEXT:
gotoNextOrPreviousBuffer(NEXTBUFFER);
break;
}
case LFUN_DROP_LAYOUTS_CHOICE:
- if (d.layout_)
- d.layout_->showPopup();
+ d.layout_->showPopup();
break;
case LFUN_MENU_OPEN:
case LFUN_CLOSE_TAB_GROUP:
if (TabWorkArea * twa = d.currentTabWorkArea()) {
- delete twa;
+ closeTabWorkArea(twa, false);
+ d.current_work_area_ = 0;
twa = d.currentTabWorkArea();
// Switch to the next GuiWorkArea in the found TabWorkArea.
if (twa) {
// Part of automatic menu appearance feature.
if (isFullScreen()) {
- if (menuBar()->isVisible())
+ if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
menuBar()->hide();
if (statusBar()->isVisible())
statusBar()->hide();
saveLayout();
setWindowState(windowState() ^ Qt::WindowFullScreen);
statusBar()->hide();
- menuBar()->hide();
+ if (lyxrc.full_screen_menubar)
+ menuBar()->hide();
if (lyxrc.full_screen_toolbars) {
ToolbarMap::iterator end = d.toolbars_.end();
for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
char const * const dialognames[] = {
"aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
"citation", "document", "errorlist", "ert", "external", "file", "findreplace",
-"float", "graphics", "include", "index", "info", "nomenclature", "label",
-"log", "mathdelimiter", "mathmatrix", "mathspace", "note", "paragraph",
-"phantom", "prefs", "print", "ref", "sendto", "space", "spellchecker",
-"symbols", "tabular", "tabularcreate",
-
-#ifdef HAVE_LIBAIKSAURUS
-"thesaurus",
-#endif
-
-"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings", "findreplaceadv" };
+"findreplaceadv", "float", "graphics", "href", "include", "index",
+"index_print", "info", "listings", "label", "log", "mathdelimiter",
+"mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note",
+"paragraph", "phantom", "prefs", "print", "ref", "sendto", "space",
+"spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo",
+"toc", "view-source", "vspace", "wrap" };
char const * const * const end_dialognames =
dialognames + (sizeof(dialognames) / sizeof(char *));
menuBar()->clear();
constructToolbars();
guiApp->menus().fillMenuBar(menuBar(), this, false);
- if (d.layout_)
- d.layout_->updateContents(true);
+ d.layout_->updateContents(true);
// Now update controls with current buffer.
theLyXFunc().setLyXView(this);
restoreLayout();
map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
if (it == d.dialogs_.end())
return false;
- return it->second.get()->isVisibleView();
+ return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
}
Dialog * createGuiFloat(GuiView & lv);
Dialog * createGuiGraphics(GuiView & lv);
Dialog * createGuiInclude(GuiView & lv);
+Dialog * createGuiIndex(GuiView & lv);
Dialog * createGuiInfo(GuiView & lv);
Dialog * createGuiLabel(GuiView & lv);
Dialog * createGuiListings(GuiView & lv);
Dialog * createGuiPhantom(GuiView & lv);
Dialog * createGuiPreferences(GuiView & lv);
Dialog * createGuiPrint(GuiView & lv);
+Dialog * createGuiPrintindex(GuiView & lv);
+Dialog * createGuiPrintNomencl(GuiView & lv);
Dialog * createGuiRef(GuiView & lv);
Dialog * createGuiSearch(GuiView & lv);
Dialog * createGuiSearchAdv(GuiView & lv);
return createGuiFloat(*this);
if (name == "graphics")
return createGuiGraphics(*this);
+ if (name == "href")
+ return createGuiHyperlink(*this);
if (name == "include")
return createGuiInclude(*this);
+ if (name == "index")
+ return createGuiIndex(*this);
+ if (name == "index_print")
+ return createGuiPrintindex(*this);
if (name == "info")
return createGuiInfo(*this);
- if (name == "nomenclature")
- return createGuiNomenclature(*this);
if (name == "label")
return createGuiLabel(*this);
+ if (name == "listings")
+ return createGuiListings(*this);
if (name == "log")
return createGuiLog(*this);
if (name == "mathdelimiter")
return createGuiMathHSpace(*this);
if (name == "mathmatrix")
return createGuiMathMatrix(*this);
+ if (name == "nomenclature")
+ return createGuiNomenclature(*this);
+ if (name == "nomencl_print")
+ return createGuiPrintNomencl(*this);
if (name == "note")
return createGuiNote(*this);
if (name == "paragraph")
return createGuiTabularCreate(*this);
if (name == "texinfo")
return createGuiTexInfo(*this);
- if (name == "view-source")
- return createGuiViewSource(*this);
-#ifdef HAVE_LIBAIKSAURUS
if (name == "thesaurus")
return createGuiThesaurus(*this);
-#endif
- if (name == "href")
- return createGuiHyperlink(*this);
- if (name == "listings")
- return createGuiListings(*this);
if (name == "toc")
return createGuiToc(*this);
+ if (name == "view-source")
+ return createGuiViewSource(*this);
if (name == "vspace")
return createGuiVSpace(*this);
if (name == "wrap")