]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiApplication.cpp
fix http://bugzilla.lyx.org/show_bug.cgi?id=5114
[lyx.git] / src / frontends / qt4 / GuiApplication.cpp
index 40b98452f5aa6d6e40ed9327a81e254f9190c1a0..95e18840a2f0c0cc851e20037342ce04ee2511e4 100644 (file)
@@ -54,6 +54,7 @@
 #include "support/gettext.h"
 #include "support/lstrings.h"
 #include "support/lyxalgo.h" // sorted
+#include "support/Messages.h"
 #include "support/os.h"
 #include "support/Package.h"
 
 #include "support/linkback/LinkBackProxy.h"
 #endif
 
+#include <QByteArray>
 #include <QClipboard>
+#include <QDir>
 #include <QEventLoop>
 #include <QFileOpenEvent>
 #include <QHash>
 #include <QIcon>
+#include <QImageReader>
 #include <QLocale>
 #include <QLibraryInfo>
 #include <QList>
 #endif // Q_WS_WIN
 
 #include <boost/bind.hpp>
+#include <boost/crc.hpp>
 
 #include <exception>
 #include <vector>
@@ -128,6 +133,34 @@ frontend::Application * createApplication(int & argc, char * argv[])
 
 namespace frontend {
 
+
+/// Return the list of loadable formats.
+vector<string> loadableImageFormats()
+{
+       vector<string> fmts;
+
+       QList<QByteArray> qt_formats = QImageReader::supportedImageFormats();
+
+       LYXERR(Debug::GRAPHICS,
+               "\nThe image loader can load the following directly:\n");
+
+       if (qt_formats.empty())
+               LYXERR(Debug::GRAPHICS, "\nQt4 Problem: No Format available!");
+
+       for (QList<QByteArray>::const_iterator it = qt_formats.begin(); it != qt_formats.end(); ++it) {
+
+               LYXERR(Debug::GRAPHICS, (const char *) *it << ", ");
+
+               string ext = ascii_lowercase((const char *) *it);
+               // special case
+               if (ext == "jpeg")
+                       ext = "jpg";
+               fmts.push_back(ext);
+       }
+
+       return fmts;
+}
+       
 ////////////////////////////////////////////////////////////////////////
 // Icon loading support code.
 ////////////////////////////////////////////////////////////////////////
@@ -307,7 +340,7 @@ QIcon getIcon(FuncRequest const & f, bool unknown)
        if (icon.isEmpty())
                return QIcon();
 
-       LYXERR(Debug::GUI, "Found icon: " << icon);
+       //LYXERR(Debug::GUI, "Found icon: " << icon);
        QPixmap pm;
        if (!pm.load(icon)) {
                LYXERR0("Cannot load icon " << icon << " please verify resource system!");
@@ -414,14 +447,16 @@ public:
                return mimeFor(flav) == mime;
        }
 
-       QVariant convertToMime(QString const & mime, QList<QByteArray> data, QString flav)
+       QVariant convertToMime(QString const & /*mime*/, QList<QByteArray> data,
+               QString /*flav*/)
        {
                if(data.count() > 1)
                        qWarning("QMacPasteboardMimeGraphics: Cannot handle multiple member data");
                return data.first();
        }
 
-       QList<QByteArray> convertFromMime(QString const & mime, QVariant data, QString flav)
+       QList<QByteArray> convertFromMime(QString const & /*mime*/,
+               QVariant data, QString /*flav*/)
        {
                QList<QByteArray> ret;
                ret.append(data.toByteArray());
@@ -595,9 +630,7 @@ struct GuiApplication::Private
 
 #ifdef Q_WS_WIN
        /// WMF Mime handler for Windows clipboard.
-       // FIXME for Windows Vista and Qt4 (see http://bugzilla.lyx.org/show_bug.cgi?id=4846)
-       // But this makes LyX crash on exit when LyX is compiled in release mode and if there
-       // is something in the clipboard.
+       /// \warning: see comment in ~GuiApplication and in bug 4846.
        QWindowsMimeMetafile wmf_mime_;
 #endif
 };
@@ -610,6 +643,13 @@ GuiApplication::~GuiApplication()
 #ifdef Q_WS_MACX
        closeAllLinkBackLinks();
 #endif
+       // FIXME: Work around bug 4846 for Windows Vista and Qt4
+       // (see http://bugzilla.lyx.org/show_bug.cgi?id=4846)
+       // If the clipboard is not cleared, LyX crashes on exit when it is
+       // compiled in release mode and if there is something in the clipboard.
+       // This is related to QWindowsMimeMetafile which is apparently not 
+       // properly destroyed.
+       qApp->clipboard()->clear(QClipboard::Clipboard);
        delete d;
 }
 
