]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Use <cstdint> instead of <boost/cstdint.hpp>
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 321a1f3a82d6f14cdd6dec3cdc701bb4c5317f2e..6e87f007f93151b27ab99bf45d5fce837529f9a4 100644 (file)
@@ -19,6 +19,7 @@
 #include "FileDialog.h"
 #include "FontLoader.h"
 #include "GuiApplication.h"
+#include "GuiClickableLabel.h"
 #include "GuiCommandBuffer.h"
 #include "GuiCompleter.h"
 #include "GuiKeySymbol.h"
@@ -51,7 +52,9 @@
 #include "FuncStatus.h"
 #include "FuncRequest.h"
 #include "Intl.h"
+#include "Language.h"
 #include "Layout.h"
+#include "LayoutFile.h"
 #include "Lexer.h"
 #include "LyXAction.h"
 #include "LyX.h"
 #include <QMovie>
 #include <QPainter>
 #include <QPixmap>
-#include <QPixmapCache>
 #include <QPoint>
 #include <QPushButton>
 #include <QScrollBar>
@@ -157,6 +159,9 @@ public:
                if (!lyxrc.show_banner)
                        return;
                /// The text to be written on top of the pixmap
+               QString const htext = qt_("The Document\nProcessor[[welcome banner]]");
+               QString const htextsize = qt_("1.0[[possibly scale the welcome banner text size]]");
+               /// The text to be written on top of the pixmap
                QString const text = lyx_version ?
                        qt_("version ") + lyx_version : qt_("unknown version");
 #if QT_VERSION >= 0x050000
@@ -178,7 +183,14 @@ public:
                QPainter pain(&splash_);
                pain.setPen(QColor(0, 0, 0));
                qreal const fsize = fontSize();
-               QPointF const position = textPosition();
+               bool ok;
+               int hfsize = 20;
+               qreal locscale = htextsize.toFloat(&ok);
+               if (!ok)
+                       locscale = 1.0;
+               QPointF const position = textPosition(false);
+               QPointF const hposition = textPosition(true);
+               QRectF const hrect(hposition, splashSize());
                LYXERR(Debug::GUI,
                        "widget pixel ratio: " << pixelRatio() <<
                        " splash pixel ratio: " << splashPixelRatio() <<
@@ -190,6 +202,36 @@ public:
                font.setPointSizeF(fsize);
                pain.setFont(font);
                pain.drawText(position, text);
+               // The font used to display the version info
+               font.setStyleHint(QFont::SansSerif);
+               font.setWeight(QFont::Normal);
+               font.setPointSizeF(hfsize);
+               // Check how long the logo gets with the current font
+               // and adapt if the font is running wider than what
+               // we assume
+               QFontMetrics fm(font);
+               // Split the title into lines to measure the longest line
+               // in the current l7n.
+               QStringList titlesegs = htext.split('\n');
+               int wline = 0;
+               int hline = fm.height();
+               QStringList::const_iterator sit;
+               for (sit = titlesegs.constBegin(); sit != titlesegs.constEnd(); ++sit) {
+                       if (fm.width(*sit) > wline)
+                               wline = fm.width(*sit);
+               }
+               // The longest line in the reference font (for English)
+               // is 180. Calculate scale factor from that.
+               double const wscale = wline > 0 ? (180.0 / wline) : 1;
+               // Now do the same for the height (necessary for condensed fonts)
+               double const hscale = (34.0 / hline);
+               // take the lower of the two scale factors.
+               double const scale = min(wscale, hscale);
+               // Now rescale. Also consider l7n's offset factor.
+               font.setPointSizeF(hfsize * scale * locscale);
+
+               pain.setFont(font);
+               pain.drawText(hrect, Qt::AlignLeft, htext);
                setFocusPolicy(Qt::StrongFocus);
        }
 
@@ -234,11 +276,12 @@ private:
        }
 
        qreal fontSize() const {
-               return toqstr(lyxrc.font_sizes[FONT_SIZE_NORMAL]).toDouble();
+               return toqstr(lyxrc.font_sizes[NORMAL_SIZE]).toDouble();
        }
 
