]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Use QMessageBox for toggleWarning if possible
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index d2e3ed9f2780d5e3bcbfb5e972a700d07df5b0fa..0eb48cfedcf0cddfd134fdfa8ae65621b4e0ccfd 100644 (file)
@@ -498,7 +498,8 @@ public:
                                   docstring const & msg,
                                   Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
                                   Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
-                                  Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const);
+                                  Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const,
+                                  bool allow_async);
 
        QVector<GuiWorkArea*> guiWorkAreas();
 };
@@ -508,7 +509,8 @@ QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
 
 GuiView::GuiView(int id)
        : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
-         command_execute_(false), minibuffer_focus_(false), devel_mode_(false)
+         command_execute_(false), minibuffer_focus_(false), toolbarsMovable_(true),
+         devel_mode_(false)
 {
        connect(this, SIGNAL(bufferViewChanged()),
                this, SLOT(onBufferViewChanged()));
@@ -577,9 +579,25 @@ GuiView::GuiView(int id)
                busylabel, SLOT(hide()));
 
        QFontMetrics const fm(statusBar()->fontMetrics());
-       int const roheight = max(int(d.normalIconSize), fm.height());
-       QSize const rosize(roheight, roheight);
-       QPixmap readonly = QIcon(getPixmap("images/", "emblem-readonly", "svgz,png")).pixmap(rosize);
+       int const iconheight = max(int(d.normalIconSize), fm.height());
+       QSize const iconsize(iconheight, iconheight);
+
+       QPixmap shellescape = QIcon(getPixmap("images/", "emblem-shellescape", "svgz,png")).pixmap(iconsize);
+       shell_escape_ = new QLabel(statusBar());
+       shell_escape_->setPixmap(shellescape);
+       shell_escape_->setScaledContents(true);
+       shell_escape_->setAlignment(Qt::AlignCenter);
+       shell_escape_->setContextMenuPolicy(Qt::CustomContextMenu);
+       shell_escape_->setToolTip(qt_("WARNING: LaTeX is allowed to execute "
+                                     "external commands for this document. "
+                                     "Right click to change."));
+       SEMenu * menu = new SEMenu(this);
+       connect(shell_escape_, SIGNAL(customContextMenuRequested(QPoint)),
+               menu, SLOT(showMenu(QPoint)));
+       shell_escape_->hide();
+       statusBar()->addPermanentWidget(shell_escape_);
+
+       QPixmap readonly = QIcon(getPixmap("images/", "emblem-readonly", "svgz,png")).pixmap(iconsize);
        read_only_ = new QLabel(statusBar());
        read_only_->setPixmap(readonly);
        read_only_->setScaledContents(true);
@@ -638,6 +656,17 @@ GuiView::~GuiView()
 }
 
 
+void GuiView::disableShellEscape()
+{
+       BufferView * bv = documentBufferView();
+       if (!bv)
+               return;
+       theSession().shellescapeFiles().remove(bv->buffer().absFileName());
+       bv->buffer().params().shell_escape = false;
+       bv->processUpdateFlags(Update::Force);
+}
+
+
 QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
 {
        QVector<GuiWorkArea*> areas;
@@ -698,7 +727,10 @@ void GuiView::processingThreadFinished()
                errors("Export");
                return;
        }
-       errors(d.last_export_format);
+       if (status != Buffer::ExportSuccess && status != Buffer::PreviewSuccess &&
+           status != Buffer::ExportCancel) {
+               errors(d.last_export_format);
+       }
 }
 
 
