]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Now LyX closes the current document WA only by default (other WAs remain open).
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 4f55834e692a4f5c524ff630f43c1692f117db40..3eda5409a27cd6e0f4382abdb946e9e009ce7a4e 100644 (file)
@@ -330,8 +330,20 @@ struct GuiView::GuiViewPrivate
                return tabWorkArea(0);
        }
 
+       int countWorkAreasOf(Buffer & buf)
+       {
+               int areas = tabWorkAreaCount();
+               int count = 0;
+               for (int i = 0; i != areas;  ++i) {
+                       TabWorkArea * twa = tabWorkArea(i);
+                       if (twa->workArea(buf))
+                               ++count;
+               }
+               return count;
+       }
+
 #if (QT_VERSION >= 0x040400)
-       void setPreviewFuture(QFuture<docstring> const & f)
+       void setPreviewFuture(QFuture<Buffer::ExportStatus> const & f)
        {
                if (processing_thread_watcher_.isRunning()) {
                        // we prefer to cancel this preview in order to keep a snappy
@@ -382,30 +394,31 @@ public:
 #if (QT_VERSION >= 0x040400)
        ///
        QFutureWatcher<docstring> autosave_watcher_;
-       QFutureWatcher<docstring> processing_thread_watcher_;
+       QFutureWatcher<Buffer::ExportStatus> processing_thread_watcher_;
        ///
        string last_export_format;
+       string processing_format;
 #else
        struct DummyWatcher { bool isRunning(){return false;} };
        DummyWatcher processing_thread_watcher_;
 #endif
 
        static QSet<Buffer const *> busyBuffers;
-       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 Buffer::ExportStatus previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
+       static Buffer::ExportStatus exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
+       static Buffer::ExportStatus compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
        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);
+       static Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format);
 
        // TODO syncFunc/previewFunc: use bind
        bool asyncBufferProcessing(string const & argument,
                                   Buffer const * used_buffer,
                                   docstring const & msg,
-                                  docstring (*asyncFunc)(Buffer const *, Buffer *, string const &),
-                                  bool (Buffer::*syncFunc)(string const &, bool, bool) const,
-                                  bool (Buffer::*previewFunc)(string const &, bool) const);
+                                  Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
+                                  Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
+                                  Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const);
 
        QVector<GuiWorkArea*> guiWorkAreas();
 };
@@ -443,11 +456,18 @@ GuiView::GuiView(int id)
        setAttribute(Qt::WA_DeleteOnClose, true);
 
 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
+       // QIcon::fromTheme was introduced in Qt 4.6
+#if (QT_VERSION >= 0x040600)
        // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
-       // since the icon is provided in the application bundle.
+       // since the icon is provided in the application bundle. We use a themed
+       // version when available and use the bundled one as fallback.
+       setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "png")));
+#else
        setWindowIcon(getPixmap("images/", "lyx", "png"));
 #endif
 
+#endif
+
 #if (QT_VERSION >= 0x040300)
        // use tabbed dock area for multiple docks
        // (such as "source" and "messages")
@@ -527,55 +547,75 @@ QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
        return areas;
 }
 
-
-#if QT_VERSION >= 0x040400
-
-void GuiView::processingThreadStarted()
+static void handleExportStatus(GuiView * view, Buffer::ExportStatus status,
+       string const & format)
 {
+       docstring const fmt = formats.prettyName(format);
+       docstring msg;
+       switch (status) {
+       case Buffer::ExportSuccess:
+               msg = bformat(_("Successful export to format: %1$s"), fmt);
+               break;
+       case Buffer::ExportCancel:
+               msg = _("Document export cancelled.");
+               break;
+       case Buffer::ExportError:
+       case Buffer::ExportNoPathToFormat:
+       case Buffer::ExportTexPathHasSpaces:
+       case Buffer::ExportConverterError:
+               msg = bformat(_("Error while exporting format: %1$s"), fmt);
+               break;
+       case Buffer::PreviewSuccess:
+               msg = bformat(_("Successful preview of format: %1$s"), fmt);
+               break;
+       case Buffer::PreviewError:
+               msg = bformat(_("Error while previewing format: %1$s"), fmt);
+               break;
+       }
+       view->message(msg);
 }
 
 
