X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiApplication.cpp;h=69e5f09a28b06979f2409e807f456a75494e25bd;hb=4e223167ff2872ee123c8354d486352c8a368102;hp=ab19035881ca304822972e8bc4567df57a82fa43;hpb=502125671aa70a4a56645e4080e6bca306ed184d;p=lyx.git diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index ab19035881..69e5f09a28 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -16,38 +16,42 @@ #include "qt_helpers.h" #include "GuiImage.h" +#include "GuiKeySymbol.h" #include "GuiView.h" #include "frontends/alert.h" #include "frontends/Application.h" -#include "frontends/NoGuiFontLoader.h" -#include "frontends/NoGuiFontMetrics.h" #include "frontends/FontLoader.h" #include "frontends/FontMetrics.h" -#include "support/ExceptionMessage.h" -#include "support/FileName.h" -#include "support/lstrings.h" -#include "support/os.h" -#include "support/Package.h" - +#include "Buffer.h" #include "BufferList.h" #include "BufferView.h" -#include "debug.h" #include "Font.h" #include "FuncRequest.h" -#include "gettext.h" +#include "FuncStatus.h" #include "LyX.h" #include "LyXFunc.h" #include "LyXRC.h" +#include "Session.h" #include "version.h" +#include "support/debug.h" +#include "support/ExceptionMessage.h" +#include "support/FileName.h" +#include "support/ForkedCalls.h" +#include "support/gettext.h" +#include "support/lstrings.h" +#include "support/os.h" +#include "support/Package.h" + #include #include #include #include #include #include +#include #include #include #include @@ -68,11 +72,8 @@ #include -using std::endl; -using std::map; -using std::string; -using std::vector; - +using namespace std; +using namespace lyx::support; namespace lyx { @@ -121,6 +122,27 @@ public: } }; +class GlobalMenuBar : public QMenuBar +{ +public: + /// + GlobalMenuBar() : QMenuBar(0) {} + + /// + bool event(QEvent * e) + { + if (e->type() == QEvent::ShortcutOverride) { + // && activeWindow() == 0) { + QKeyEvent * ke = static_cast(e); + KeySymbol sym; + setKeySymbol(&sym, ke); + theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers())); + e->accept(); + return true; + } + return false; + } +}; /////////////////////////////////////////////////////////////// // You can find more platform specific stuff @@ -128,22 +150,28 @@ public: /////////////////////////////////////////////////////////////// -using support::FileName; - GuiApplication * guiApp; GuiApplication::GuiApplication(int & argc, char ** argv) - : QApplication(argc, argv), Application(), current_view_(0) + : QApplication(argc, argv), Application(), current_view_(0), global_menubar_(0) { QString app_name = "LyX"; QCoreApplication::setOrganizationName(app_name); QCoreApplication::setOrganizationDomain("lyx.org"); QCoreApplication::setApplicationName(app_name + "-" + lyx_version); - // Qt bug? setQuitOnLastWindowClosed(true); does not work + // FIXME: quitOnLastWindowClosed is true by default. We should have a + // lyxrc setting for this in order to let the application stay resident. + // But then we need some kind of dock icon, at least on Windows. + /* + if (lyxrc.quit_on_last_window_closed) + setQuitOnLastWindowClosed(false); + */ +#ifdef Q_WS_MAC setQuitOnLastWindowClosed(false); - +#endif + #ifdef Q_WS_X11 // doubleClickInterval() is 400 ms on X11 which is just too long. // On Windows and Mac OS X, the operating system's value is used. @@ -175,6 +203,7 @@ GuiApplication::GuiApplication(int & argc, char ** argv) // This allows to translate the strings that appear in the LyX menu. addMenuTranslator(); #endif + connect(this, SIGNAL(lastWindowClosed()), this, SLOT(onLastWindowClosed())); using namespace lyx::graphics; @@ -200,6 +229,19 @@ GuiApplication::GuiApplication(int & argc, char ** argv) if (lyxrc.typewriter_font_name.empty()) lyxrc.typewriter_font_name = fromqstr(typewriterFontName()); + + general_timer_.setInterval(500); + connect(&general_timer_, SIGNAL(timeout()), + this, SLOT(handleRegularEvents())); + general_timer_.start(); + +#ifdef Q_WS_MACX + if (global_menubar_ == 0) { + // Create the global default menubar which is shown for the dialogs + // and if no GuiView is visible. + global_menubar_ = new GlobalMenuBar(); + } +#endif } @@ -209,11 +251,117 @@ GuiApplication::~GuiApplication() } +FuncStatus GuiApplication::getStatus(FuncRequest const & cmd) +{ + FuncStatus flag; + bool enable = true; + + switch(cmd.action) { + + case LFUN_WINDOW_CLOSE: + enable = view_ids_.size() > 0; + break; + + default: + if (!current_view_) { + enable = false; + break; + } + } + + if (!enable) + flag.enabled(false); + + return flag; +} + + +bool GuiApplication::dispatch(FuncRequest const & cmd) +{ + switch(cmd.action) { + + case LFUN_WINDOW_NEW: + createView(toqstr(cmd.argument())); + break; + + case LFUN_WINDOW_CLOSE: + // update bookmark pit of the current buffer before window close + for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) + theLyXFunc().gotoBookmark(i+1, false, false); + current_view_->close(); + break; + + case LFUN_LYX_QUIT: + // quitting is triggered by the gui code + // (leaving the event loop). + current_view_->message(from_utf8(N_("Exiting."))); + if (closeAllViews()) + quit(); + break; + + case LFUN_SCREEN_FONT_UPDATE: { + // handle the screen font changes. + font_loader_.update(); + // Backup current_view_ + GuiView * view = current_view_; + // Set current_view_ to zero to forbid GuiWorkArea::redraw() + // to skip the refresh. + current_view_ = 0; + BufferList::iterator it = theBufferList().begin(); + BufferList::iterator const end = theBufferList().end(); + for (; it != end; ++it) + (*it)->changed(); + // Restore current_view_ + current_view_ = view; + break; + } + + case LFUN_BUFFER_NEW: + if (viewCount() == 0 + || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) + createView(); + current_view_->newDocument(to_utf8(cmd.argument()), false); + break; + + case LFUN_BUFFER_NEW_TEMPLATE: + if (viewCount() == 0 + || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) { + createView(); + current_view_->newDocument(to_utf8(cmd.argument()), true); + if (!current_view_->buffer()) + current_view_->close(); + } else + current_view_->newDocument(to_utf8(cmd.argument()), true); + break; + + case LFUN_FILE_OPEN: + if (viewCount() == 0 + || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) { + createView(); + current_view_->openDocument(to_utf8(cmd.argument())); + if (!current_view_->buffer()) + current_view_->close(); + } else + current_view_->openDocument(to_utf8(cmd.argument())); + break; + + default: + // Notify the caller that the action has not been dispatched. + return false; + } + + // The action has been dispatched. + return true; +} + + void GuiApplication::resetGui() { map::iterator it; for (it = views_.begin(); it != views_.end(); ++it) it->second->resetDialogs(); + + dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)); } @@ -226,25 +374,33 @@ static void updateIds(map const & stdmap, vector & ids) } -void GuiApplication::createView(string const & geometry_arg) +void GuiApplication::createView(QString const & geometry_arg) { + if (global_menubar_) + global_menubar_->releaseKeyboard(); + + // create new view updateIds(views_, view_ids_); int id = 0; while (views_.find(id) != views_.end()) id++; - views_[id] = new GuiView(id); - updateIds(views_, view_ids_); + GuiView * view = new GuiView(id); + + // copy the icon size from old view + if (viewCount() > 0) + view->setIconSize(current_view_->iconSize()); - GuiView * view = views_[id]; - theLyXFunc().setLyXView(view); + // register view + views_[id] = view; + updateIds(views_, view_ids_); view->show(); - if (!geometry_arg.empty()) { + if (!geometry_arg.isEmpty()) { #ifdef Q_WS_WIN int x, y; int w, h; QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" ); - re.indexIn(toqstr(geometry_arg.c_str())); + re.indexIn(geometry_arg); w = re.cap(1).toInt(); h = re.cap(2).toInt(); x = re.cap(3).toInt(); @@ -253,7 +409,7 @@ void GuiApplication::createView(string const & geometry_arg) #endif } view->setFocus(); - + setActiveWindow(view); setCurrentView(*view); } @@ -291,6 +447,24 @@ void GuiApplication::execBatchCommands() } +void GuiApplication::restoreGuiSession() +{ + if (!lyxrc.load_session) + return; + + Session & session = LyX::ref().session(); + vector const & lastopened = session.lastOpened().getfiles(); + // do not add to the lastfile list since these files are restored from + // last session, and should be already there (regular files), or should + // not be added at all (help files). + for_each(lastopened.begin(), lastopened.end(), + bind(&GuiView::loadDocument, current_view_, _1, false)); + + // clear this list to save a few bytes of RAM + session.lastOpened().clear(); +} + + QString const GuiApplication::romanFontName() { QFont font; @@ -324,6 +498,12 @@ QString const GuiApplication::typewriterFontName() } +void GuiApplication::handleRegularEvents() +{ + ForkedCallsController::handleCompletedProcesses(); +} + + bool GuiApplication::event(QEvent * e) { switch(e->type()) { @@ -336,7 +516,7 @@ bool GuiApplication::event(QEvent * e) // So we acknowledge the event and delay the file opening // until LyX is ready. // FIXME UNICODE: FileName accept an utf8 encoded string. - LyX::ref().addFileToLoad(FileName(fromqstr(foe->file()))); + LyX::ref().addFileToLoad(fromqstr(foe->file())); else lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, qstring_to_ucs4(foe->file()))); @@ -355,31 +535,47 @@ bool GuiApplication::notify(QObject * receiver, QEvent * event) try { return QApplication::notify(receiver, event); } - catch (support::ExceptionMessage const & e) { - if (e.type_ == support::ErrorException) { - Alert::error(e.title_, e.details_); + catch (ExceptionMessage const & e) { + switch(e.type_) { + case ErrorException: LyX::cref().emergencyCleanup(); - QApplication::exit(1); - } else if (e.type_ == support::WarningException) { - Alert::warning(e.title_, e.details_); + setQuitOnLastWindowClosed(false); + closeAllViews(); + Alert::error(e.title_, e.details_); +#ifndef NDEBUG + // Properly crash in debug mode in order to get a useful backtrace. + abort(); +#endif + // In release mode, try to exit gracefully. + this->exit(1); + + case BufferException: { + Buffer * buf = current_view_->buffer(); + docstring details = e.details_ + '\n'; + details += theBufferList().emergencyWrite(buf); + theBufferList().release(buf); + details += _("\nThe current document was closed."); + Alert::error(e.title_, details); return false; } + case WarningException: + Alert::warning(e.title_, e.details_); + return false; + }; } - catch (std::exception const & e) { + catch (exception const & e) { docstring s = _("LyX has caught an exception, it will now " - "attemp to save all unsaved documents and exit." + "attempt to save all unsaved documents and exit." "\n\nException: "); s += from_ascii(e.what()); Alert::error(_("Software exception Detected"), s); - LyX::cref().emergencyCleanup(); - QApplication::exit(1); + LyX::cref().exit(1); } catch (...) { docstring s = _("LyX has caught some really weird exception, it will " - "now attemp to save all unsaved documents and exit."); + "now attempt to save all unsaved documents and exit."); Alert::error(_("Software exception Detected"), s); - LyX::cref().emergencyCleanup(); - QApplication::exit(1); + LyX::cref().exit(1); } return false; @@ -404,7 +600,7 @@ bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol) string const GuiApplication::hexName(ColorCode col) { - return support::ltrim(fromqstr(color_cache_.get(col).name()), "#"); + return ltrim(fromqstr(color_cache_.get(col).name()), "#"); } @@ -442,8 +638,9 @@ void GuiApplication::commitData(QSessionManager & sm) /// The default implementation sends a close event to all /// visible top level widgets when session managment allows /// interaction. - /// We are changing that to write all unsaved buffers... - if (sm.allowsInteraction() && !theBufferList().quitWriteAll()) + /// We are changing that to close all wiew one by one. + /// FIXME: verify if the default implementation is enough now. + if (sm.allowsInteraction() && !closeAllViews()) sm.cancel(); } @@ -475,20 +672,14 @@ bool GuiApplication::unregisterView(int id) bool GuiApplication::closeAllViews() { updateIds(views_, view_ids_); - if (views_.empty()) { - // quit in CloseEvent will not be triggert - qApp->quit(); + if (views_.empty()) return true; - } map const cmap = views_; map::const_iterator it; for (it = cmap.begin(); it != cmap.end(); ++it) { - // TODO: return false when close event was ignored - // e.g. quitWriteAll()->'Cancel' - // maybe we need something like 'bool closeView()' - it->second->close(); - // unregisterd by the CloseEvent + if (!it->second->close()) + return false; } views_.clear(); @@ -527,6 +718,32 @@ Buffer const * GuiApplication::updateInset(Inset const * inset) const } +void GuiApplication::readMenus(Lexer & lex) +{ + menus().read(lex); +} + + +bool GuiApplication::searchMenu(FuncRequest const & func, + vector & names) const +{ + return menus().searchMenu(func, names); +} + + +void GuiApplication::initGlobalMenu() +{ + if (global_menubar_) + menus().fillMenuBar(global_menubar_, 0); +} + + +void GuiApplication::onLastWindowClosed() +{ + if (global_menubar_) + global_menubar_->grabKeyboard(); +} + //////////////////////////////////////////////////////////////////////// // X11 specific stuff goes here... #ifdef Q_WS_X11 @@ -573,11 +790,6 @@ bool GuiApplication::x11EventFilter(XEvent * xev) frontend::FontLoader & theFontLoader() { - static frontend::NoGuiFontLoader no_gui_font_loader; - - if (!use_gui) - return no_gui_font_loader; - BOOST_ASSERT(frontend::guiApp); return frontend::guiApp->fontLoader(); } @@ -591,11 +803,6 @@ frontend::FontMetrics const & theFontMetrics(Font const & f) frontend::FontMetrics const & theFontMetrics(FontInfo const & f) { - static frontend::NoGuiFontMetrics no_gui_font_metrics; - - if (!use_gui) - return no_gui_font_metrics; - BOOST_ASSERT(frontend::guiApp); return frontend::guiApp->fontLoader().metrics(f); }