]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Replay r36745
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 5b5ccf6e2c803ccbdff54d0dbc1e4d1a2ce33cfe..8585fb4cb1471ac8b62518517a0da8dba7822e86 100644 (file)
 # include <unistd.h>
 #endif
 
+
 using namespace std;
 using namespace lyx::support;
 
@@ -374,7 +375,7 @@ public:
        static docstring previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
        static docstring exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
        static docstring compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
-       static docstring saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname);
+       static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer);
 
        template<class T>
        static docstring runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format, string const & msg);
@@ -445,7 +446,7 @@ GuiView::GuiView(int id)
 
 #if (QT_VERSION >= 0x040400)
        connect(&d.autosave_watcher_, SIGNAL(finished()), this,
-               SLOT(processingThreadFinished()));
+               SLOT(autoSaveThreadFinished()));
        connect(&d.processing_thread_watcher_, SIGNAL(finished()), this,
                SLOT(processingThreadFinished()));
 
@@ -495,6 +496,8 @@ QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
        return areas;
 }
 
+
+#if QT_VERSION >= 0x040400
 void GuiView::setCursorShapes(Qt::CursorShape shape)
 {
        QVector<GuiWorkArea*> areas = d.guiWorkAreas();
@@ -503,6 +506,7 @@ void GuiView::setCursorShapes(Qt::CursorShape shape)
        }
 }
 
+
 void GuiView::restoreCursorShapes()
 {
        QVector<GuiWorkArea*> areas = d.guiWorkAreas();
@@ -513,6 +517,7 @@ void GuiView::restoreCursorShapes()
        }
 }
 
+
 void GuiView::saveCursorShapes()
 {
        d.orig_cursors_.clear();
@@ -522,6 +527,7 @@ void GuiView::saveCursorShapes()
        }
 }
 