-void GuiView::processingThreadFinished(bool show_errors)
+#if QT_VERSION >= 0x040400
+
+void GuiView::processingThreadStarted()
 {
-       QFutureWatcher<docstring> const * watcher =
-               static_cast<QFutureWatcher<docstring> const *>(sender());
-       message(watcher->result());
-       updateToolbars();
-       if (show_errors) {
-               BufferView const * const bv = currentBufferView();
-               if (bv && !bv->buffer().errorList("Export").empty()) {
-                       errors("Export");
-                       return;
-               }
-               errors(d.last_export_format);
-       }
 }
 
 
 void GuiView::processingThreadFinished()
 {
-       processingThreadFinished(true);
+       QFutureWatcher<Buffer::ExportStatus> const * watcher =
+               static_cast<QFutureWatcher<Buffer::ExportStatus> const *>(sender());
+
+       Buffer::ExportStatus const status = watcher->result();
+       handleExportStatus(this, status, d.processing_format);
+       
+       updateToolbars();
+       BufferView const * const bv = currentBufferView();
+       if (bv && !bv->buffer().errorList("Export").empty()) {
+               errors("Export");
+               return;
+       }
+       errors(d.last_export_format);
 }
 
 
 void GuiView::autoSaveThreadFinished()
 {
-       processingThreadFinished(false);
+       QFutureWatcher<docstring> const * watcher =
+               static_cast<QFutureWatcher<docstring> const *>(sender());
+       message(watcher->result());
+       updateToolbars();
 }
 
 #else
 
-
 void GuiView::processingThreadStarted()
 {
 }
 
 
-void GuiView::processingThreadFinished(bool)
-{
-}
-
-
 void GuiView::processingThreadFinished()
 {
 }
@@ -801,6 +841,7 @@ void GuiView::showEvent(QShowEvent * e)
                // No work area, switch to the background widget.
                d.setBackground();
 
+       updateToolbars();
        QMainWindow::showEvent(e);
 }
 
@@ -993,6 +1034,9 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa)
 
 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
 {
+       if (d.current_work_area_)
+               QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
+                       this, SLOT(setBusy(bool)));
        disconnectBuffer();
        disconnectBufferView();
        connectBufferView(wa->bufferView());
@@ -1000,6 +1044,7 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
        d.current_work_area_ = wa;
        QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
                this, SLOT(updateWindowTitle(GuiWorkArea *)));
+       QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
        updateWindowTitle(wa);
 
        structureChanged();
@@ -1172,20 +1217,12 @@ void GuiView::setBusy(bool busy)
                // busy state didn't change
                return;
 
-       if (d.current_work_area_) {
-               //Why would we want to stop updates only for one workarea and
-               //not for the others ? This leads to problems as in #7314 (vfr).
-               //d.current_work_area_->setUpdatesEnabled(!busy);
-               if (busy)
-                       d.current_work_area_->stopBlinkingCursor();
-               else
-                       d.current_work_area_->startBlinkingCursor();
-       }
-
-       if (busy)
+       if (busy) {
                QApplication::setOverrideCursor(Qt::WaitCursor);
-       else
-               QApplication::restoreOverrideCursor();
+               return;
+       }
+       QApplication::restoreOverrideCursor();
+       updateLayoutList();     
 }
 
 
@@ -1380,12 +1417,14 @@ void GuiView::updateToolbars()
                        lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true);
                bool const mathmacrotemplate =
                        lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
+               bool const ipa =
+                       lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled();
 
                for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update(math, table, review, mathmacrotemplate);
+                       it->second->update(math, table, review, mathmacrotemplate, ipa);
        } else
                for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update(false, false, false, false);
+                       it->second->update(false, false, false, false, false);
 }
 
 
@@ -1532,10 +1571,10 @@ BufferView const * GuiView::currentBufferView() const
 
 #if (QT_VERSION >= 0x040400)
 docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