-       QPointF textPosition() const {
-               return QPointF(width_/2 - 18, height_/2 + 45);
+       QPointF textPosition(bool const heading) const {
+               return heading ? QPointF(width_/2 - 18, height_/2 - 45)
+                              : QPointF(width_/2 - 18, height_/2 + 45);
        }
 
        QSize splashSize() const {
@@ -484,13 +527,17 @@ public:
        string processing_format;
 
        static QSet<Buffer const *> busyBuffers;
-       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 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 Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format);
+       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,
@@ -498,7 +545,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 +556,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()));
@@ -562,7 +611,7 @@ GuiView::GuiView(int id)
        setAcceptDrops(true);
 
        // add busy indicator to statusbar
-       QLabel * busylabel = new QLabel(statusBar());
+       GuiClickableLabel * busylabel = new GuiClickableLabel(statusBar());
        statusBar()->addPermanentWidget(busylabel);
        search_mode mode = theGuiApp()->imageSearchMode();
        QString fn = toqstr(lyx::libFileSearch("images", "busy", "gif", mode).absFileName());
@@ -575,6 +624,7 @@ GuiView::GuiView(int id)
                busylabel, SLOT(show()));
        connect(&d.processing_thread_watcher_, SIGNAL(finished()),
                busylabel, SLOT(hide()));
+       connect(busylabel, SIGNAL(clicked()), this, SLOT(checkCancelBackground()));
 
        QFontMetrics const fm(statusBar()->fontMetrics());
        int const iconheight = max(int(d.normalIconSize), fm.height());
@@ -665,6 +715,18 @@ void GuiView::disableShellEscape()
 }
 
 
+void GuiView::checkCancelBackground()
+{
+       docstring const ttl = _("Cancel Export?");
+       docstring const msg = _("Do you want to cancel the background export process?");
+       int const ret =
+               Alert::prompt(ttl, msg, 1, 1,
+                       _("&Cancel export"), _("Co&ntinue"));
+       if (ret == 0)
+               Systemcall::killscript();
+}
+
+
 QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
 {
        QVector<GuiWorkArea*> areas;
@@ -732,7 +794,7 @@ void GuiView::processingThreadFinished()
        bool const error = (status != Buffer::ExportSuccess &&
                            status != Buffer::PreviewSuccess &&
                            status != Buffer::ExportCancel);
-       if (error) {
+       if (error && bv) {
                ErrorList & el = bv->buffer().errorList(d.last_export_format);
                // at this point, we do not know if buffer-view or
                // master-buffer-view was called. If there was an export error,
@@ -1861,6 +1923,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
@@ -1935,6 +2006,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                }
                // fall through
        case LFUN_BUFFER_WRITE_AS:
+       case LFUN_BUFFER_WRITE_AS_TEMPLATE:
                enable = doc_buffer != 0;
                break;
 
@@ -2043,6 +2115,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                if (!doc_buffer)
                        enable = name == "aboutlyx"
                                || name == "file" //FIXME: should be removed.
+                               || name == "lyxfiles"
                                || name == "prefs"
                                || name == "texinfo"
                                || name == "progress"
@@ -2511,7 +2584,8 @@ void GuiView::importDocument(string const & argument)
 }
 
 
-void GuiView::newDocument(string const & filename, bool from_template)
+void GuiView::newDocument(string const & filename, string templatefile,
+                         bool from_template)
 {
        FileName initpath(lyxrc.document_path);
        if (documentBufferView()) {
@@ -2521,9 +2595,9 @@ void GuiView::newDocument(string const & filename, bool from_template)
                        initpath = trypath;
        }
 
-       string templatefile;
        if (from_template) {
-               templatefile = selectTemplateFile().absFileName();
+               if (templatefile.empty())
+                       templatefile =  selectTemplateFile().absFileName();
                if (templatefile.empty())
                        return;
        }
@@ -2545,7 +2619,7 @@ void GuiView::newDocument(string const & filename, bool from_template)
 }
 
 
-void GuiView::insertLyXFile(docstring const & fname)
+void GuiView::insertLyXFile(docstring const & fname, bool ignorelang)
 {
        BufferView * bv = documentBufferView();
        if (!bv)
@@ -2584,34 +2658,116 @@ void GuiView::insertLyXFile(docstring const & fname)
                }
        }
 
-       bv->insertLyXFile(filename);
+       bv->insertLyXFile(filename, ignorelang);
        bv->buffer().errors("Parse");
 }
 
 
