]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiDocument.cpp
Use QFontMetrics information for underlines (and friends) width and position
[lyx.git] / src / frontends / qt4 / GuiDocument.cpp
index 1ac9259586779bc75e5722bd1b313b3692ea5b46..96ea215f080634a66967b5c416689f7dec49d9de 100644 (file)
@@ -31,6 +31,7 @@
 #include "BufferView.h"
 #include "Color.h"
 #include "ColorCache.h"
+#include "Cursor.h"
 #include "Encoding.h"
 #include "FloatPlacement.h"
 #include "Format.h"
@@ -50,6 +51,8 @@
 #include "qt_helpers.h"
 #include "Spacing.h"
 #include "TextClass.h"
+#include "Undo.h"
+#include "VSpace.h"
 
 #include "insets/InsetListingsParams.h"
 
@@ -628,7 +631,8 @@ void LocalLayout::validatePressed() {
 
 
 GuiDocument::GuiDocument(GuiView & lv)
-       : GuiDialog(lv, "document", qt_("Document Settings"))
+       : GuiDialog(lv, "document", qt_("Document Settings")),
+         nonModuleChanged_(false)
 {
        setupUi(this);
 
@@ -1155,7 +1159,7 @@ GuiDocument::GuiDocument(GuiView & lv)
        headers << qt_("Package") << qt_("Load automatically")
                << qt_("Load always") << qt_("Do not load");
        mathsModule->packagesTW->setHorizontalHeaderLabels(headers);
-       setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch);        
+       setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch);
        map<string, string> const & packages = BufferParams::auto_packages();
        mathsModule->packagesTW->setRowCount(packages.size());
        int i = 0;
@@ -1226,7 +1230,7 @@ GuiDocument::GuiDocument(GuiView & lv)
        connect(latexModule->psdriverCO, SIGNAL(activated(int)),
                this, SLOT(change_adaptor()));
        connect(latexModule->classCO, SIGNAL(activated(int)),
-               this, SLOT(classChanged()));
+               this, SLOT(classChanged_adaptor()));
        connect(latexModule->classCO, SIGNAL(activated(int)),
                this, SLOT(change_adaptor()));
        connect(latexModule->layoutPB, SIGNAL(clicked()),
@@ -1321,8 +1325,6 @@ GuiDocument::GuiDocument(GuiView & lv)
                        availableModel(), selectedModel(), this);
        connect(selectionManager, SIGNAL(updateHook()),
                this, SLOT(updateModuleInfo()));
-       connect(selectionManager, SIGNAL(updateHook()),
-               this, SLOT(change_adaptor()));
        connect(selectionManager, SIGNAL(selectionChanged()),
                this, SLOT(modulesChanged()));
 
@@ -1442,6 +1444,7 @@ void GuiDocument::useDefaultsClicked()
 
 void GuiDocument::change_adaptor()
 {
+       nonModuleChanged_ = true;
        changed();
 }
 
@@ -1462,7 +1465,7 @@ void GuiDocument::includeonlyClicked(QTreeWidgetItem * item, int)
                includeonlys_.push_back(child);
 
        updateIncludeonlys();
-       changed();
+       change_adaptor();
 }
 
 