-       Buffer const * orig, Buffer * buffer)
+       Buffer const * orig, Buffer * clone)
 {
-       bool const success = buffer->autoSave();
-       delete buffer;
+       bool const success = clone->autoSave();
+       delete clone;
        busyBuffers.remove(orig);
        return success
                ? _("Automatic save done.")
@@ -1558,7 +1597,7 @@ void GuiView::autoSave()
 #if (QT_VERSION >= 0x040400)
        GuiViewPrivate::busyBuffers.insert(buffer);
        QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
-               buffer, buffer->clone());
+               buffer, buffer->cloneBufferOnly());
        d.autosave_watcher_.setFuture(f);
 #else
        buffer->autoSave();
@@ -1656,10 +1695,12 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
        }
 
        case LFUN_BUFFER_WRITE_AS:
+       case LFUN_BUFFER_EXPORT_AS:
                enable = doc_buffer;
                break;
 
        case LFUN_BUFFER_CLOSE:
+       case LFUN_VIEW_CLOSE:
                enable = doc_buffer;
                break;
 
@@ -1677,7 +1718,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_CLOSE_TAB_GROUP:
-               enable = d.currentTabWorkArea();
+               enable = d.tabWorkAreaCount() > 1;
                break;
 
        case LFUN_TOOLBAR_TOGGLE: {
@@ -1734,7 +1775,9 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                else if (name == "latexlog")
                        enable = FileName(doc_buffer->logName()).isReadableFile();
                else if (name == "spellchecker")
-                       enable = theSpellChecker() && !doc_buffer->isReadonly();
+                       enable = theSpellChecker() 
+                               && !doc_buffer->isReadonly()
+                               && !doc_buffer->text().empty();
                else if (name == "vclog")
                        enable = doc_buffer->lyxvc().inUse();
                break;
@@ -1849,6 +1892,11 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
                break;
 
+       case LFUN_FILE_INSERT_PLAINTEXT:
+       case LFUN_FILE_INSERT_PLAINTEXT_PARA:
+               enable = documentBufferView() && documentBufferView()->cursor().inTexted();
+               break;
+
        default:
                return false;
        }
@@ -1994,8 +2042,9 @@ static bool import(GuiView * lv, FileName const & filename,
        string loader_format;
        vector<string> loaders = theConverters().loaders();
        if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
-               for (vector<string>::const_iterator it = loaders.begin();
-                        it != loaders.end(); ++it) {
+               vector<string>::const_iterator it = loaders.begin();
+               vector<string>::const_iterator en = loaders.end();
+               for (; it != en; ++it) {
                        if (!theConverters().isReachable(format, *it))
                                continue;
 
@@ -2066,10 +2115,10 @@ void GuiView::importDocument(string const & argument)
                        toqstr(addPath(package().system_support().absFileName(), "examples")));
 
                docstring filter = formats.prettyName(format);
-               filter += " (*.";
+               filter += " (*.{";
                // FIXME UNICODE
-               filter += from_utf8(formats.extension(format));
-               filter += ')';
+               filter += from_utf8(formats.extensions(format));
+               filter += "})";
 
                FileDialog::Result result =
                        dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
@@ -2210,49 +2259,6 @@ void GuiView::insertLyXFile(docstring const & fname)
 }
 
 
-void GuiView::insertPlaintextFile(docstring const & fname,
-       bool asParagraph)
-{
-       BufferView * bv = documentBufferView();
-       if (!bv)
-               return;
-
-       if (!fname.empty() && !FileName::isAbsolute(to_utf8(fname))) {
-               message(_("Absolute filename expected."));
-               return;
-       }
-
-       // FIXME UNICODE
-       FileName filename(to_utf8(fname));
-
-       if (!filename.empty()) {
-               bv->insertPlaintextFile(filename, asParagraph);
-               return;
-       }
-
-       FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
-               LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
-
-       FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
-               QStringList(qt_("All Files (*)")));
-
-       if (result.first == FileDialog::Later)
-               return;
-
-       // FIXME UNICODE
-       filename.set(fromqstr(result.second));
-
-       // check selected filename
-       if (filename.empty()) {
-               // emit message signal.
-               message(_("Canceled."));
-               return;
-       }
-
-       bv->insertPlaintextFile(filename, asParagraph);
-}
-
-
 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
 {
        FileName fname = b.fileName();
@@ -2292,6 +2298,101 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
                        fname.changeExtension(".lyx");
        }
 