@@ -714,7 +746,7 @@ void GuiView::autoSaveThreadFinished()
 void GuiView::saveLayout() const
 {
        QSettings settings;
-       settings.setValue("zoom", lyxrc.currentZoom);
+       settings.setValue("zoom_ratio", zoom_ratio_);
        settings.setValue("devel_mode", devel_mode_);
        settings.beginGroup("views");
        settings.beginGroup(QString::number(id_));
@@ -731,22 +763,28 @@ void GuiView::saveLayout() const
 
 void GuiView::saveUISettings() const
 {
+       QSettings settings;
+
        // Save the toolbar private states
        ToolbarMap::iterator end = d.toolbars_.end();
        for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-               it->second->saveSession();
+               it->second->saveSession(settings);
        // Now take care of all other dialogs
        map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
        for (; it!= d.dialogs_.end(); ++it)
-               it->second->saveSession();
+               it->second->saveSession(settings);
 }
 
 
 bool GuiView::restoreLayout()
 {
        QSettings settings;
-       lyxrc.currentZoom = settings.value("zoom", lyxrc.zoom).toInt();
-       lyx::dispatch(FuncRequest(LFUN_BUFFER_ZOOM, convert<docstring>(lyxrc.currentZoom)));
+       zoom_ratio_ = settings.value("zoom_ratio", 1.0).toDouble();
+       // Actual zoom value: default zoom + fractional offset
+       int zoom = lyxrc.defaultZoom * zoom_ratio_;
+       if (zoom < static_cast<int>(zoom_min_))
+               zoom = zoom_min_;
+       lyxrc.currentZoom = zoom;
        devel_mode_ = settings.value("devel_mode", devel_mode_).toBool();
        settings.beginGroup("views");
        settings.beginGroup(QString::number(id_));
@@ -1160,6 +1198,11 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa)
        // Tell Qt whether the current document is changed
        setWindowModified(!buf.isClean());
 
+       if (buf.params().shell_escape)
+               shell_escape_->show();
+       else
+               shell_escape_->hide();
+
        if (buf.hasReadonlyFlag())
                read_only_->show();
        else
@@ -1818,6 +1861,15 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
        case LFUN_BUFFER_IMPORT:
                break;
 
+       case LFUN_MASTER_BUFFER_EXPORT:
+               enable = doc_buffer
+                       && (doc_buffer->parent() != 0
+                           || doc_buffer->hasChildren())
+                       && !d.processing_thread_watcher_.isRunning()
+                       // this launches a dialog, which would be in the wrong Buffer
+                       && !(::lyx::operator==(cmd.argument(), "custom"));
+               break;
+
        case LFUN_MASTER_BUFFER_UPDATE:
        case LFUN_MASTER_BUFFER_VIEW:
                enable = doc_buffer
@@ -1841,7 +1893,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        case LFUN_BUFFER_RELOAD:
                enable = doc_buffer && !doc_buffer->isUnnamed()
-                       && doc_buffer->fileName().exists() && !doc_buffer->isClean();
+                       && doc_buffer->fileName().exists()
+                       && (!doc_buffer->isClean() || doc_buffer->notifiesExternalModification());
                break;
 
        case LFUN_BUFFER_CHILD_OPEN:
@@ -1875,8 +1928,22 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                enable = doc_buffer && doc_buffer->notifiesExternalModification();
                break;
 
-       case LFUN_BUFFER_WRITE_AS:
+       case LFUN_BUFFER_EXPORT: {
+               if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
+                       enable = false;
+                       break;
+               }
+               return doc_buffer->getStatus(cmd, flag);
+               break;
+       }
+
        case LFUN_BUFFER_EXPORT_AS:
+               if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
+                       enable = false;
+                       break;
+               }
+               // fall through
+       case LFUN_BUFFER_WRITE_AS:
                enable = doc_buffer != 0;
                break;
 
@@ -1889,6 +1956,23 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                enable = theBufferList().last() != theBufferList().first();
                break;
 
+       case LFUN_BUFFER_CHKTEX: {
+               // hide if we have no checktex command
+               if (lyxrc.chktex_command.empty()) {
+                       flag.setUnknown(true);
+                       enable = false;
+                       break;
+               }
+               if (!doc_buffer || !doc_buffer->params().isLatex()
+                   || d.processing_thread_watcher_.isRunning()) {
+                       // grey out, don't hide
+                       enable = false;
+                       break;
+               }
+               enable = true;
+               break;
+       }
+
        case LFUN_VIEW_SPLIT:
                if (cmd.getArg(0) == "vertical")
                        enable = doc_buffer && (d.splitter_->count() == 1 ||
@@ -1957,7 +2041,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        case LFUN_DIALOG_TOGGLE:
                flag.setOnOff(isDialogVisible(cmd.getArg(0)));
-               // fall through to set "enable"
+               // to set "enable"
+               // fall through
        case LFUN_DIALOG_SHOW: {
                string const name = cmd.getArg(0);
                if (!doc_buffer)
@@ -2189,8 +2274,10 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
        setBuffer(newBuffer);
        newBuffer->errors("Parse");
 
-       if (tolastfiles)
+       if (tolastfiles) {
                theSession().lastFiles().add(filename);
+               theSession().writeFile();
+  }
 
        return newBuffer;
 }
@@ -2729,6 +2816,7 @@ bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
        bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
        if (success) {
                theSession().lastFiles().add(b.fileName());
+               theSession().writeFile();
                return true;
        }
 
@@ -3136,6 +3224,7 @@ static bool ensureBufferClean(Buffer * buffer)
 
 bool GuiView::reloadBuffer(Buffer & buf)
 {
+       currentBufferView()->cursor().reset();
        Buffer::ReadStatus status = buf.reload();
        return status == Buffer::ReadSuccess;
 }
@@ -3492,7 +3581,8 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
                           docstring const & msg,
                           Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
                           Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
-                          Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
+                          Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const,
+                          bool allow_async)
 {
        if (!used_buffer)
                return false;
@@ -3506,24 +3596,38 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
                gv_->message(msg);
        }
 #if EXPORT_in_THREAD