+string const GuiView::getTemplatesPath(Buffer & b)
+{
+       // We start off with the user's templates path
+       string result = addPath(package().user_support().absFileName(), "templates");
+       // Check for the document language
+       string const langcode = b.params().language->code();
+       string const shortcode = langcode.substr(0, 2);
+       if (!langcode.empty() && shortcode != "en") {
+               string subpath = addPath(result, shortcode);
+               string subpath_long = addPath(result, langcode);
+               // If we have a subdirectory for the language already,
+               // navigate there
+               FileName sp = FileName(subpath);
+               if (sp.isDirectory())
+                       result = subpath;
+               else if (FileName(subpath_long).isDirectory())
+                       result = subpath_long;
+               else {
+                       // Ask whether we should create such a subdirectory
+                       docstring const text =
+                               bformat(_("It is suggested to save the template in a subdirectory\n"
+                                         "appropriate to the document language (%1$s).\n"
+                                         "This subdirectory does not exists yet.\n"
+                                         "Do you want to create it?"),
+                                       _(b.params().language->display()));
+                       if (Alert::prompt(_("Create Language Directory?"),
+                                         text, 0, 1, _("&Yes, Create"), _("&No, Save Template in Parent Directory")) == 0) {
+                               // If the user agreed, we try to create it and report if this failed.
+                               if (!sp.createDirectory(0777))
+                                       Alert::error(_("Subdirectory creation failed!"),
+                                                    _("Could not create subdirectory.\n"
+                                                      "The template will be saved in the parent directory."));
+                               else
+                                       result = subpath;
+                       }
+               }
+       }
+       // Do we have a layout category?
+       string const cat = b.params().baseClass() ?
+                               b.params().baseClass()->category()
+                             : string();
+       if (!cat.empty()) {
+               string subpath = addPath(result, cat);
+               // If we have a subdirectory for the category already,
+               // navigate there
+               FileName sp = FileName(subpath);
+               if (sp.isDirectory())
+                       result = subpath;
+               else {
+                       // Ask whether we should create such a subdirectory
+                       docstring const text =
+                               bformat(_("It is suggested to save the template in a subdirectory\n"
+                                         "appropriate to the layout category (%1$s).\n"
+                                         "This subdirectory does not exists yet.\n"
+                                         "Do you want to create it?"),
+                                       _(cat));
+                       if (Alert::prompt(_("Create Category Directory?"),
+                                         text, 0, 1, _("&Yes, Create"), _("&No, Save Template in Parent Directory")) == 0) {
+                               // If the user agreed, we try to create it and report if this failed.
+                               if (!sp.createDirectory(0777))
+                                       Alert::error(_("Subdirectory creation failed!"),
+                                                    _("Could not create subdirectory.\n"
+                                                      "The template will be saved in the parent directory."));
+                               else
+                                       result = subpath;
+                       }
+               }
+       }
+       return result;
+}
+
+
 bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kind)
 {
        FileName fname = b.fileName();
        FileName const oldname = fname;
+       bool const as_template = (kind == LV_WRITE_AS_TEMPLATE);
 
        if (!newname.empty()) {
                // FIXME UNICODE
-               fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName());
+               if (as_template)
+                       fname = support::makeAbsPath(to_utf8(newname), getTemplatesPath(b));
+               else
+                       fname = support::makeAbsPath(to_utf8(newname),
+                                                    oldname.onlyPath().absFileName());
        } else {
                // Switch to this Buffer.
                setBuffer(&b);
 
                // No argument? Ask user through dialog.
                // FIXME UNICODE
-               FileDialog dlg(qt_("Choose a filename to save document as"));
+               QString const title = as_template ? qt_("Choose a filename to save template as")
+                                                 : qt_("Choose a filename to save document as");
+               FileDialog dlg(title);
                dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("&Templates"), toqstr(lyxrc.template_path));
 
                if (!isLyXFileName(fname.absFileName()))
                        fname.changeExtension(".lyx");
 
+               string const path = as_template ?
+                                       getTemplatesPath(b)
+                                     : fname.onlyPath().absFileName();
                FileDialog::Result result =
-                       dlg.save(toqstr(fname.onlyPath().absFileName()),
+                       dlg.save(toqstr(path),
                                   QStringList(qt_("LyX Documents (*.lyx)")),
                                         toqstr(fname.onlyFileName()));
 
@@ -2703,6 +2859,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
                break;
        }
        case LV_WRITE_AS:
+       case LV_WRITE_AS_TEMPLATE:
                break;
        }
        // LyXVC created the file already in case of LV_VC_RENAME or