+       // fname is now the new Buffer location.
+
+       // if there is already a Buffer open with this name, we do not want
+       // to have another one. (the second test makes sure we're not just
+       // trying to overwrite ourselves, which is fine.)
+       if (theBufferList().exists(fname) && fname != oldname
+                 && theBufferList().getBuffer(fname) != &b) {
+               docstring const text = 
+                       bformat(_("The file\n%1$s\nis already open in your current session.\n"
+                           "Please close it before attempting to overwrite it.\n"
+                           "Do you want to choose a new filename?"),
+                               from_utf8(fname.absFileName()));
+               int const ret = Alert::prompt(_("Chosen File Already Open"),
+                       text, 0, 1, _("&Rename"), _("&Cancel"));
+               switch (ret) {
+               case 0: return renameBuffer(b, docstring());
+               case 1: return false;
+               }
+               //return false;
+       }
+       
+       if (FileName(fname).exists()) {
+               docstring const file = makeDisplayPath(fname.absFileName(), 30);
+               docstring const text = bformat(_("The document %1$s already "
+                                          "exists.\n\nDo you want to "
+                                          "overwrite that document?"),
+                                        file);
+               int const ret = Alert::prompt(_("Overwrite document?"),
+                       text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
+               switch (ret) {
+               case 0: break;
+               case 1: return renameBuffer(b, docstring());
+               case 2: return false;
+               }
+       }
+
+       bool const saved = saveBuffer(b, fname);
+       if (saved)
+               b.reload(false);
+       return saved;
+}
+
+
+struct PrettyNameComparator
+{
+       bool operator()(Format const *first, Format const *second) const {
+               return compare_ascii_no_case(first->prettyname(), second->prettyname()) <= 0;
+       }
+};
+
+
+bool GuiView::exportBufferAs(Buffer & b)
+{
+       FileName fname = b.fileName();
+
+       FileDialog dlg(qt_("Choose a filename to export the document as"));
+       dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
+
+       QStringList types;
+       types << "Any supported format (*.*)";
+       Formats::const_iterator it = formats.begin();
+       vector<Format const *> export_formats;
+       for (; it != formats.end(); ++it)
+               if (it->documentFormat() && it->inExportMenu())
+                       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() + ")");
+       QString filter;
+       FileDialog::Result result =
+               dlg.save(toqstr(fname.onlyPath().absFileName()),
+                        types,
+                        toqstr(fname.onlyFileName()),
+                        &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")
+               fmt_name = formats.getFormatFromExtension(fname.extension());
+       else
+               fmt_name = formats.getFormatFromPrettyName(fmt_prettyname);
+       LYXERR(Debug::FILES, "fmt_prettyname=" << fmt_prettyname
+              << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
+
+       if (fmt_name.empty() || fname.empty())
+               return false;
+
        // fname is now the new Buffer location.
        if (FileName(fname).exists()) {
                docstring const file = makeDisplayPath(fname.absFileName(), 30);
@@ -2303,12 +2404,15 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
                        text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
                switch (ret) {
                case 0: break;
-               case 1: return renameBuffer(b, docstring());
+               case 1: return exportBufferAs(b);
                case 2: return false;
                }
        }
 
-       return saveBuffer(b, fname);
+       FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName());
+       DispatchResult dr;
+       dispatch(cmd, dr);
+       return dr.dispatched();
 }
 
 
@@ -2367,10 +2471,45 @@ bool GuiView::hideWorkArea(GuiWorkArea * wa)
 }
 
 
+// We only want to close the buffer if it is not visible in other workareas
+// of the same view, nor in other views, and if this is not a child
 bool GuiView::closeWorkArea(GuiWorkArea * wa)
 {
        Buffer & buf = wa->bufferView().buffer();
-       return closeWorkArea(wa, !buf.parent());
+
+       bool last_wa = d.countWorkAreasOf(buf) == 1
+               && !inOtherView(buf) && !buf.parent();
+
+       bool close_buffer = last_wa;
+
+       if (last_wa) {
+               if (lyxrc.close_buffer_with_last_view == "yes")
+                       ; // Nothing to do
+               else if (lyxrc.close_buffer_with_last_view == "no")
+                       close_buffer = false;
+               else {
+                       docstring file;
+                       if (buf.isUnnamed())
+                               file = from_utf8(buf.fileName().onlyFileName());
+                       else
+                               file = buf.fileName().displayName(30);
+                       docstring const text = bformat(
+                               _("Last view on document %1$s is being closed.\n"
+                                 "Would you like to close or hide the document?\n"
+                                 "\n"
+                                 "Hidden documents can be displayed back through\n"
+                                 "the menu: View->Hidden->...\n"
+                                 "\n"
+                                 "To remove this question, set your preference in:\n"
+                                 "  Tools->Preferences->Look&Feel->UserInterface\n"
+                               ), file);
+                       int ret = Alert::prompt(_("Close or hide document?"),
+                               text, 0, 1, _("&Close"), _("&Hide"));
+                       close_buffer = (ret == 0);
+               }
+       }
+
+       return closeWorkArea(wa, close_buffer);
 }
 
 
