X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=ba6b33dd0c7f6c7893996710ecffbc9c1e77f21f;hb=4e223167ff2872ee123c8354d486352c8a368102;hp=af555a69bdb735fc6b0be25696a7a2d033e218c2;hpb=7c392af6eab5e06a4836146859cbd9f2c3764420;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index af555a69bd..ba6b33dd0c 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -16,13 +16,13 @@ #include "GuiView.h" #include "Dialog.h" -#include "frontends/FileDialog.h" +#include "FileDialog.h" #include "GuiApplication.h" #include "GuiWorkArea.h" #include "GuiKeySymbol.h" -#include "GuiMenubar.h" #include "GuiToolbar.h" #include "GuiToolbars.h" +#include "Menus.h" #include "qt_helpers.h" @@ -33,9 +33,11 @@ #include "BufferList.h" #include "BufferParams.h" #include "BufferView.h" +#include "Converter.h" #include "Cursor.h" -#include "support/debug.h" #include "ErrorList.h" +#include "Format.h" +#include "FuncStatus.h" #include "FuncRequest.h" #include "support/gettext.h" #include "Intl.h" @@ -45,16 +47,17 @@ #include "LyX.h" #include "LyXRC.h" #include "LyXVC.h" -#include "MenuBackend.h" #include "Paragraph.h" #include "TextClass.h" #include "Text.h" #include "ToolbarBackend.h" #include "version.h" +#include "support/debug.h" #include "support/FileFilterList.h" #include "support/FileName.h" #include "support/filetools.h" +#include "support/ForkedCalls.h" #include "support/lstrings.h" #include "support/os.h" #include "support/Package.h" @@ -69,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +85,7 @@ #include #include #include +#include #include #include @@ -96,9 +101,6 @@ using namespace std; using namespace lyx::support; namespace lyx { - -extern bool quitting; - namespace frontend { namespace { @@ -144,8 +146,8 @@ typedef boost::shared_ptr DialogPtr; struct GuiView::GuiViewPrivate { GuiViewPrivate() - : current_work_area_(0), layout_(0), - quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false) + : current_work_area_(0), layout_(0), autosave_timeout_(5000), + in_show_(false) { // hardcode here the platform specific icon size smallIconSize = 14; // scaling problems @@ -165,7 +167,6 @@ struct GuiView::GuiViewPrivate delete splitter_; delete bg_widget_; delete stack_widget_; - delete menubar_; delete toolbars_; } @@ -224,17 +225,14 @@ struct GuiView::GuiViewPrivate // The first TabWorkArea is always the first one, if any. return tabWorkArea(0); - TabWorkArea * tab_widget = 0; for (int i = 0; i != splitter_->count(); ++i) { - QWidget * w = splitter_->widget(i); - if (!w->hasFocus()) - continue; - tab_widget = dynamic_cast(w); - if (tab_widget) - break; + TabWorkArea * twa = tabWorkArea(i); + if (current_work_area_ == twa->currentWorkArea()) + return twa; } - return tab_widget; + // None has the focus so we just take the first one. + return tabWorkArea(0); } public: @@ -242,8 +240,6 @@ public: QSplitter * splitter_; QStackedWidget * stack_widget_; BackgroundWidget * bg_widget_; - /// view's menubar - GuiMenubar * menubar_; /// view's toolbars GuiToolbars * toolbars_; /// The main layout box. @@ -268,8 +264,6 @@ public: unsigned int bigIconSize; /// QTimer statusbar_timer_; - /// are we quitting by the menu? - bool quitting_by_menu_; /// auto-saving of buffers Timeout autosave_timeout_; /// flag against a race condition due to multiclicks, see bug #1119 @@ -280,9 +274,16 @@ public: GuiView::GuiView(int id) : d(*new GuiViewPrivate), id_(id) { - // GuiToolbars *must* be initialised before GuiMenubar. + // GuiToolbars *must* be initialised before the menu bar. d.toolbars_ = new GuiToolbars(*this); - d.menubar_ = new GuiMenubar(this, menubackend); + + // set ourself as the current view. This is needed for the menu bar + // filling, at least for the static special menu item on Mac. Otherwise + // they are greyed out. + theLyXFunc().setLyXView(this); + + // Fill up the menu bar. + guiApp->menus().fillMenuBar(menuBar(), this); setCentralWidget(d.stack_widget_); @@ -295,9 +296,9 @@ GuiView::GuiView(int id) connect(&d.statusbar_timer_, SIGNAL(timeout()), this, SLOT(clearMessage())); - // Qt bug? signal lastWindowClosed does not work - setAttribute(Qt::WA_QuitOnClose, false); + // We don't want to keep the window in memory if it is closed. setAttribute(Qt::WA_DeleteOnClose, true); + #ifndef Q_WS_MACX // assign an icon to main form. We do not do it under Qt/Mac, // since the icon is provided in the application bundle. @@ -339,20 +340,6 @@ GuiView::~GuiView() } -void GuiView::close() -{ - d.quitting_by_menu_ = true; - d.current_work_area_ = 0; - for (int i = 0; i != d.splitter_->count(); ++i) { - TabWorkArea * twa = d.tabWorkArea(i); - if (twa) - twa->closeAll(); - } - QMainWindow::close(); - d.quitting_by_menu_ = false; -} - - void GuiView::setFocus() { if (d.current_work_area_) @@ -384,10 +371,41 @@ void GuiView::showEvent(QShowEvent * e) 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 (!quitWriteAll()) { + // it can happen that this event arrives without selecting the view, + // e.g. when clicking the close button on a background window. + theLyXFunc().setLyXView(this); + + while (Buffer * b = buffer()) { + if (b->parent()) { + // This is a child document, just close the tab after saving + // but keep the file loaded. + if (!saveBuffer(*b)) { + close_event->ignore(); + return; + } + removeWorkArea(d.current_work_area_); + continue; + } + + std::vector const & ids = guiApp->viewIds(); + for (size_type 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 + // but close the associated work area nevertheless. + removeWorkArea(d.current_work_area_); + // but don't close it. + b = 0; + break; + } + } + if (b && !closeBuffer(*b)) { close_event->ignore(); return; } @@ -395,10 +413,19 @@ void GuiView::closeEvent(QCloseEvent * close_event) // Make sure that no LFUN use this close to be closed View. theLyXFunc().setLyXView(0); + + // Save toolbars configuration + if (isFullScreen()) { + d.toolbars_->toggleFullScreen(!isFullScreen()); + updateToolbars(); + } + // Make sure the timer time out will not trigger a statusbar update. d.statusbar_timer_.stop(); - if (lyxrc.allow_geometry_session) { + // Saving fullscreen requires additional tweaks in the toolbar code. + // It wouldn't also work under linux natively. + if (lyxrc.allow_geometry_session && !isFullScreen()) { QSettings settings; QString const key = "view-" + QString::number(id_); #ifdef Q_WS_X11 @@ -416,20 +443,7 @@ void GuiView::closeEvent(QCloseEvent * close_event) } guiApp->unregisterView(id_); - if (guiApp->viewCount() > 0) { - // Just close the window and do nothing else if this is not the - // last window. - close_event->accept(); - return; - } - - quitting = true; - - // this is the place where we leave the frontend. - // it is the only point at which we start quitting. close_event->accept(); - // quit the event loop - qApp->quit(); } @@ -461,6 +475,9 @@ void GuiView::dropEvent(QDropEvent* event) void GuiView::message(docstring const & str) { + if (ForkedProcess::iAmAChild()) + return; + statusBar()->showMessage(toqstr(str)); d.statusbar_timer_.stop(); d.statusbar_timer_.start(3000); @@ -526,12 +543,29 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa) } +void GuiView::on_lastWorkAreaRemoved() +{ +#ifdef Q_WS_MAC + // On Mac close the view if there is no Tab open anymore, + // but only if no splitter is visible + if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) { + TabWorkArea * twa = qobject_cast(d.splitter_->widget(0)); + if (twa && twa->count() == 0) { + // close the view, as no tab is open anymore + QTimer::singleShot(0, this, SLOT(close())); + } + } +#endif +} + + void GuiView::updateStatusBar() { // let the user see the explicit message if (d.statusbar_timer_.isActive()) return; + theLyXFunc().setLyXView(this); statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage())); } @@ -562,6 +596,10 @@ bool GuiView::event(QEvent * e) // break; case QEvent::WindowActivate: { + if (this == guiApp->currentView()) { + setFocus(); + return QMainWindow::event(e); + } guiApp->setCurrentView(*this); if (d.current_work_area_) { BufferView & bv = d.current_work_area_->bufferView(); @@ -570,30 +608,40 @@ bool GuiView::event(QEvent * e) // The document structure, name and dialogs might have // changed in another view. updateBufferDependent(true); + updateToolbars(); + updateLayoutList(); + updateStatusBar(); } else { setWindowTitle(qt_("LyX")); setWindowIconText(qt_("LyX")); } + setFocus(); return QMainWindow::event(e); } + case QEvent::ShortcutOverride: { + if (d.current_work_area_) + // Nothing special to do. + return QMainWindow::event(e); + QKeyEvent * ke = static_cast(e); - if (!d.current_work_area_) { - theLyXFunc().setLyXView(this); - KeySymbol sym; - setKeySymbol(&sym, ke); - theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers())); - e->accept(); - return true; - } - if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { - KeySymbol sym; - setKeySymbol(&sym, ke); - d.current_work_area_->processKeySym(sym, NoModifier); - e->accept(); - return true; - } + + // Let Qt handle menu access and the Tab keys to navigate keys to navigate + // between controls. + if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab + || ke->key() == Qt::Key_Backtab) + return QMainWindow::event(e); + + // Allow processing of shortcuts that are allowed even when no Buffer + // is viewed. + theLyXFunc().setLyXView(this); + KeySymbol sym; + setKeySymbol(&sym, ke); + theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers())); + e->accept(); + return true; } + default: return QMainWindow::event(e); } @@ -607,17 +655,17 @@ bool GuiView::focusNextPrevChild(bool /*next*/) } -void GuiView::setBusy(bool yes) +void GuiView::setBusy(bool busy) { if (d.current_work_area_) { - d.current_work_area_->setUpdatesEnabled(!yes); - if (yes) + d.current_work_area_->setUpdatesEnabled(!busy); + if (busy) d.current_work_area_->stopBlinkingCursor(); else d.current_work_area_->startBlinkingCursor(); } - if (yes) + if (busy) QApplication::setOverrideCursor(Qt::WaitCursor); else QApplication::restoreOverrideCursor(); @@ -673,34 +721,32 @@ GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline) GuiWorkArea * GuiView::workArea(Buffer & buffer) { - for (int i = 0; i != d.splitter_->count(); ++i) { - GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer); - if (wa) - return wa; - } + if (TabWorkArea * twa = d.currentTabWorkArea()) + return twa->workArea(buffer); return 0; } GuiWorkArea * GuiView::addWorkArea(Buffer & buffer) { - // Automatically create a TabWorkArea if there are none yet. - if (!d.splitter_->count()) - addTabWorkArea(); - - TabWorkArea * tab_widget = d.currentTabWorkArea(); + TabWorkArea * tab_widget = d.splitter_->count() + ? d.currentTabWorkArea() : addTabWorkArea(); return tab_widget->addWorkArea(buffer, *this); } -void GuiView::addTabWorkArea() +TabWorkArea * GuiView::addTabWorkArea() { TabWorkArea * twa = new TabWorkArea; QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)), this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *))); + QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()), + this, SLOT(on_lastWorkAreaRemoved())); + d.splitter_->addWidget(twa); d.stack_widget_->setCurrentWidget(d.splitter_); + return twa; } @@ -787,10 +833,12 @@ void GuiView::updateToolbars() bool const review = lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true); + bool const mathmacrotemplate = + lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled(); - d.toolbars_->update(math, table, review); + d.toolbars_->update(math, table, review, mathmacrotemplate); } else - d.toolbars_->update(false, false, false); + d.toolbars_->update(false, false, false, false); // update read-only status of open dialogs. checkStatus(); @@ -943,6 +991,14 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd) enable = buf; break; + case LFUN_SPLIT_VIEW: + enable = buf; + break; + + case LFUN_CLOSE_TAB_GROUP: + enable = d.currentTabWorkArea(); + break; + case LFUN_TOOLBAR_TOGGLE: flag.setOnOff(d.toolbars_->visible(cmd.getArg(0))); break; @@ -968,6 +1024,14 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd) 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; + } + } else if (name == "latexlog") enable = FileName(buf->logName()).isReadableFile(); else if (name == "spellchecker") @@ -1011,6 +1075,24 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd) break; } + case LFUN_COMPLETION_INLINE: + if (!d.current_work_area_ + || !d.current_work_area_->completer().inlinePossible(view()->cursor())) + enable = false; + break; + + case LFUN_COMPLETION_POPUP: + if (!d.current_work_area_ + || !d.current_work_area_->completer().popupPossible(view()->cursor())) + enable = false; + break; + + case LFUN_COMPLETION_COMPLETE: + if (!d.current_work_area_ + || !d.current_work_area_->completer().inlinePossible(view()->cursor())) + enable = false; + break; + default: if (!view()) { enable = false; @@ -1027,20 +1109,265 @@ FuncStatus GuiView::getStatus(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 dlg(qt_("Select template file")); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); FileDialog::Result result = - dlg.open(from_utf8(lyxrc.template_path), - FileFilterList(_("LyX Documents (*.lyx)")), - docstring()); + dlg.open(toqstr(lyxrc.template_path), + FileFilterList(_("LyX Documents (*.lyx)"))); if (result.first == FileDialog::Later) return FileName(); - if (result.second.empty()) + if (result.second.isEmpty()) return FileName(); - return FileName(to_utf8(result.second)); + return FileName(fromqstr(result.second)); +} + + +Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles) +{ + setBusy(true); + + Buffer * newBuffer = checkAndLoadLyXFile(filename); + + if (!newBuffer) { + message(_("Document not loaded.")); + setBusy(false); + return 0; + } + + setBuffer(newBuffer); + + // scroll to the position when the file was last closed + if (lyxrc.use_lastfilepos) { + LastFilePosSection::FilePos filepos = + LyX::ref().session().lastFilePos().load(filename); + view()->moveToPosition(filepos.pit, filepos.pos, 0, 0); + } + + if (tolastfiles) + LyX::ref().session().lastFiles().add(filename); + + setBusy(false); + return newBuffer; +} + + +void GuiView::openDocument(string const & fname) +{ + string initpath = lyxrc.document_path; + + if (buffer()) { + string const trypath = buffer()->filePath(); + // If directory is writeable, use this as default. + if (FileName(trypath).isDirWritable()) + initpath = trypath; + } + + string filename; + + if (fname.empty()) { + FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton2(qt_("Examples|#E#e"), + toqstr(addPath(package().system_support().absFilename(), "examples"))); + + FileDialog::Result result = + dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)"))); + + if (result.first == FileDialog::Later) + return; + + filename = fromqstr(result.second); + + // check selected filename + if (filename.empty()) { + message(_("Canceled.")); + return; + } + } else + filename = fname; + + // get absolute path of file and add ".lyx" to the filename if + // necessary. + FileName const fullname = + fileSearch(string(), filename, "lyx", support::may_not_exist); + if (!fullname.empty()) + filename = fullname.absFilename(); + + // if the file doesn't exist, let the user create one + if (!fullname.exists()) { + // the user specifically chose this name. Believe him. + Buffer * const b = newFile(filename, string(), true); + if (b) + setBuffer(b); + return; + } + + docstring const disp_fn = makeDisplayPath(filename); + message(bformat(_("Opening document %1$s..."), disp_fn)); + + docstring str2; + Buffer * buf = loadDocument(fullname); + if (buf) { + updateLabels(*buf); + + setBuffer(buf); + buf->errors("Parse"); + str2 = bformat(_("Document %1$s opened."), disp_fn); + } else { + str2 = bformat(_("Could not open document %1$s"), disp_fn); + } + message(str2); +} + +// FIXME: clean that +static bool import(GuiView * lv, FileName const & filename, + string const & format, ErrorList & errorList) +{ + FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx")); + + string loader_format; + vector loaders = theConverters().loaders(); + if (find(loaders.begin(), loaders.end(), format) == loaders.end()) { + for (vector::const_iterator it = loaders.begin(); + it != loaders.end(); ++it) { + if (!theConverters().isReachable(format, *it)) + continue; + + string const tofile = + support::changeExtension(filename.absFilename(), + formats.extension(*it)); + if (!theConverters().convert(0, filename, FileName(tofile), + filename, format, *it, errorList)) + return false; + loader_format = *it; + break; + } + if (loader_format.empty()) { + frontend::Alert::error(_("Couldn't import file"), + bformat(_("No information for importing the format %1$s."), + formats.prettyName(format))); + return false; + } + } else + loader_format = format; + + if (loader_format == "lyx") { + Buffer * buf = lv->loadDocument(lyxfile); + if (!buf) + return false; + updateLabels(*buf); + lv->setBuffer(buf); + buf->errors("Parse"); + } else { + Buffer * const b = newFile(lyxfile.absFilename(), string(), true); + if (!b) + return false; + lv->setBuffer(b); + bool as_paragraphs = loader_format == "textparagraph"; + string filename2 = (loader_format == format) ? filename.absFilename() + : support::changeExtension(filename.absFilename(), + formats.extension(loader_format)); + lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs); + theLyXFunc().setLyXView(lv); + lyx::dispatch(FuncRequest(LFUN_MARK_OFF)); + } + + return true; +} + + +void GuiView::importDocument(string const & argument) +{ + string format; + string filename = split(argument, format, ' '); + + LYXERR(Debug::INFO, format << " file: " << filename); + + // need user interaction + if (filename.empty()) { + string initpath = lyxrc.document_path; + + Buffer const * buf = buffer(); + if (buf) { + string const trypath = buf->filePath(); + // If directory is writeable, use this as default. + if (FileName(trypath).isDirWritable()) + initpath = trypath; + } + + docstring const text = bformat(_("Select %1$s file to import"), + formats.prettyName(format)); + + FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton2(qt_("Examples|#E#e"), + toqstr(addPath(package().system_support().absFilename(), "examples"))); + + docstring filter = formats.prettyName(format); + filter += " (*."; + // FIXME UNICODE + filter += from_utf8(formats.extension(format)); + filter += ')'; + + FileDialog::Result result = + dlg.open(toqstr(initpath), FileFilterList(filter)); + + if (result.first == FileDialog::Later) + return; + + filename = fromqstr(result.second); + + // check selected filename + if (filename.empty()) + message(_("Canceled.")); + } + + if (filename.empty()) + return; + + // get absolute path of file + FileName const fullname(makeAbsPath(filename)); + + FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx")); + + // Check if the document already is open + Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename()); + if (buf) { + setBuffer(buf); + if (!closeBuffer()) { + message(_("Canceled.")); + return; + } + } + + docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30); + + // if the file exists already, and we didn't do + // -i lyx thefile.lyx, warn + if (lyxfile.exists() && fullname != lyxfile) { + + docstring text = bformat(_("The document %1$s already exists.\n\n" + "Do you want to overwrite that document?"), displaypath); + int const ret = Alert::prompt(_("Overwrite document?"), + text, 0, 1, _("&Overwrite"), _("&Cancel")); + + if (ret == 1) { + message(_("Canceled.")); + return; + } + } + + message(bformat(_("Importing %1$s..."), displaypath)); + ErrorList errorList; + if (import(this, fullname, format, errorList)) + message(_("imported.")); + else + message(_("file not imported!")); + + // FIXME (Abdel 12/08/06): Is there a need to display the error list here? } @@ -1065,6 +1392,8 @@ void GuiView::newDocument(string const & filename, bool from_template) if (b) setBuffer(b); + // Ensure the cursor is correctly positionned on screen. + view()->showCursor(); } @@ -1091,22 +1420,21 @@ void GuiView::insertLyXFile(docstring const & fname) 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(), + FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton2(qt_("Examples|#E#e"), + toqstr(addPath(package().system_support().absFilename(), "examples"))); FileDialog::Result result = - dlg.open(from_utf8(initpath), - FileFilterList(_("LyX Documents (*.lyx)")), - docstring()); + dlg.open(toqstr(initpath), + FileFilterList(_("LyX Documents (*.lyx)"))); if (result.first == FileDialog::Later) return; // FIXME UNICODE - filename.set(to_utf8(result.second)); + filename.set(fromqstr(result.second)); // check selected filename if (filename.empty()) { @@ -1134,17 +1462,17 @@ void GuiView::insertPlaintextFile(docstring const & fname, return; } - FileDialog dlg(_("Select file to insert"), (asParagraph ? + FileDialog dlg(qt_("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()); + FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()), + FileFilterList()); if (result.first == FileDialog::Later) return; // FIXME UNICODE - filename.set(to_utf8(result.second)); + filename.set(fromqstr(result.second)); // check selected filename if (filename.empty()) { @@ -1171,10 +1499,10 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) /// No argument? Ask user through dialog. // FIXME UNICODE - FileDialog dlg(_("Choose a filename to save document as"), + FileDialog dlg(qt_("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)); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); if (!isLyXFilename(fname.absFilename())) fname.changeExtension(".lyx"); @@ -1182,14 +1510,14 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) FileFilterList const filter(_("LyX Documents (*.lyx)")); FileDialog::Result result = - dlg.save(from_utf8(fname.onlyPath().absFilename()), + dlg.save(toqstr(fname.onlyPath().absFilename()), filter, - from_utf8(fname.onlyFileName())); + toqstr(fname.onlyFileName())); if (result.first == FileDialog::Later) return false; - fname.set(to_utf8(result.second)); + fname.set(fromqstr(result.second)); if (fname.empty()) return false; @@ -1257,9 +1585,9 @@ bool GuiView::saveBuffer(Buffer & b) return false; break; case 1: - return false; - case 2: break; + case 2: + return false; } return saveBuffer(b); @@ -1275,7 +1603,14 @@ bool GuiView::closeBuffer() bool GuiView::closeBuffer(Buffer & buf) { + // goto bookmark to update bookmark pit. + //FIXME: we should update only the bookmarks related to this buffer! + for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) + theLyXFunc().gotoBookmark(i+1, false, false); + if (buf.isClean() || buf.paragraphs().empty()) { + if (buf.masterBuffer() == &buf) + LyX::ref().session().lastOpened().add(buf.fileName()); theBufferList().release(&buf); return true; } @@ -1289,6 +1624,10 @@ bool GuiView::closeBuffer(Buffer & buf) else file = buf.fileName().displayName(30); + // Bring this window to top before asking questions. + 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?"), @@ -1320,17 +1659,6 @@ bool GuiView::closeBuffer(Buffer & buf) } -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(); @@ -1339,6 +1667,10 @@ bool GuiView::dispatch(FuncRequest const & cmd) bv->cursor().updateFlags(Update::None); switch(cmd.action) { + case LFUN_BUFFER_IMPORT: + importDocument(to_utf8(cmd.argument())); + break; + case LFUN_BUFFER_SWITCH: setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument()))); break; @@ -1362,7 +1694,8 @@ bool GuiView::dispatch(FuncRequest const & cmd) break; case LFUN_MENU_OPEN: - d.menubar_->openByName(toqstr(cmd.argument())); + if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this)) + menu->exec(QCursor::pos()); break; case LFUN_FILE_INSERT: @@ -1463,8 +1796,6 @@ bool GuiView::dispatch(FuncRequest const & cmd) break; case LFUN_DIALOG_HIDE: { - if (quitting) - break; guiApp->hideDialogs(to_utf8(cmd.argument()), 0); break; } @@ -1494,6 +1825,10 @@ bool GuiView::dispatch(FuncRequest const & cmd) string const data = "vc " + Lexer::quoteString(buffer()->lyxvc().getLogFile()); showDialog("log", data); + } else if (name == "symbols") { + data = bv->cursor().getEncoding()->name(); + if (!data.empty()) + showDialog("symbols", data); } else showDialog(name, data); break; @@ -1512,6 +1847,51 @@ bool GuiView::dispatch(FuncRequest const & cmd) break; } + case LFUN_UI_TOGGLE: + lfunUiToggle(cmd); + // Make sure the keyboard focus stays in the work area. + setFocus(); + break; + + case LFUN_COMPLETION_INLINE: + if (d.current_work_area_) + d.current_work_area_->completer().showInline(); + break; + + case LFUN_SPLIT_VIEW: + if (Buffer * buf = buffer()) { + string const orientation = cmd.getArg(0); + d.splitter_->setOrientation(orientation == "vertical" + ? Qt::Vertical : Qt::Horizontal); + TabWorkArea * twa = addTabWorkArea(); + GuiWorkArea * wa = twa->addWorkArea(*buf, *this); + setCurrentWorkArea(wa); + } + break; + + case LFUN_CLOSE_TAB_GROUP: + if (TabWorkArea * twa = d.currentTabWorkArea()) { + delete twa; + twa = d.currentTabWorkArea(); + // Switch to the next GuiWorkArea in the found TabWorkArea. + d.current_work_area_ = twa? twa->currentWorkArea() : 0; + if (d.splitter_->count() == 0) + // No more work area, switch to the background widget. + d.setBackground(); + } + break; + + case LFUN_COMPLETION_POPUP: + if (d.current_work_area_) + d.current_work_area_->completer().showPopup(); + break; + + + case LFUN_COMPLETION_COMPLETE: + if (d.current_work_area_) + d.current_work_area_->completer().tab(); + break; + default: return false; } @@ -1520,6 +1900,73 @@ bool GuiView::dispatch(FuncRequest const & cmd) } +void GuiView::lfunUiToggle(FuncRequest const & cmd) +{ + string const arg = cmd.getArg(0); + if (arg == "scrollbar") { + // hide() is of no help + if (d.current_work_area_->verticalScrollBarPolicy() == + Qt::ScrollBarAlwaysOff) + + d.current_work_area_->setVerticalScrollBarPolicy( + Qt::ScrollBarAsNeeded); + else + d.current_work_area_->setVerticalScrollBarPolicy( + Qt::ScrollBarAlwaysOff); + return; + } + if (arg == "statusbar") { + statusBar()->setVisible(!statusBar()->isVisible()); + return; + } + if (arg == "menubar") { + menuBar()->setVisible(!menuBar()->isVisible()); + return; + } +#if QT_VERSION >= 0x040300 + if (arg == "frame") { + int l, t, r, b; + getContentsMargins(&l, &t, &r, &b); + //are the frames in default state? + d.current_work_area_->setFrameStyle(QFrame::NoFrame); + if (l == 0) { + setContentsMargins(-2, -2, -2, -2); + } else { + setContentsMargins(0, 0, 0, 0); + } + return; + } +#endif + if (arg != "fullscreen") { + message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg))); + return; + } + + if (lyxrc.full_screen_toolbars) + d.toolbars_->toggleFullScreen(!isFullScreen()); + + if (isFullScreen()) { + for (int i = 0; i != d.splitter_->count(); ++i) + d.tabWorkArea(i)->setFullScreen(false); +#if QT_VERSION >= 0x040300 + setContentsMargins(0, 0, 0, 0); +#endif + showNormal(); + menuBar()->show(); + statusBar()->show(); + } else { + for (int i = 0; i != d.splitter_->count(); ++i) + d.tabWorkArea(i)->setFullScreen(true); +#if QT_VERSION >= 0x040300 + setContentsMargins(-2, -2, -2, -2); +#endif + showFullScreen(); + statusBar()->hide(); + menuBar()->hide(); + } +} + + Buffer const * GuiView::updateInset(Inset const * inset) { if (!d.current_work_area_) @@ -1540,9 +1987,17 @@ void GuiView::restartCursor() if (d.current_work_area_) d.current_work_area_->startBlinkingCursor(); - // Take this occasion to update the toobars and layout list. + // Take this occasion to update the other GUI elements. updateLayoutList(); updateToolbars(); + updateStatusBar(); +} + + +void GuiView::updateCompletion(Cursor & cur, bool start, bool keep) +{ + if (d.current_work_area_) + d.current_work_area_->completer().updateVisibility(cur, start, keep); } namespace { @@ -1555,8 +2010,8 @@ char const * const dialognames[] = { "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character", "citation", "document", "embedding", "errorlist", "ert", "external", "file", "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log", -"mathdelimiter", "mathmatrix", "note", "paragraph", -"prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate", +"mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", +"ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate", #ifdef HAVE_LIBAIKSAURUS "thesaurus", @@ -1591,8 +2046,10 @@ void GuiView::resetDialogs() { // Make sure that no LFUN uses any LyXView. theLyXFunc().setLyXView(0); - d.toolbars_->init(); - d.menubar_->init(); + // FIXME: the "math panels" toolbar takes an awful lot of time to + // initialise so we don't do that for the time being. + //d.toolbars_->init(); + guiApp->menus().fillMenuBar(menuBar(), this); if (d.layout_) d.layout_->updateContents(true); // Now update controls with current buffer. @@ -1647,13 +2104,6 @@ bool GuiView::isDialogVisible(string const & name) const void GuiView::hideDialog(string const & name, Inset * inset) { - // Don't send the signal if we are quitting, because on MSVC it is - // destructed before the cut stack in CutAndPaste.cpp, and this method - // is called from some inset destructor if the cut stack is not empty - // on exit. - if (quitting) - return; - map::const_iterator it = d.dialogs_.find(name); if (it == d.dialogs_.end()) return; @@ -1766,7 +2216,6 @@ Dialog * createGuiExternal(GuiView & lv); Dialog * createGuiFloat(GuiView & lv); Dialog * createGuiGraphics(GuiView & lv); Dialog * createGuiInclude(GuiView & lv); -Dialog * createGuiIndex(GuiView & lv); Dialog * createGuiLabel(GuiView & lv); Dialog * createGuiListings(GuiView & lv); Dialog * createGuiLog(GuiView & lv); @@ -1781,6 +2230,7 @@ Dialog * createGuiSearch(GuiView & lv); Dialog * createGuiSendTo(GuiView & lv); Dialog * createGuiShowFile(GuiView & lv); Dialog * createGuiSpellchecker(GuiView & lv); +Dialog * createGuiSymbols(GuiView & lv); Dialog * createGuiTabularCreate(GuiView & lv); Dialog * createGuiTabular(GuiView & lv); Dialog * createGuiTexInfo(GuiView & lv); @@ -1830,8 +2280,6 @@ Dialog * GuiView::build(string const & name) return createGuiGraphics(*this); if (name == "include") return createGuiInclude(*this); - if (name == "index") - return createGuiIndex(*this); if (name == "nomenclature") return createGuiNomenclature(*this); if (name == "label") @@ -1858,6 +2306,8 @@ Dialog * GuiView::build(string const & name) return createGuiSendTo(*this); if (name == "spellchecker") return createGuiSpellchecker(*this); + if (name == "symbols") + return createGuiSymbols(*this); if (name == "tabular") return createGuiTabular(*this); if (name == "tabularcreate")