-       GuiViewPrivate::busyBuffers.insert(used_buffer);
-       Buffer * cloned_buffer = used_buffer->cloneFromMaster();
-       if (!cloned_buffer) {
-               Alert::error(_("Export Error"),
-                            _("Error cloning the Buffer."));
-               return false;
+       if (allow_async) {
+               GuiViewPrivate::busyBuffers.insert(used_buffer);
+               Buffer * cloned_buffer = used_buffer->cloneFromMaster();
+               if (!cloned_buffer) {
+                       Alert::error(_("Export Error"),
+                                                                        _("Error cloning the Buffer."));
+                       return false;
+               }
+               QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
+                                       asyncFunc,
+                                       used_buffer,
+                                       cloned_buffer,
+                                       format);
+               setPreviewFuture(f);
+               last_export_format = used_buffer->params().bufferFormat();
+               (void) syncFunc;
+               (void) previewFunc;
+               // We are asynchronous, so we don't know here anything about the success
+               return true;
+       } else {
+               Buffer::ExportStatus status;
+               if (syncFunc) {
+                       status = (used_buffer->*syncFunc)(format, false);
+               } else if (previewFunc) {
+                       status = (used_buffer->*previewFunc)(format);
+               } else
+                       return false;
+               handleExportStatus(gv_, status, format);
+               (void) asyncFunc;
+               return (status == Buffer::ExportSuccess
+                               || status == Buffer::PreviewSuccess);
        }