@@ -2945,71 +3084,61 @@ bool GuiView::goToFileRow(string const & argument)
 
 #if (QT_VERSION >= 0x040400)
 template<class T>
-docstring GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format, string const & msg)
+Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format)
 {
-       bool const update_unincluded =
-                               buffer->params().maintain_unincluded_children
-                               && !buffer->params().getIncludedChildren().empty();
-       bool const success = func(format, update_unincluded);
+       Buffer::ExportStatus const status = func(format);
 
        // the cloning operation will have produced a clone of the entire set of
        // documents, starting from the master. so we must delete those.
-       Buffer * mbuf = const_cast<Buffer *>(buffer->masterBuffer());
+       Buffer * mbuf = const_cast<Buffer *>(clone->masterBuffer());
        delete mbuf;
        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 export to format: %1$s"), from_utf8(format))
-               : bformat(_("Error while exporting format: %1$s"), from_utf8(format));
+       return status;
 }
 
 
-docstring GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
+Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, 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");
+       Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
+       return runAndDestroy(bind(mem_func, clone, _1, true), orig, clone, format);
 }
 
 
-docstring GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
+Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, 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");
+       Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
+       return runAndDestroy(bind(mem_func, clone, _1, false), orig, clone, format);
 }
 
 
-docstring GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
+Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, 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");
+       Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview;
+       return runAndDestroy(bind(mem_func, clone, _1), orig, clone, format);
 }
 
 #else
 
 // not used, but the linker needs them
 
-docstring GuiView::GuiViewPrivate::compileAndDestroy(
+Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(
                Buffer const *, Buffer *, string const &)
 {
-       return docstring();
+       return Buffer::ExportSuccess;
 }
 
 
-docstring GuiView::GuiViewPrivate::exportAndDestroy(
+Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(
                Buffer const *, Buffer *, string const &)
 {
-       return docstring();
+       return Buffer::ExportSuccess;
 }
 
 
-docstring GuiView::GuiViewPrivate::previewAndDestroy(
+Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(
                Buffer const *, Buffer *, string const &)
 {
-       return docstring();
+       return Buffer::ExportSuccess;
 }
 
 #endif
@@ -3019,9 +3148,9 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
                           string const & argument,
                           Buffer const * used_buffer,
                           docstring const & msg,
-                          docstring (*asyncFunc)(Buffer const *, Buffer *, string const &),
-                          bool (Buffer::*syncFunc)(string const &, bool, bool) const,
-                          bool (Buffer::*previewFunc)(string const &, bool) const)
+                          Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
+                          Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
+                          Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
 {
        if (!used_buffer)
                return false;
@@ -3029,17 +3158,23 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
        string format = argument;
        if (format.empty())
                format = used_buffer->params().getDefaultOutputFormat();
-
+       processing_format = format;
 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
        if (!msg.empty()) {
                progress_->clearMessages();
                gv_->message(msg);
        }
        GuiViewPrivate::busyBuffers.insert(used_buffer);
-       QFuture<docstring> f = QtConcurrent::run(
+       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,
-                               used_buffer->clone(),
+                               cloned_buffer,
                                format);
        setPreviewFuture(f);
        last_export_format = used_buffer->params().bufferFormat();
@@ -3048,17 +3183,18 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
        // We are asynchronous, so we don't know here anything about the success
        return true;
 #else
+       Buffer::ExportStatus status;
        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);
+               status = (used_buffer->*syncFunc)(format, true);
        } else if (previewFunc) {
-               return (used_buffer->*previewFunc)(format, false);
-       }
+               status = (used_buffer->*previewFunc)(format); 
+       } else
+               return false;
+       handleExportStatus(gv_, status, format);
        (void) asyncFunc;