@@ -622,6 +662,9 @@ GuiApplication::GuiApplication(int & argc, char ** argv)
        QCoreApplication::setOrganizationDomain("lyx.org");
        QCoreApplication::setApplicationName(app_name + "-" + lyx_version);
 
+       // Install translator for GUI elements.
+       installTranslator(&d->qt_trans_);
+
        // 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.
@@ -633,6 +676,11 @@ GuiApplication::GuiApplication(int & argc, char ** argv)
        // FIXME: Do we need a lyxrc setting for this on Mac? This behaviour
        // seems to be the default case for applications like LyX.
        setQuitOnLastWindowClosed(false);
+
+       // This allows to translate the strings that appear in the LyX menu.
+       /// A translator suitable for the entries in the LyX menu.
+       /// Only needed with Qt/Mac.
+       installTranslator(new MenuTranslator(this));
 #endif
        
 #ifdef Q_WS_X11
@@ -643,37 +691,11 @@ GuiApplication::GuiApplication(int & argc, char ** argv)
        QApplication::setDoubleClickInterval(300);
 #endif
 
-       // install translation file for Qt built-in dialogs
-       QString language_name = QString("qt_") + QLocale::system().name();
-       
-       // language_name can be short (e.g. qt_zh) or long (e.g. qt_zh_CN). 
-       // Short-named translator can be loaded from a long name, but not the
-       // opposite. Therefore, long name should be used without truncation.
-       // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load
-       if (d->qt_trans_.load(language_name,
-               QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
-       {
-               installTranslator(&d->qt_trans_);
-               // even if the language calls for RtL, don't do that
-               setLayoutDirection(Qt::LeftToRight);
-               LYXERR(Debug::GUI, "Successfully installed Qt translations for locale "
-                       << language_name);
-       } else
-               LYXERR(Debug::GUI, "Could not find  Qt translations for locale "
-                       << language_name);
-
-#ifdef Q_WS_MACX
-       // This allows to translate the strings that appear in the LyX menu.
-       /// A translator suitable for the entries in the LyX menu.
-       /// Only needed with Qt/Mac.
-       installTranslator(new MenuTranslator(this));
-#endif
        connect(this, SIGNAL(lastWindowClosed()), this, SLOT(onLastWindowClosed()));
 
        using namespace lyx::graphics;
 
        Image::newImage = boost::bind(&GuiImage::newImage);
-       Image::loadableFormats = boost::bind(&GuiImage::loadableFormats);
 
        // needs to be done before reading lyxrc
        QWidget w;
@@ -750,7 +772,7 @@ bool GuiApplication::dispatch(FuncRequest const & cmd)
 
        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)
+               for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
                        theLyXFunc().gotoBookmark(i+1, false, false);
                current_view_->close();
                break;
@@ -808,8 +830,13 @@ bool GuiApplication::dispatch(FuncRequest const & cmd)
        case LFUN_FILE_OPEN:
                if (d->views_.empty()
                    || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
-                       createView();
-                       current_view_->openDocument(to_utf8(cmd.argument()));
+                       string const fname = to_utf8(cmd.argument());
+                       // We want the ui session to be saved per document and not per
+                       // window number. The filename crc is a good enough identifier.
+                       boost::crc_32_type crc;
+                       crc = for_each(fname.begin(), fname.end(), crc);
+                       createView(crc.checksum());
+                       current_view_->openDocument(fname);
                        if (!current_view_->buffer())
                                current_view_->close();
                } else
@@ -860,15 +887,38 @@ bool GuiApplication::dispatch(FuncRequest const & cmd)
 
 void GuiApplication::resetGui()
 {
+       // Set the language defined by the user.
+       setGuiLanguage();
+
+       // Read menus
+       if (!readUIFile(toqstr(lyxrc.ui_file)))
+               // Gives some error box here.
+               return;
+
+       // init the global menubar on Mac. This must be done after the session
+       // was recovered to know the "last files".
+       if (d->global_menubar_)
+               d->menus_.fillMenuBar(d->global_menubar_, 0, true);
+
        QHash<int, GuiView *>::iterator it;
-       for (it = d->views_.begin(); it != d->views_.end(); ++it)
-               (*it)->resetDialogs();
+       for (it = d->views_.begin(); it != d->views_.end(); ++it) {
+               GuiView * gv = *it;
+               gv->setLayoutDirection(layoutDirection());
+               gv->resetDialogs();
+       }
 
        dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
 }
 
 
-void GuiApplication::createView(QString const & geometry_arg, bool autoShow)
+void GuiApplication::createView(int view_id)
+{
+       createView(QString(), true, view_id);
+}
+
+
+void GuiApplication::createView(QString const & geometry_arg, bool autoShow,
+       int view_id)
 {
        // release the keyboard which might have been grabed by the global
        // menubar on Mac to catch shortcuts even without any GuiView.
@@ -876,15 +926,13 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow)
                d->global_menubar_->releaseKeyboard();
 
        // create new view
-       int id = 0;
-       while (d->views_.find(id) != d->views_.end())
-               id++;
+       int id = view_id;
+       if (id == 0) {
+               while (d->views_.find(id) != d->views_.end())
+                       id++;
+       }
+       LYXERR(Debug::GUI, "About to create new window with ID " << id);
        GuiView * view = new GuiView(id);
-       
-       // copy the icon size from old view
-       if (current_view_)
-               view->setIconSize(current_view_->iconSize());
-
        // register view
        d->views_[id] = view;
 
@@ -978,8 +1026,49 @@ void GuiApplication::exit(int status)
 }
 
 