@@ -1470,6 +1473,7 @@ QString GuiDocument::validateListingsParameters()
 {
        // use a cache here to avoid repeated validation
        // of the same parameters
+       // FIXME THREAD
        static string param_cache;
        static QString msg_cache;
 
@@ -1487,6 +1491,7 @@ QString GuiDocument::validateListingsParameters()
 
 void GuiDocument::setListingsMessage()
 {
+       // FIXME THREAD
        static bool isOK = true;
        QString msg = validateListingsParameters();
        if (msg.isEmpty()) {
@@ -1496,7 +1501,7 @@ void GuiDocument::setListingsMessage()
                // listingsTB->setTextColor("black");
                listingsModule->listingsTB->setPlainText(
                        qt_("Input listings parameters below. "
-                "Enter ? for a list of parameters."));
+                           "Enter ? for a list of parameters."));
        } else {
                isOK = false;
                // listingsTB->setTextColor("red");
@@ -1639,7 +1644,7 @@ void GuiDocument::changeBackgroundColor()
        // save color
        set_backgroundcolor = rgbFromHexName(fromqstr(newColor.name()));
        is_backgroundcolor = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1652,7 +1657,7 @@ void GuiDocument::deleteBackgroundColor()
        // save default color (white)
        set_backgroundcolor = rgbFromHexName("#ffffff");
        is_backgroundcolor = false;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1669,7 +1674,7 @@ void GuiDocument::changeFontColor()
        // save color
        set_fontcolor = rgbFromHexName(fromqstr(newColor.name()));
        is_fontcolor = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1682,7 +1687,7 @@ void GuiDocument::deleteFontColor()
        // save default color (black)
        set_fontcolor = rgbFromHexName("#000000");
        is_fontcolor = false;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1697,7 +1702,7 @@ void GuiDocument::changeNoteFontColor()
                colorButtonStyleSheet(newColor));
        // save color
        set_notefontcolor = rgbFromHexName(fromqstr(newColor.name()));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1707,7 +1712,7 @@ void GuiDocument::deleteNoteFontColor()
        theApp()->getRgbColor(Color_greyedouttext, set_notefontcolor);
        colorModule->noteFontColorPB->setStyleSheet(
                colorButtonStyleSheet(rgb2qcolor(set_notefontcolor)));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1722,7 +1727,7 @@ void GuiDocument::changeBoxBackgroundColor()
                colorButtonStyleSheet(newColor));
        // save color
        set_boxbgcolor = rgbFromHexName(fromqstr(newColor.name()));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1732,7 +1737,7 @@ void GuiDocument::deleteBoxBackgroundColor()
        theApp()->getRgbColor(Color_shadedbg, set_boxbgcolor);
        colorModule->boxBackgroundPB->setStyleSheet(
                colorButtonStyleSheet(rgb2qcolor(set_boxbgcolor)));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1798,7 +1803,7 @@ void GuiDocument::osFontsChanged(bool nontexfonts)
        if (!tex_fonts)
                fontModule->fontencLE->setEnabled(false);
        else
-               fontencChanged(fontModule->fontencCO->currentIndex()); 
+               fontencChanged(fontModule->fontencCO->currentIndex());
 }
 
 
@@ -1964,14 +1969,14 @@ void GuiDocument::updateFontlist()
                fontModule->fontsRomanCO->addItem(rmi.key(), rmi.value());
                ++rmi;
        }
-       
+
        fontModule->fontsSansCO->addItem(qt_("Default"), QString("default"));
        QMap<QString, QString>::const_iterator sfi = sffonts_.constBegin();
        while (sfi != sffonts_.constEnd()) {
                fontModule->fontsSansCO->addItem(sfi.key(), sfi.value());
                ++sfi;
        }
-       
+
        fontModule->fontsTypewriterCO->addItem(qt_("Default"), QString("default"));
        QMap<QString, QString>::const_iterator tti = ttfonts_.constBegin();
        while (tti != ttfonts_.constEnd()) {
@@ -2099,9 +2104,9 @@ void GuiDocument::browseLayout()
 
        int const ret = Alert::prompt(_("Local layout file"),
                _("The layout file you have selected is a local layout\n"
-                 "file, not one in the system or user directory. Your\n"
-                 "document may not work with this layout if you do not\n"
-                 "keep the layout file in the document directory."),
+                 "file, not one in the system or user directory.\n"
+                 "Your document will not work with this layout if you\n"
+                 "move the layout file to a different directory."),
                  1, 1, _("&Set Layout"), _("&Cancel"));
        if (ret == 1)
                return;
@@ -2110,9 +2115,9 @@ void GuiDocument::browseLayout()
        LayoutFileList & bcl = LayoutFileList::get();
        string classname = layoutFile.onlyFileName();
        // this will update an existing layout if that layout has been loaded before.