+
 void GuiView::indicateProcessing()
 {
        if (d.indicates_processing_) {
@@ -532,6 +538,7 @@ void GuiView::indicateProcessing()
        d.indicates_processing_ = !d.indicates_processing_;
 }
 
+
 void GuiView::processingThreadStarted()
 {
        saveCursorShapes();
@@ -540,21 +547,74 @@ void GuiView::processingThreadStarted()
        d.processing_cursor_timer_.start();
 }
 
-void GuiView::processingThreadFinished()
+
+void GuiView::processingThreadFinished(bool show_errors)
 {
-#if (QT_VERSION >= 0x040400)
        QFutureWatcher<docstring> const * watcher =
                static_cast<QFutureWatcher<docstring> const *>(sender());
        message(watcher->result());
        updateToolbars();
-       errors(d.last_export_format);
+       if (show_errors) {
+               errors(d.last_export_format);
+       }
        d.processing_cursor_timer_.stop();
        restoreCursorShapes();
        d.indicates_processing_ = false;
-#endif
+}
+
+void GuiView::processingThreadFinished()
+{
+       processingThreadFinished(true);
+}
+
+void GuiView::autoSaveThreadFinished()
+{
+       processingThreadFinished(false);
+}
+
+#else
+
+void GuiView::setCursorShapes(Qt::CursorShape)
+{
+}
+
+
+void GuiView::restoreCursorShapes()
+{
+}
+
+
+void GuiView::saveCursorShapes()
+{
 }
 
 
+void GuiView::indicateProcessing()
+{
+}
+
+
+void GuiView::processingThreadStarted()
+{
+}
+
+
+void GuiView::processingThreadFinished(bool)
+{
+}
+
+
+void GuiView::processingThreadFinished()
+{
+}
+
+
+void GuiView::autoSaveThreadFinished()
+{
+}
+#endif
+
+
 void GuiView::saveLayout() const
 {
        QSettings settings;
@@ -764,7 +824,8 @@ void GuiView::closeEvent(QCloseEvent * close_event)
        LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
 
        if (!GuiViewPrivate::busyBuffers.isEmpty()) {
-               Alert::warning(_("Exit LyX"), _("LyX could not be closed because documents are processed by LyX."));
+               Alert::warning(_("Exit LyX"), 
+                       _("LyX could not be closed because documents are being processed by LyX."));
                close_event->setAccepted(false);
                return;
        }
@@ -1138,6 +1199,15 @@ void GuiView::setBusy(bool busy)
 }
 
 
+GuiWorkArea * GuiView::workArea(int index)
+{
+       if (TabWorkArea * twa = d.currentTabWorkArea())
+               if (index < twa->count())
+                       return dynamic_cast<GuiWorkArea *>(twa->widget(index));
+       return 0;
+}
+
+
 GuiWorkArea * GuiView::workArea(Buffer & buffer)
 {
        if (currentWorkArea()
@@ -1455,23 +1525,15 @@ BufferView const * GuiView::currentBufferView() const
 
 
 #if (QT_VERSION >= 0x040400)
-docstring GuiView::GuiViewPrivate::saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname)
+docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
+       Buffer const * orig, Buffer * buffer)
 {
-       bool failed = true;
-       FileName const tmp_ret = FileName::tempName("lyxauto");
-       if (!tmp_ret.empty()) {
-               if (buffer->writeFile(tmp_ret))
-                       failed = !tmp_ret.moveTo(fname);
-       }
-       if (failed) {
-               // failed to write/rename tmp_ret so try writing direct
-               failed = buffer->writeFile(fname);
-       }
+       bool const success = buffer->autoSave();
        delete buffer;
        busyBuffers.remove(orig);
-       return failed
-               ? _("Automatic save failed!")
-               : _("Automatic save done.");
+       return success
+               ? _("Automatic save done.")
+               : _("Automatic save failed!");
 }
 #endif
 
@@ -1487,12 +1549,13 @@ void GuiView::autoSave()
 
 #if (QT_VERSION >= 0x040400)
        GuiViewPrivate::busyBuffers.insert(buffer);
-       QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::saveAndDestroy, buffer, buffer->clone(),
-               buffer->getAutosaveFileName());
+       QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
+               buffer, buffer->clone());
        d.autosave_watcher_.setFuture(f);
 #else
        buffer->autoSave();
 #endif
+       resetAutosaveTimers();
 }
 
 
@@ -2240,50 +2303,30 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
                }
        }
 
-       FileName oldauto = b.getAutosaveFileName();
-
-       // Ok, change the name of the buffer
-       b.setFileName(fname.absFileName());
-       b.markDirty();
-       bool unnamed = b.isUnnamed();
-       b.setUnnamed(false);
-       b.saveCheckSum();
-
-       // bring the autosave file with us, just in case.
-       b.moveAutosaveFile(oldauto);
-
-       if (!saveBuffer(b)) {
-               oldauto = b.getAutosaveFileName();
-               b.setFileName(oldname.absFileName());
-               b.setUnnamed(unnamed);
-               b.saveCheckSum();
-               b.moveAutosaveFile(oldauto);
-               return false;
-       }
-
-       // validate version control data and
-       // correct buffer title
-       b.lyxvc().file_found_hook(b.fileName());
-       b.updateTitles();
+       return saveBuffer(b, fname);
+}
 
-       // the file has now been saved to the new location.
-       // we need to check that the locations of child buffers
-       // are still valid.
-       b.checkChildBuffers();
 
-       return true;
+bool GuiView::saveBuffer(Buffer & b) {
+       return saveBuffer(b, FileName());
 }
 
 