+void GuiApplication::setGuiLanguage()
+{
+       // Set the language defined by the user.
+       setRcGuiLanguage();
+
+       QString const default_language = toqstr(Messages::defaultLanguage());
+       LYXERR(Debug::LOCALE, "Tring to set default locale to: " << default_language);
+       QLocale const default_locale(default_language);
+       QLocale::setDefault(default_locale);
+
+       // install translation file for Qt built-in dialogs
+       QString const language_name = QString("qt_") + default_locale.name();
+
+       // language_name can be short (e.g. qt_zh) or long (e.g. qt_zh_CN). 
+       // Short-named translator can be loaded from a long name, but not the
+       // opposite. Therefore, long name should be used without truncation.
+       // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load
+       if (!d->qt_trans_.load(language_name,
+                       QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
+               LYXERR(Debug::LOCALE, "Could not find  Qt translations for locale "
+                       << language_name);
+       } else {
+               LYXERR(Debug::LOCALE, "Successfully installed Qt translations for locale "
+                       << language_name);
+       }
+
+       switch (default_locale.language()) {
+       case QLocale::Arabic :
+       case QLocale::Hebrew :
+       case QLocale::Persian :
+       case QLocale::Urdu :
+        setLayoutDirection(Qt::RightToLeft);
+               break;
+       default:
+        setLayoutDirection(Qt::LeftToRight);
+       }
+}
+
+
 void GuiApplication::execBatchCommands()
 {
+       setGuiLanguage();
+
        // Read menus
        if (!readUIFile(toqstr(lyxrc.ui_file)))
                // Gives some error box here.
@@ -990,7 +1079,7 @@ void GuiApplication::execBatchCommands()
        if (d->global_menubar_)
                d->menus_.fillMenuBar(d->global_menubar_, 0, true);
 
-       LyX::ref().execBatchCommands();
+       lyx::execBatchCommands();
 }
 
 QAbstractItemModel * GuiApplication::languageModel()
@@ -1024,7 +1113,7 @@ void GuiApplication::restoreGuiSession()
        if (!lyxrc.load_session)
                return;
 
-       Session & session = LyX::ref().session();
+       Session & session = theSession();
        vector<FileName> 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
@@ -1101,7 +1190,7 @@ bool GuiApplication::notify(QObject * receiver, QEvent * event)
        catch (ExceptionMessage const & e) {
                switch(e.type_) { 
                case ErrorException:
-                       LyX::cref().emergencyCleanup();
+                       emergencyCleanup();
                        setQuitOnLastWindowClosed(false);
                        closeAllViews();
                        Alert::error(e.title_, e.details_);
@@ -1132,13 +1221,13 @@ bool GuiApplication::notify(QObject * receiver, QEvent * event)
                        "\n\nException: ");
                s += from_ascii(e.what());
                Alert::error(_("Software exception Detected"), s);
-               LyX::cref().exit(1);
+               lyx_exit(1);
        }
        catch (...) {
                docstring s = _("LyX has caught some really weird exception, it will "
                        "now attempt to save all unsaved documents and exit.");
                Alert::error(_("Software exception Detected"), s);
-               LyX::cref().exit(1);
+               lyx_exit(1);
        }
 
        return false;
@@ -1282,9 +1371,16 @@ bool GuiApplication::readUIFile(QString const & name, bool include)
        // Ensure that a file is read only once (prevents include loops)
        static QStringList uifiles;
        if (uifiles.contains(name)) {
-               LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
-                                   << "Is this an include loop?");
-               return false;
+               if (!include) {
+                       // We are reading again the top uifile so reset the safeguard:
+                       uifiles.clear();
+                       d->menus_.reset();
+                       d->toolbars_.reset();
+               } else {
+                       LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
+                               << "Is this an include loop?");
+                       return false;
+               }
        }
 
        LYXERR(Debug::INIT, "About to read " << name << "...");