-       LayoutFileIndex name = bcl.addLocalLayout(
+       LayoutFileIndex name = support::onlyFileName(bcl.addLocalLayout(
                classname.substr(0, classname.size() - 7),
-               layoutFile.onlyPath().absFileName());
+               layoutFile.onlyPath().absFileName()));
 
        if (name.empty()) {
                Alert::error(_("Error"),
@@ -2120,6 +2125,8 @@ void GuiDocument::browseLayout()
                return;
        }
 
+       const_cast<Buffer &>(buffer()).setLayoutPos(layoutFile.onlyPath().absFileName());
+
        // do not trigger classChanged if there is no change.
        if (latexModule->classCO->currentText() == toqstr(name))
                return;
@@ -2158,6 +2165,13 @@ void GuiDocument::browseMaster()
 }
 
 
+void GuiDocument::classChanged_adaptor()
+{
+       const_cast<Buffer &>(buffer()).setLayoutPos(string());
+       classChanged();
+}
+
+
 void GuiDocument::classChanged()
 {
        int idx = latexModule->classCO->currentIndex();
@@ -2165,30 +2179,13 @@ void GuiDocument::classChanged()
                return;
        string const classname = fromqstr(latexModule->classCO->getData(idx));
 
-       // check whether the selected modules have changed.
-       bool modules_changed = false;
-       unsigned int const srows = selectedModel()->rowCount();
-       if (srows != bp_.getModules().size())
-               modules_changed = true;
-       else {
-               list<string>::const_iterator mit = bp_.getModules().begin();
-               list<string>::const_iterator men = bp_.getModules().end();
-               for (unsigned int i = 0; i < srows && mit != men; ++i, ++mit)
-                       if (selectedModel()->getIDString(i) != *mit) {
-                               modules_changed = true;
-                               break;
-                       }
-       }
-
-       if (modules_changed || lyxrc.auto_reset_options) {
-               if (applyPB->isEnabled()) {
-                       int const ret = Alert::prompt(_("Unapplied changes"),
-                                       _("Some changes in the dialog were not yet applied.\n"
-                                       "If you do not apply now, they will be lost after this action."),
-                                       1, 1, _("&Apply"), _("&Dismiss"));
-                       if (ret == 0)
-                               applyView();
-               }
+       if (applyPB->isEnabled()) {
+               int const ret = Alert::prompt(_("Unapplied changes"),
+                               _("Some changes in the dialog were not yet applied.\n"
+                               "If you do not apply now, they will be lost after this action."),
+                               1, 1, _("&Apply"), _("&Dismiss"));
+               if (ret == 0)
+                       applyView();
        }
 
        // We load the TextClass as soon as it is selected. This is
@@ -2224,7 +2221,7 @@ void GuiDocument::languagePackageChanged(int i)
 void GuiDocument::biblioChanged()
 {
        biblioChanged_ = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -2374,8 +2371,19 @@ void GuiDocument::modulesToParams(BufferParams & bp)
 void GuiDocument::modulesChanged()
 {
        modulesToParams(bp_);
+
+       if (applyPB->isEnabled() && nonModuleChanged_) {
+               int const ret = Alert::prompt(_("Unapplied changes"),
+                               _("Some changes in the dialog were not yet applied.\n"
+                               "If you do not apply now, they will be lost after this action."),
+                               1, 1, _("&Apply"), _("&Dismiss"));
+               if (ret == 0)
+                       applyView();
+       }
+
        bp_.makeDocumentClass();
        paramsToDialog();
+       changed();
 }
 
 
@@ -2598,9 +2606,16 @@ void GuiDocument::applyView()
        bp_.quotes_language = (InsetQuotes::QuoteLanguage) langModule->quoteStyleCO->itemData(
                langModule->quoteStyleCO->currentIndex()).toInt();
 
-       QString const lang = langModule->languageCO->itemData(
+       QString const langname = langModule->languageCO->itemData(
                langModule->languageCO->currentIndex()).toString();
-       bp_.language = lyx::languages.getLanguage(fromqstr(lang));
+       Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
+       Cursor & cur = const_cast<BufferView *>(bufferview())->cursor();
+       // If current cursor language was the document language, then update it too.
+       if (cur.current_font.language() == bp_.language) {
+               cur.current_font.setLanguage(newlang);
+               cur.real_current_font.setLanguage(newlang);
+       }
+       bp_.language = newlang;
 
        QString const pack = langModule->languagePackageCO->itemData(
                langModule->languagePackageCO->currentIndex()).toString();
@@ -2793,7 +2808,7 @@ void GuiDocument::applyView()
        bp_.useNonTeXFonts = nontexfonts;
 
        bp_.output_sync = outputModule->outputsyncCB->isChecked();
-       
+
        bp_.output_sync_macro = fromqstr(outputModule->synccustomCB->currentText());
 
        int mathfmt = outputModule->mathoutCB->currentIndex();
@@ -2805,6 +2820,7 @@ void GuiDocument::applyView()
        bp_.html_be_strict = outputModule->strictCB->isChecked();
        bp_.html_css_as_file = outputModule->cssCB->isChecked();
        bp_.html_math_img_scale = outputModule->mathimgSB->value();
+       bp_.display_pixel_ratio = theGuiApp()->pixelRatio();
 
        // fonts
        bp_.fonts_roman =
@@ -2915,6 +2931,9 @@ void GuiDocument::applyView()
                pdf.pagemode.clear();
        pdf.quoted_options = pdf.quoted_options_check(
                                fromqstr(pdfSupportModule->optionsLE->text()));
+
+       // reset tracker
+       nonModuleChanged_ = false;
 }
 
 
@@ -2975,7 +2994,7 @@ void GuiDocument::paramsToDialog()
        biblioChanged_ = false;
 
        // indices
-       indicesModule->update(bp_);
+       indicesModule->update(bp_, buffer().isReadonly());
 
        // language & quotes
        int const pos = langModule->languageCO->findData(toqstr(
@@ -3434,6 +3453,9 @@ void GuiDocument::paramsToDialog()
 
        // clear changed branches cache
        changedBranches_.clear();
+
+       // reset tracker
+       nonModuleChanged_ = false;
 }
 
 
@@ -3667,11 +3689,11 @@ DocumentClass const & GuiDocument::documentClass() const
 
 
 static void dispatch_bufferparams(Dialog const & dialog,
-       BufferParams const & bp, FuncCode lfun)
+       BufferParams const & bp, FuncCode lfun, Buffer const * buf)
 {
        ostringstream ss;
        ss << "\\begin_header\n";
-       bp.writeFile(ss);
+       bp.writeFile(ss, buf);
        ss << "\\end_header\n";
        dialog.dispatch(FuncRequest(lfun, ss.str()));
 }
@@ -3679,12 +3701,17 @@ static void dispatch_bufferparams(Dialog const & dialog,
 
 void GuiDocument::dispatchParams()
 {
+       // We need a non-const buffer object.
+       Buffer & buf = const_cast<BufferView *>(bufferview())->buffer();
+       // There may be several undo records; group them (bug #8998)
+       buf.undo().beginUndoGroup();
+
        // This must come first so that a language change is correctly noticed
        setLanguage();
 
        // Apply the BufferParams. Note that this will set the base class
        // and then update the buffer's layout.
-       dispatch_bufferparams(*this, params(), LFUN_BUFFER_PARAMS_APPLY);
+       dispatch_bufferparams(*this, params(), LFUN_BUFFER_PARAMS_APPLY, &buffer());
 
        if (!params().master.empty()) {
                FileName const master_file = support::makeAbsPath(params().master,
@@ -3748,6 +3775,10 @@ void GuiDocument::dispatchParams()
        // If we used an LFUN, we would not need these two lines:
        BufferView * bv = const_cast<BufferView *>(bufferview());
        bv->processUpdateFlags(Update::Force | Update::FitCursor);
+
+       // Don't forget to close the group. Note that it is important
+       // to check that there is no early return in the method.
+       buf.undo().endUndoGroup();
 }
 
 
@@ -3764,7 +3795,7 @@ void GuiDocument::setLanguage() const
 
 void GuiDocument::saveAsDefault() const
 {
-       dispatch_bufferparams(*this, params(), LFUN_BUFFER_SAVE_AS_DEFAULT);
+       dispatch_bufferparams(*this, params(), LFUN_BUFFER_SAVE_AS_DEFAULT, &buffer());
 }