-       return false;
+       return (status == Buffer::ExportSuccess 
+                       || status == Buffer::PreviewSuccess);
 #endif
 }
 
@@ -3157,6 +3293,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
                }
 
+               case LFUN_BUFFER_EXPORT_AS:
+                       LASSERT(doc_buffer, break);
+                       exportBufferAs(*doc_buffer);
+                       break;
+
                case LFUN_BUFFER_UPDATE: {
                        d.asyncBufferProcessing(argument,
                                                doc_buffer,
@@ -3266,13 +3407,37 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        insertLyXFile(cmd.argument());
                        break;
 
-               case LFUN_FILE_INSERT_PLAINTEXT_PARA:
-                       insertPlaintextFile(cmd.argument(), true);
-                       break;
-
                case LFUN_FILE_INSERT_PLAINTEXT:
-                       insertPlaintextFile(cmd.argument(), false);
+               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."));
+                               break;
+                       }
+                       
+                       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::Result result = dlg.open(toqstr(bv->buffer().filePath()),
+                                       QStringList(qt_("All Files (*)")));
+                               
+                               if (result.first == FileDialog::Later || result.second.isEmpty()) {
+                                       dr.setMessage(_("Canceled."));
+                                       break;
+                               }
+
+                               filename.set(fromqstr(result.second));
+                       }
+
+                       if (bv) {
+                               FuncRequest const new_cmd(cmd, filename.absoluteFilePath());
+                               bv->dispatch(new_cmd, dr);
+                       }
                        break;
+               }
 
                case LFUN_BUFFER_RELOAD: {
                        LASSERT(doc_buffer, break);
@@ -3453,6 +3618,21 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        }
                        break;
 
+               case LFUN_VIEW_CLOSE:
+                       if (TabWorkArea * twa = d.currentTabWorkArea()) {
+                               closeWorkArea(twa->currentWorkArea());
+                               d.current_work_area_ = 0;
+                               twa = d.currentTabWorkArea();
+                               // Switch to the next GuiWorkArea in the found TabWorkArea.
+                               if (twa) {
+                                       // Make sure the work area is up to date.
+                                       setCurrentWorkArea(twa->currentWorkArea());
+                               } else {
+                                       setCurrentWorkArea(0);
+                               }
+                       }
+                       break;
+
                case LFUN_COMPLETION_INLINE:
                        if (d.current_work_area_)
                                d.current_work_area_->completer().showInline();
@@ -3527,6 +3707,8 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                        doc_buffer->absFileName(),
                                                "tex")).mangledFileName()
                                : doc_buffer->latexName();
+                       string const fulltexname = 
+                               support::makeAbsPath(texname, doc_master->temppath()).absFileName();
                        string const mastername =
                                removeExtension(doc_master->latexName());
                        FileName const dviname(addName(path.absFileName(),
@@ -3547,9 +3729,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                command = lyxrc.forward_search_pdf;
                        }
 
-                       int row = doc_buffer->texrow().getRowFromIdPos(bv->cursor().paragraph().id(), bv->cursor().pos());
+                       DocIterator tmpcur = bv->cursor();
+                       // Leave math first
+                       while (tmpcur.inMathed())
+                               tmpcur.pop_back();
+                       int row = tmpcur.inMathed() ? 0 : doc_buffer->texrow().getRowFromIdPos(
+                                                               tmpcur.paragraph().id(), tmpcur.pos());
                        LYXERR(Debug::ACTION, "Forward search: row:" << row
-                               << " id:" << bv->cursor().paragraph().id());
+                               << " id:" << tmpcur.paragraph().id());
                        if (!row || command.empty()) {
                                dr.setMessage(_("Couldn't proceed."));
                                break;
@@ -3557,6 +3744,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        string texrow = convert<string>(row);
 
                        command = subst(command, "$$n", texrow);
+                       command = subst(command, "$$f", fulltexname);
                        command = subst(command, "$$t", texname);
                        command = subst(command, "$$o", outname);