@@ -2988,35 +3145,51 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
 
 bool GuiView::closeBuffer(Buffer & buf)
 {
-       // If we are in a close_event all children will be closed in some time,
-       // so no need to do it here. This will ensure that the children end up
-       // in the session file in the correct order. If we close the master
-       // buffer, we can close or release the child buffers here too.
        bool success = true;
-       if (!closing_) {
-               ListOfBuffers clist = buf.getChildren();
-               ListOfBuffers::const_iterator it = clist.begin();
-               ListOfBuffers::const_iterator const bend = clist.end();
-               for (; it != bend; ++it) {
-                       Buffer * child_buf = *it;
-                       if (theBufferList().isOthersChild(&buf, child_buf)) {
-                               child_buf->setParent(0);
-                               continue;
-                       }
+       ListOfBuffers clist = buf.getChildren();
+       ListOfBuffers::const_iterator it = clist.begin();
+       ListOfBuffers::const_iterator const bend = clist.end();
+       for (; it != bend; ++it) {
+               Buffer * child_buf = *it;
+               if (theBufferList().isOthersChild(&buf, child_buf)) {
+                       child_buf->setParent(0);
+                       continue;
+               }
 
-                       // FIXME: should we look in other tabworkareas?
-                       // ANSWER: I don't think so. I've tested, and if the child is
-                       // open in some other window, it closes without a problem.
-                       GuiWorkArea * child_wa = workArea(*child_buf);
-                       if (child_wa) {
-                               success = closeWorkArea(child_wa, true);
-                               if (!success)
-                                       break;
-                       } else {
-                               // In this case the child buffer is open but hidden.
-                               // It therefore should not (MUST NOT) be dirty!
-                               LATTEST(child_buf->isClean());
+               // FIXME: should we look in other tabworkareas?
+               // ANSWER: I don't think so. I've tested, and if the child is
+               // open in some other window, it closes without a problem.
+               GuiWorkArea * child_wa = workArea(*child_buf);
+               if (child_wa) {
+                       if (closing_)
+                               // If we are in a close_event all children will be closed in some time,
+                               // so no need to do it here. This will ensure that the children end up
+                               // in the session file in the correct order. If we close the master
+                               // buffer, we can close or release the child buffers here too.
+                               continue;
+                       success = closeWorkArea(child_wa, true);
+                       if (!success)
+                               break;
+               } else {
+                       // In this case the child buffer is open but hidden.
+                       // Even in this case, children can be dirty (e.g.,
+                       // after a label change in the master, see #11405).
+                       // Therefore, check this
+                       if (closing_ && (child_buf->isClean() || child_buf->paragraphs().empty()))
+                               // If we are in a close_event all children will be closed in some time,
+                               // so no need to do it here. This will ensure that the children end up
+                               // in the session file in the correct order. If we close the master
+                               // buffer, we can close or release the child buffers here too.
+                               continue;
+                       // Save dirty buffers also if closing_!
+                       if (saveBufferIfNeeded(*child_buf, false)) {
+                               child_buf->removeAutosaveFile();
                                theBufferList().release(child_buf);
+                       } else {
+                               // Saving of dirty children has been cancelled.
+                               // Cancel the whole process.
+                               success = false;
+                               break;
                        }
                }
        }
@@ -3583,7 +3756,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;
@@ -3597,25 +3771,40 @@ 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->cloneWithChildren();
+               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
+       (void) allow_async;
        Buffer::ExportStatus status;
        if (syncFunc) {
                status = (used_buffer->*syncFunc)(format, true);
@@ -3637,15 +3826,21 @@ void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
 
        // Let the current BufferView dispatch its own actions.
        bv->dispatch(cmd, dr);
-       if (dr.dispatched())
+       if (dr.dispatched()) {
+               if (cmd.action() == LFUN_REDO || cmd.action() == LFUN_UNDO)
+                       updateDialog("document", "");
                return;
+       }
 
        // Try with the document BufferView dispatch if any.
        BufferView * doc_bv = documentBufferView();
        if (doc_bv && doc_bv != bv) {
                doc_bv->dispatch(cmd, dr);
-               if (dr.dispatched())
+               if (dr.dispatched()) {
+                       if (cmd.action() == LFUN_REDO || cmd.action() == LFUN_UNDO)
+                               updateDialog("document", "");
                        return;
+               }
        }
 
        // Then let the current Cursor dispatch its own actions.
@@ -3697,11 +3892,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;
                        }
@@ -3728,7 +3931,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Exporting ..."),
                                                &GuiViewPrivate::exportAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        // TODO Inform user about success
                        break;
                }
@@ -3748,7 +3951,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Exporting ..."),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        break;
                }
                case LFUN_BUFFER_VIEW: {
@@ -3757,7 +3960,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: {
@@ -3766,7 +3969,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                docstring(),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               0);
+                                               0, cmd.allowAsync());
                        break;
                }
                case LFUN_MASTER_BUFFER_VIEW: {
@@ -3774,7 +3977,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_EXPORT_CANCEL: {
@@ -3860,9 +4063,13 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                menu->exec(QCursor::pos());
                        break;
 
-               case LFUN_FILE_INSERT:
-                       insertLyXFile(cmd.argument());
+               case LFUN_FILE_INSERT: {
+                       if (cmd.getArg(1) == "ignorelang")
+                               insertLyXFile(from_utf8(cmd.getArg(0)), true);
+                       else
+                               insertLyXFile(cmd.argument());
                        break;
+               }
 
                case LFUN_FILE_INSERT_PLAINTEXT:
                case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
@@ -3897,8 +4104,8 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                case LFUN_BUFFER_RELOAD: {
                        LASSERT(doc_buffer, break);
 
-                       //drop changes?
-                       bool drop = (cmd.argument()=="dump");
+                       // drop changes?
+                       bool drop = (cmd.argument() == "dump");
 
                        int ret = 0;
                        if (!drop && !doc_buffer->isClean()) {
@@ -3939,6 +4146,12 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        renameBuffer(*doc_buffer, cmd.argument());
                        break;
 
+               case LFUN_BUFFER_WRITE_AS_TEMPLATE:
+                       LASSERT(doc_buffer, break);
+                       renameBuffer(*doc_buffer, cmd.argument(),
+                                    LV_WRITE_AS_TEMPLATE);
+                       break;
+
                case LFUN_BUFFER_WRITE_ALL: {
                        Buffer * first = theBufferList().first();
                        if (!first)
@@ -4059,11 +4272,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        string const name = cmd.getArg(0);
                        string sdata = trim(to_utf8(cmd.argument()).substr(name.size()));
 
-                       if (name == "character") {
-                               sdata = freefont2string();
-                               if (!sdata.empty())
-                                       showDialog("character", sdata);
-                       } else if (name == "latexlog") {
+                       if (name == "latexlog") {
                                // gettatus checks that
                                LATTEST(doc_buffer);
                                Buffer::LogType type;
@@ -4211,9 +4420,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        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();
                        dr.screenUpdate(Update::Force | Update::FitCursor);
                        break;
@@ -4451,7 +4657,7 @@ char const * const dialognames[] = {
 "citation", "compare", "comparehistory", "document", "errorlist", "ert",
 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
 "href", "include", "index", "index_print", "info", "listings", "label", "line",
-"log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
+"log", "lyxfiles", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
 "nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
@@ -4541,7 +4747,7 @@ void GuiView::doShowDialog(QString const & qname, QString const & qdata,
                if (dialog) {
                        bool const visible = dialog->isVisibleView();
                        dialog->showData(sdata);
-                       if (inset && currentBufferView())
+                       if (currentBufferView())
                                currentBufferView()->editInset(name, inset);
                        // We only set the focus to the new dialog if it was not yet
                        // visible in order not to change the existing previous behaviour
@@ -4647,6 +4853,7 @@ Dialog * createGuiInclude(GuiView & lv);
 Dialog * createGuiIndex(GuiView & lv);
 Dialog * createGuiListings(GuiView & lv);
 Dialog * createGuiLog(GuiView & lv);
+Dialog * createGuiLyXFiles(GuiView & lv);
 Dialog * createGuiMathMatrix(GuiView & lv);
 Dialog * createGuiNote(GuiView & lv);
 Dialog * createGuiParagraph(GuiView & lv);
@@ -4717,6 +4924,8 @@ Dialog * GuiView::build(string const & name)
                return createGuiListings(*this);
        if (name == "log")
                return createGuiLog(*this);
+       if (name == "lyxfiles")
+               return createGuiLyXFiles(*this);
        if (name == "mathdelimiter")
                return createGuiDelimiter(*this);
        if (name == "mathmatrix")