@@ -1300,7 +1396,7 @@ bool GuiApplication::readUIFile(QString const & name, bool include)
 
        if (ui_path.empty()) {
                LYXERR(Debug::INIT, "Could not find " << name);
-               Alert::warning(_("Could not find UI defintion file"),
+               Alert::warning(_("Could not find UI definition file"),
                               bformat(_("Error while reading the configuration file\n%1$s.\n"
                                   "Please check your installation."), qstring_to_ucs4(name)));
                return false;
@@ -1372,7 +1468,7 @@ bool GuiApplication::x11EventFilter(XEvent * xev)
        case SelectionRequest: {
                if (xev->xselectionrequest.selection != XA_PRIMARY)
                        break;
-               LYXERR(Debug::GUI, "X requested selection.");
+               LYXERR(Debug::SELECTION, "X requested selection.");
                BufferView * bv = current_view_->view();
                if (bv) {
                        docstring const sel = bv->requestSelection();
@@ -1384,7 +1480,7 @@ bool GuiApplication::x11EventFilter(XEvent * xev)
        case SelectionClear: {
                if (xev->xselectionclear.selection != XA_PRIMARY)
                        break;
-               LYXERR(Debug::GUI, "Lost selection.");
+               LYXERR(Debug::SELECTION, "Lost selection.");
                BufferView * bv = current_view_->view();
                if (bv)
                        bv->clearSelection();