]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
On Linux show in crash message box the backtrace
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 1f54bbc109c4ac3a9e91d62ca0cabee237f90eac..a7cbbe49fed44c0026419e1a63c88d1aa6974ee4 100644 (file)
@@ -34,6 +34,7 @@
 #include "qt_helpers.h"
 
 #include "frontends/alert.h"
+#include "frontends/KeySymbol.h"
 
 #include "buffer_funcs.h"
 #include "Buffer.h"
@@ -58,6 +59,7 @@
 #include "LyXVC.h"
 #include "Paragraph.h"
 #include "SpellChecker.h"
+#include "Session.h"
 #include "TexRow.h"
 #include "TextClass.h"
 #include "Text.h"
@@ -501,7 +503,7 @@ GuiView::GuiView(int id)
 
        if (lyxrc.allow_geometry_session) {
                // Now take care of session management.
-               if (restoreLayout(true))
+               if (restoreLayout())
                        return;
        }
 
@@ -623,7 +625,7 @@ void GuiView::saveUISettings() const
 }
 
 
-bool GuiView::restoreLayout(bool force_inittoolbars)
+bool GuiView::restoreLayout()
 {
        QSettings settings;
        settings.beginGroup("views");
@@ -669,12 +671,19 @@ bool GuiView::restoreLayout(bool force_inittoolbars)
                dialog->prepareView();
        if ((dialog = findOrBuild("progress", true)))
                dialog->prepareView();
-       if ((dialog = findOrBuild("findreplaceadv", true)))
-               dialog->prepareView();
 
-       if (!restoreState(settings.value("layout").toByteArray(), 0)
-           || force_inittoolbars)
+       if (!restoreState(settings.value("layout").toByteArray(), 0))
                initToolbars();
+       
+       // init the toolbars that have not been restored
+       Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
+       Toolbars::Infos::iterator end = guiApp->toolbars().end();
+       for (; cit != end; ++cit) {
+               GuiToolbar * tb = toolbar(cit->name);
+               if (tb && !tb->isRestored())
+                       initToolbar(cit->name);
+       }
+
        updateDialogs();
        return true;
 }
@@ -717,42 +726,47 @@ void GuiView::initToolbars()
        // extracts the toolbars from the backend
        Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
        Toolbars::Infos::iterator end = guiApp->toolbars().end();
-       for (; cit != end; ++cit) {
-               GuiToolbar * tb = toolbar(cit->name);
-               if (!tb)
-                       continue;
-               int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
-               bool newline = !(visibility & Toolbars::SAMEROW);
-               tb->setVisible(false);
-               tb->setVisibility(visibility);
-
-               if (visibility & Toolbars::TOP) {
-                       if (newline)
-                               addToolBarBreak(Qt::TopToolBarArea);
-                       addToolBar(Qt::TopToolBarArea, tb);
-               }
+       for (; cit != end; ++cit)
+               initToolbar(cit->name);
+}
 
-               if (visibility & Toolbars::BOTTOM) {
-                       if (newline)
-                               addToolBarBreak(Qt::BottomToolBarArea);
-                       addToolBar(Qt::BottomToolBarArea, tb);
-               }
 
-               if (visibility & Toolbars::LEFT) {
-                       if (newline)
-                               addToolBarBreak(Qt::LeftToolBarArea);
-                       addToolBar(Qt::LeftToolBarArea, tb);
-               }
+void GuiView::initToolbar(string const & name)
+{
+       GuiToolbar * tb = toolbar(name);
+       if (!tb)
+               return;
+       int const visibility = guiApp->toolbars().defaultVisibility(name);
+       bool newline = !(visibility & Toolbars::SAMEROW);
+       tb->setVisible(false);
+       tb->setVisibility(visibility);
+
+       if (visibility & Toolbars::TOP) {
+               if (newline)
+                       addToolBarBreak(Qt::TopToolBarArea);
+               addToolBar(Qt::TopToolBarArea, tb);
+       }
 
-               if (visibility & Toolbars::RIGHT) {
-                       if (newline)
-                               addToolBarBreak(Qt::RightToolBarArea);
-                       addToolBar(Qt::RightToolBarArea, tb);
-               }
+       if (visibility & Toolbars::BOTTOM) {
+               if (newline)
+                       addToolBarBreak(Qt::BottomToolBarArea);
+               addToolBar(Qt::BottomToolBarArea, tb);
+       }
 
-               if (visibility & Toolbars::ON)
-                       tb->setVisible(true);
+       if (visibility & Toolbars::LEFT) {
+               if (newline)
+                       addToolBarBreak(Qt::LeftToolBarArea);
+               addToolBar(Qt::LeftToolBarArea, tb);
        }
+
+       if (visibility & Toolbars::RIGHT) {
+               if (newline)
+                       addToolBarBreak(Qt::RightToolBarArea);
+               addToolBar(Qt::RightToolBarArea, tb);
+       }
+
+       if (visibility & Toolbars::ON)
+               tb->setVisible(true);
 }
 
 