-       QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
-                               asyncFunc,
-                               used_buffer,
-                               cloned_buffer,
-                               format);
-       setPreviewFuture(f);
-       last_export_format = used_buffer->params().bufferFormat();
-       (void) syncFunc;
-       (void) previewFunc;
-       // We are asynchronous, so we don't know here anything about the success
-       return true;
 #else
        Buffer::ExportStatus status;
        if (syncFunc) {
@@ -3606,11 +3710,19 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        importDocument(to_utf8(cmd.argument()));
                        break;
 
+               case LFUN_MASTER_BUFFER_EXPORT:
+                       if (doc_buffer)
+                               doc_buffer = const_cast<Buffer *>(doc_buffer->masterBuffer());
+                       // fall through
                case LFUN_BUFFER_EXPORT: {
                        if (!doc_buffer)
                                break;
                        // GCC only sees strfwd.h when building merged
                        if (::lyx::operator==(cmd.argument(), "custom")) {
+                               // LFUN_MASTER_BUFFER_EXPORT is not enabled for this case,
+                               // so the following test should not be needed.
+                               // In principle, we could try to switch to such a view...
+                               // if (cmd.action() == LFUN_BUFFER_EXPORT)
                                dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
                                break;
                        }
@@ -3637,7 +3749,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Exporting ..."),
                                                &GuiViewPrivate::exportAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        // TODO Inform user about success
                        break;
                }
@@ -3657,7 +3769,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Exporting ..."),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        break;
                }
                case LFUN_BUFFER_VIEW: {
@@ -3666,7 +3778,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Previewing ..."),
                                                &GuiViewPrivate::previewAndDestroy,
                                                0,
-                                               &Buffer::preview);
+                                               &Buffer::preview, cmd.allowAsync());
                        break;
                }
                case LFUN_MASTER_BUFFER_UPDATE: {
@@ -3675,7 +3787,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                docstring(),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        break;
                }
                case LFUN_MASTER_BUFFER_VIEW: {
@@ -3683,7 +3795,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                (doc_buffer ? doc_buffer->masterBuffer() : 0),
                                                docstring(),
                                                &GuiViewPrivate::previewAndDestroy,
-                                               0, &Buffer::preview);
+                                               0, &Buffer::preview, cmd.allowAsync());
                        break;
                }
                case LFUN_BUFFER_SWITCH: {
@@ -3746,6 +3858,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        gotoNextOrPreviousBuffer(PREVBUFFER, true);
                        break;
 
+               case LFUN_BUFFER_CHKTEX:
+                       LASSERT(doc_buffer, break);
+                       doc_buffer->runChktex();
+                       break;
+
                case LFUN_COMMAND_EXECUTE: {
                        command_execute_ = true;
                        minibuffer_focus_ = true;
@@ -4082,36 +4199,37 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                case LFUN_BUFFER_ZOOM_IN:
                case LFUN_BUFFER_ZOOM_OUT:
                case LFUN_BUFFER_ZOOM: {
-                       // use a signed temp to avoid overflow
-                       int zoom = lyxrc.currentZoom;
                        if (cmd.argument().empty()) {
                                if (cmd.action() == LFUN_BUFFER_ZOOM)
-                                       zoom = lyxrc.zoom;
+                                       zoom_ratio_ = 1.0;
                                else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
-                                       zoom += 20;
+                                       zoom_ratio_ += 0.1;
                                else
-                                       zoom -= 20;
+                                       zoom_ratio_ -= 0.1;
                        } else {
                                if (cmd.action() == LFUN_BUFFER_ZOOM)
-                                       zoom = convert<int>(cmd.argument());
+                                       zoom_ratio_ = convert<int>(cmd.argument()) / double(lyxrc.defaultZoom);
                                else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
-                                       zoom += convert<int>(cmd.argument());
+                                       zoom_ratio_ += convert<int>(cmd.argument()) / 100.0;
                                else
-                                       zoom -= convert<int>(cmd.argument());
+                                       zoom_ratio_ -= convert<int>(cmd.argument()) / 100.0;
                        }
 
+                       // Actual zoom value: default zoom + fractional extra value
+                       int zoom = lyxrc.defaultZoom * zoom_ratio_;
                        if (zoom < static_cast<int>(zoom_min_))
                                zoom = zoom_min_;
 
                        lyxrc.currentZoom = zoom;
 
-                       dr.setMessage(bformat(_("Zoom level is now %1$d%"), lyxrc.currentZoom));
+                       dr.setMessage(bformat(_("Zoom level is now %1$d% (default value: %2$d%)"),
+                                             lyxrc.currentZoom, lyxrc.defaultZoom));
 
                        // The global QPixmapCache is used in GuiPainter to cache text
                        // painting so we must reset it.
                        QPixmapCache::clear();
                        guiApp->fontLoader().update();
-                       lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
+                       dr.screenUpdate(Update::Force | Update::FitCursor);
                        break;
                }
 
@@ -4307,19 +4425,19 @@ Buffer const * GuiView::updateInset(Inset const * inset)
                        continue;
                Buffer const * buffer = &(wa->bufferView().buffer());
                if (inset_buffer == buffer)
-                       wa->scheduleRedraw();
+                       wa->scheduleRedraw(true);
        }
        return inset_buffer;
 }
 
 
-void GuiView::restartCursor()
+void GuiView::restartCaret()
 {
        /* When we move around, or type, it's nice to be able to see
-        * the cursor immediately after the keypress.
+        * the caret immediately after the keypress.
         */
        if (d.current_work_area_)
-               d.current_work_area_->startBlinkingCursor();
+               d.current_work_area_->startBlinkingCaret();
 
        // Take this occasion to update the other GUI elements.
        updateDialogs();
@@ -4388,7 +4506,7 @@ void GuiView::resetDialogs()
        // Now update controls with current buffer.
        guiApp->setCurrentView(this);
        restoreLayout();
-       restartCursor();
+       restartCaret();
 }
 
 
@@ -4652,6 +4770,14 @@ Dialog * GuiView::build(string const & name)
 }
 
 
+SEMenu::SEMenu(QWidget * parent)
+{
+       QAction * action = addAction(qt_("Disable Shell Escape"));
+       connect(action, SIGNAL(triggered()),
+               parent, SLOT(disableShellEscape()));
+}
+
+
 } // namespace frontend
 } // namespace lyx