-bool GuiView::saveBuffer(Buffer & b)
+bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
 {
        if (workArea(b) && workArea(b)->inDialogMode())
                return true;
 
-       if (b.isUnnamed())
-               return renameBuffer(b, docstring());
+       if (fn.empty() && b.isUnnamed())
+                       return renameBuffer(b, docstring());
 
-       if (b.save()) {
+       bool success;
+       if (fn.empty())
+               success = b.save();
+       else
+               success = b.saveAs(fn);
+       
+       if (success) {
                theSession().lastFiles().add(b.fileName());
                return true;
        }
@@ -2403,7 +2446,8 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
        Buffer & buf = wa->bufferView().buffer();
 
        if (close_buffer && GuiViewPrivate::busyBuffers.contains(&buf)) {
-               Alert::warning(_("Close document "), _("Document could not be closed because it is processed by LyX."));
+               Alert::warning(_("Close document"), 
+                       _("Document could not be closed because it is being processed by LyX."));
                return false;
        }
 
@@ -2519,10 +2563,10 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
                        return false;
                break;
        case 1:
-               // if we crash after this we could
-               // have no autosave file but I guess
-               // this is really improbable (Jug)
-               // Sometime improbable things happen, bug 6857 (ps)
+               // If we crash after this we could have no autosave file
+               // but I guess this is really improbable (Jug).
+               // Sometimes improbable things happen:
+               // - see bug http://www.lyx.org/trac/ticket/6587 (ps)
                // buf.removeAutosaveFile();
                if (hiding)
                        // revert all changes
@@ -2568,24 +2612,24 @@ bool GuiView::inMultiViews(GuiWorkArea * wa)
 
 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np)
 {
-       Buffer * const curbuf = documentBufferView()
-               ? &documentBufferView()->buffer() : 0;
-       Buffer * nextbuf = curbuf;
-       while (true) {
-               if (np == NEXTBUFFER)
-                       nextbuf = theBufferList().next(nextbuf);
-               else
-                       nextbuf = theBufferList().previous(nextbuf);
-               if (nextbuf == curbuf)
-                       break;
-               if (nextbuf == 0) {
-                       nextbuf = curbuf;
-                       break;
+       if (!documentBufferView())
+               return;
+       
+       if (TabWorkArea * twa = d.currentTabWorkArea()) {
+               Buffer * const curbuf = &documentBufferView()->buffer();
+               int nwa = twa->count();
+               for (int i = 0; i < nwa; ++i) {
+                       if (&workArea(i)->bufferView().buffer() == curbuf) {
+                               int next_index;
+                               if (np == NEXTBUFFER)
+                                       next_index = (i == nwa - 1 ? 0 : i + 1);
+                               else
+                                       next_index = (i == 0 ? nwa - 1 : i - 1);
+                               setBuffer(&workArea(next_index)->bufferView().buffer());
+                               break;
+                       }
                }
-               if (workArea(*nextbuf))
-                       break;
        }
-       setBuffer(nextbuf);
 }
 
 
@@ -2891,29 +2935,61 @@ docstring GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * o
        bool const success = func(format, update_unincluded);
        delete buffer;
        busyBuffers.remove(orig);
+       if (msg == "preview") {
+               return success
+                       ? bformat(_("Successful preview of format: %1$s"), from_utf8(format))
+                       : bformat(_("Error while previewing format: %1$s"), from_utf8(format));
+       }
        return success
-               ? bformat(_("Successful " + msg + " to format: %1$s"), from_utf8(format))
-               : bformat(_("Error " + msg + " format: %1$s"), from_utf8(format));
+               ? bformat(_("Successful export to format: %1$s"), from_utf8(format))
+               : bformat(_("Error while exporting format: %1$s"), from_utf8(format));
 }
 
+
 docstring GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
 {
        bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExport;
        return runAndDestroy(bind(mem_func, buffer, _1, true, _2), orig, buffer, format, "export");
 }
 
+
 docstring GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
 {
        bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExport;
        return runAndDestroy(bind(mem_func, buffer, _1, false, _2), orig, buffer, format, "export");
-
 }
 
+
 docstring GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
 {
        bool(Buffer::* mem_func)(std::string const &, bool) const = &Buffer::preview;
        return runAndDestroy(bind(mem_func, buffer, _1, _2), orig, buffer, format, "preview");
 }
+
+#else
+
+// not used, but the linker needs them
+
+docstring GuiView::GuiViewPrivate::compileAndDestroy(
+               Buffer const *, Buffer *, string const &)
+{
+       return docstring();
+}
+
+
+docstring GuiView::GuiViewPrivate::exportAndDestroy(
+               Buffer const *, Buffer *, string const &)
+{
+       return docstring();
+}
+
+
+docstring GuiView::GuiViewPrivate::previewAndDestroy(
+               Buffer const *, Buffer *, string const &)
+{
+       return docstring();
+}
+
 #endif
 
 
@@ -2925,15 +3001,15 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
                           bool (Buffer::*syncFunc)(string const &, bool, bool) const,
                           bool (Buffer::*previewFunc)(string const &, bool) const)
 {
-       if (!used_buffer) {
+       if (!used_buffer)
                return false;
-       }
-       gv_->processingThreadStarted();
+
        string format = argument;
-       if (format.empty()) {
+       if (format.empty())
                format = used_buffer->getDefaultOutputFormat();
-       }
+
 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
+       gv_->processingThreadStarted();
        if (!msg.empty()) {
                progress_->clearMessages();
                gv_->message(msg);
@@ -2951,19 +3027,58 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
        // We are asynchronous, so we don't know here anything about the success
        return true;
 #else
-       bool const update_unincluded =
-               used_buffer->params().maintain_unincluded_children &&
-               !used_buffer->params().getIncludedChildren().empty();
        if (syncFunc) {
+               // TODO check here if it breaks exporting with Qt < 4.4
+               bool const update_unincluded =
+                               used_buffer->params().maintain_unincluded_children &&
+                               !used_buffer->params().getIncludedChildren().empty();
                return (used_buffer->*syncFunc)(format, true, update_unincluded);
        } else if (previewFunc) {
-               return (used_buffer->*previewFunc)(format, update_unincluded);
+               return (used_buffer->*previewFunc)(format, false);
        }
        (void) asyncFunc;
        return false;
 #endif
 }
 
+void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
+{
+       BufferView * bv = currentBufferView();
+       LASSERT(bv, /**/);
+
+       // Let the current BufferView dispatch its own actions.
+       bv->dispatch(cmd, dr);
+       if (dr.dispatched())
+               return;
+
+       // Try with the document BufferView dispatch if any.
+       BufferView * doc_bv = documentBufferView();
+       if (doc_bv) {
+               doc_bv->dispatch(cmd, dr);
+               if (dr.dispatched())
+                       return;
+       }
+
+       // Then let the current Cursor dispatch its own actions.
+       bv->cursor().dispatch(cmd);
+
+       // update completion. We do it here and not in
+       // processKeySym to avoid another redraw just for a
+       // changed inline completion
+       if (cmd.origin() == FuncRequest::KEYBOARD) {
+               if (cmd.action() == LFUN_SELF_INSERT
+                       || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed()))
+                       updateCompletion(bv->cursor(), true, true);
+               else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD)
+                       updateCompletion(bv->cursor(), false, true);
+               else
+                       updateCompletion(bv->cursor(), false, false);
+       }
+
+       dr = bv->cursor().result();
+}
+
+
 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 {
        BufferView * bv = currentBufferView();
@@ -3001,8 +3116,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
                                break;
                        }
-#if 0
-                       // TODO Remove if we could export asynchronous
+#if QT_VERSION < 0x040400
                        if (!doc_buffer->doExport(argument, false)) {
                                dr.setError(true);
                                dr.setMessage(bformat(_("Error exporting to format: %1$s."),
@@ -3423,7 +3537,9 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
                }
                default:
-                       dr.dispatched(false);
+                       // The LFUN must be for one of BufferView, Buffer or Cursor;
+                       // let's try that:
+                       dispatchToBufferView(cmd, dr);
                        break;
        }
 
@@ -3434,8 +3550,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                if (statusBar()->isVisible())
                        statusBar()->hide();
        }
-
-       return;
 }