@@ -988,6 +1002,12 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa)
                return;
        setWindowTitle(qt_("LyX: ") + wa->windowTitle());
        setWindowIconText(wa->windowIconText());
+#if (QT_VERSION >= 0x040400)
+       // Sets the path for the window: this is used by OSX to 
+       // allow a context click on the title bar showing a menu
+       // with the path up to the file
+       setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
+#endif
 }
 
 
@@ -1334,7 +1354,7 @@ void GuiView::removeWorkArea(GuiWorkArea * wa)
 
        // It is not a tabbed work area (i.e., the search work area), so it
        // should be deleted by other means.
-       LASSERT(found_twa, /* */);
+       LASSERT(found_twa, return);
 
        if (d.current_work_area_ == 0) {
                if (d.splitter_->count() != 0) {
@@ -1595,7 +1615,9 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        case LFUN_MASTER_BUFFER_UPDATE:
        case LFUN_MASTER_BUFFER_VIEW:
-               enable = doc_buffer && doc_buffer->parent() != 0
+               enable = doc_buffer
+                       && (doc_buffer->parent() != 0
+                           || doc_buffer->hasChildren())
                        && !d.processing_thread_watcher_.isRunning();
                break;
 
@@ -1716,7 +1738,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                else if (name == "print")
                        enable = doc_buffer->params().isExportable("dvi")
                                && lyxrc.print_command != "none";
-               else if (name == "character" || name == "symbols") {
+               else if (name == "character" || name == "symbols"
+                       || name == "mathdelimiter" || name == "mathmatrix") {
                        if (!buf || buf->isReadonly())
                                enable = false;
                        else {
@@ -1762,7 +1785,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        enable = false;
                break;
 
-       case LFUN_COMPLETION_COMPLETE:
+       case LFUN_COMPLETE:
                if (!d.current_work_area_
                        || !d.current_work_area_->completer().inlinePossible(
                        currentBufferView()->cursor()))
@@ -1855,6 +1878,10 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                enable = documentBufferView() && documentBufferView()->cursor().inTexted();
                break;
 
+       case LFUN_SPELLING_CONTINUOUSLY:
+               flag.setOnOff(lyxrc.spellcheck_continuously);
+               break;
+
        default:
                return false;
        }
@@ -1925,16 +1952,12 @@ void GuiView::openDocument(string const & fname)
        string filename;
 
        if (fname.empty()) {
-               FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
+               FileDialog dlg(qt_("Select document to open"));
                dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("Examples|#E#e"),
                                toqstr(addPath(package().system_support().absFileName(), "examples")));
 
-               QStringList filter(qt_("LyX Documents (*.lyx)"));
-               filter << qt_("LyX-1.3.x Documents (*.lyx13)")
-                       << qt_("LyX-1.4.x Documents (*.lyx14)")
-                       << qt_("LyX-1.5.x Documents (*.lyx15)")
-                       << qt_("LyX-1.6.x Documents (*.lyx16)");
+               QStringList const filter(qt_("LyX Documents (*.lyx)"));
                FileDialog::Result result =
                        dlg.open(toqstr(initpath), filter);
 
@@ -2068,7 +2091,7 @@ void GuiView::importDocument(string const & argument)
                docstring const text = bformat(_("Select %1$s file to import"),
                        formats.prettyName(format));
 
-               FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
+               FileDialog dlg(toqstr(text));
                dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("Examples|#E#e"),
                        toqstr(addPath(package().system_support().absFileName(), "examples")));
@@ -2098,6 +2121,18 @@ void GuiView::importDocument(string const & argument)
        // get absolute path of file
        FileName const fullname(support::makeAbsPath(filename));
 
+       // Can happen if the user entered a path into the dialog
+       // (see bug #7437)
+       if (fullname.onlyFileName().empty()) {
+               docstring msg = bformat(_("The file name '%1$s' is invalid!\n"
+                                         "Aborting import."),
+                                       from_utf8(fullname.absFileName()));
+               frontend::Alert::error(_("File name error"), msg);
+               message(_("Canceled."));
+               return;
+       }
+
+
        FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx"));
 
        // Check if the document already is open
@@ -2190,7 +2225,7 @@ void GuiView::insertLyXFile(docstring const & fname)
                        initpath = trypath;
 
                // FIXME UNICODE
-               FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
+               FileDialog dlg(qt_("Select LyX document to insert"));
                dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("Examples|#E#e"),
                        toqstr(addPath(package().system_support().absFileName(),
@@ -2232,8 +2267,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
 
                // No argument? Ask user through dialog.
                // FIXME UNICODE
-               FileDialog dlg(qt_("Choose a filename to save document as"),
-                                  LFUN_BUFFER_WRITE_AS);
+               FileDialog dlg(qt_("Choose a filename to save document as"));
                dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
 
@@ -2342,7 +2376,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
 
        bool const saved = saveBuffer(b, fname);
        if (saved)
-               b.reload(false);
+               b.reload();
        return saved;
 }
 
@@ -2350,12 +2384,13 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
 struct PrettyNameComparator
 {
        bool operator()(Format const *first, Format const *second) const {
-               return compare_ascii_no_case(first->prettyname(), second->prettyname()) <= 0;
+               return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
+                                      translateIfPossible(from_ascii(second->prettyname()))) <= 0;
        }
 };
 
 
-bool GuiView::exportBufferAs(Buffer & b)
+bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
 {
        FileName fname = b.fileName();
 
@@ -2363,37 +2398,50 @@ bool GuiView::exportBufferAs(Buffer & b)
        dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
 
        QStringList types;
-       types << "Any supported format (*.*)";
+       QString const anyformat = qt_("Guess from extension (*.*)");
+       types << anyformat;
        Formats::const_iterator it = formats.begin();
        vector<Format const *> export_formats;
        for (; it != formats.end(); ++it)
-               if (it->documentFormat() && it->inExportMenu())
+               if (it->documentFormat())
                        export_formats.push_back(&(*it));
        PrettyNameComparator cmp;
        sort(export_formats.begin(), export_formats.end(), cmp);
        vector<Format const *>::const_iterator fit = export_formats.begin();
-       for (; fit != export_formats.end(); ++fit)
-               types << toqstr((*fit)->prettyname() + " (*." + (*fit)->extension() + ")");
+       map<QString, string> fmap;
        QString filter;
+       string ext;
+       for (; fit != export_formats.end(); ++fit) {
+               docstring const loc_prettyname =
+                       translateIfPossible(from_utf8((*fit)->prettyname()));
+               QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
+                                                    loc_prettyname,
+                                                    from_ascii((*fit)->extension())));
+               types << loc_filter;
+               fmap[loc_filter] = (*fit)->name();
+               if (from_ascii((*fit)->name()) == iformat) {
+                       filter = loc_filter;
+                       ext = (*fit)->extension();
+               }
+       }
+       string ofname = fname.onlyFileName();
+       if (!ext.empty())
+               ofname = support::changeExtension(ofname, ext);
        FileDialog::Result result =
                dlg.save(toqstr(fname.onlyPath().absFileName()),
                         types,
-                        toqstr(fname.onlyFileName()),
+                        toqstr(ofname),
                         &filter);
        if (result.first != FileDialog::Chosen)
                return false;
 
-       string s = fromqstr(filter);
-       size_t pos = s.find(" (*.");
-       LASSERT(pos != string::npos, /**/);
-       string fmt_prettyname = s.substr(0, pos);
        string fmt_name;
        fname.set(fromqstr(result.second));
-       if (fmt_prettyname == "Any supported format")
+       if (filter == anyformat)
                fmt_name = formats.getFormatFromExtension(fname.extension());
        else
-               fmt_name = formats.getFormatFromPrettyName(fmt_prettyname);
-       LYXERR(Debug::FILES, "fmt_prettyname=" << fmt_prettyname
+               fmt_name = fmap[filter];
+       LYXERR(Debug::FILES, "filter=" << fromqstr(filter)
               << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
 
        if (fmt_name.empty() || fname.empty())
@@ -2410,7 +2458,7 @@ bool GuiView::exportBufferAs(Buffer & b)
                        text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
                switch (ret) {
                case 0: break;
-               case 1: return exportBufferAs(b);
+               case 1: return exportBufferAs(b, from_ascii(fmt_name));
                case 2: return false;
                }
        }
@@ -2855,7 +2903,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
                if (!buffer->lyxvc().inUse()) {
                        if (buffer->lyxvc().registrer()) {
                                reloadBuffer(*buffer);
-                               dr.suppressMessageUpdate();
+                               dr.clearMessageUpdate();
                        }
                }
                break;
@@ -2935,7 +2983,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
                LASSERT(buffer, return);
                if (buffer->lyxvc().revert()) {
                        reloadBuffer(*buffer);
-                       dr.suppressMessageUpdate();
+                       dr.clearMessageUpdate();
                }
                break;
 
@@ -2943,7 +2991,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
                LASSERT(buffer, return);
                buffer->lyxvc().undoLast();
                reloadBuffer(*buffer);
-               dr.suppressMessageUpdate();
+               dr.clearMessageUpdate();
                break;
 
        case LFUN_VC_REPO_UPDATE:
@@ -3212,7 +3260,7 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
 void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
 {
        BufferView * bv = currentBufferView();
-       LASSERT(bv, /**/);
+       LASSERT(bv, return);
 
        // Let the current BufferView dispatch its own actions.
        bv->dispatch(cmd, dr);
@@ -3279,11 +3327,19 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                case LFUN_BUFFER_EXPORT: {
                        if (!doc_buffer)
                                break;
+                       FileName target_dir = doc_buffer->fileName().onlyPath();
+                       string const dest = cmd.getArg(1);
+                       if (!dest.empty() && FileName::isAbsolute(dest))
+                               target_dir = FileName(support::onlyPath(dest));
                        // GCC only sees strfwd.h when building merged
                        if (::lyx::operator==(cmd.argument(), "custom")) {
                                dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
                                break;
                        }
+                       if (!target_dir.isDirWritable()) {
+                               exportBufferAs(*doc_buffer, cmd.argument());
+                               break;
+                       }
                        /* TODO/Review: Is it a problem to also export the children?
                                        See the update_unincluded flag */
                        d.asyncBufferProcessing(argument,
@@ -3296,10 +3352,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
                }
 
-               case LFUN_BUFFER_EXPORT_AS:
+               case LFUN_BUFFER_EXPORT_AS: {
                        LASSERT(doc_buffer, break);
-                       exportBufferAs(*doc_buffer);
+                       docstring f = cmd.argument();
+                       if (f.empty())
+                               f = from_ascii(doc_buffer->params().getDefaultOutputFormat());
+                       exportBufferAs(*doc_buffer, f);
                        break;
+               }
 
                case LFUN_BUFFER_UPDATE: {
                        d.asyncBufferProcessing(argument,
@@ -3412,7 +3472,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
                case LFUN_FILE_INSERT_PLAINTEXT:
                case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
-                       bool const as_paragraph = (cmd.action() == LFUN_FILE_INSERT_PLAINTEXT_PARA);
                        string const fname = to_utf8(cmd.argument());
                        if (!fname.empty() && !FileName::isAbsolute(fname)) {
                                dr.setMessage(_("Absolute filename expected."));
@@ -3421,8 +3480,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        
                        FileName filename(fname);
                        if (fname.empty()) {
-                               FileDialog dlg(qt_("Select file to insert"), (as_paragraph ?
-                                       LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
+                               FileDialog dlg(qt_("Select file to insert"));
 
                                FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
                                        QStringList(qt_("All Files (*)")));
@@ -3647,7 +3705,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
 
 
-               case LFUN_COMPLETION_COMPLETE:
+               case LFUN_COMPLETE:
                        if (d.current_work_area_)
                                d.current_work_area_->completer().tab();
                        break;
@@ -3758,6 +3816,12 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        one.startscript(Systemcall::DontWait, command);
                        break;
                }
+
+               case LFUN_SPELLING_CONTINUOUSLY:
+                       lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
+                       dr.screenUpdate(Update::Force | Update::FitCursor);
+                       break;
+
                default:
                        // The LFUN must be for one of BufferView, Buffer or Cursor;
                        // let's try that:
@@ -3769,8 +3833,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        if (isFullScreen()) {
                if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
                        menuBar()->hide();
-               if (statusBar()->isVisible())
-                       statusBar()->hide();
        }
 }
 
@@ -3829,7 +3891,8 @@ void GuiView::toggleFullScreen()
                setContentsMargins(-2, -2, -2, -2);
                saveLayout();
                setWindowState(windowState() ^ Qt::WindowFullScreen);
-               statusBar()->hide();
+               if (lyxrc.full_screen_statusbar)
+                       statusBar()->hide();
                if (lyxrc.full_screen_menubar)
                        menuBar()->hide();
                if (lyxrc.full_screen_toolbars) {