]> 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 1017d5d8f148b9a5fb8e5140628d6c9594aa9373..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"
 
@@ -130,48 +133,6 @@ char const * backref_opts_gui[] =
 };
 
 
-char const * packages_gui[][4] =
-{
-       {"amsmath",
-        N_("&Use amsmath package automatically"),
-        N_("Use ams&math package"),
-        N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas")},
-       {"amssymb",
-        N_("&Use amssymb package automatically"),
-        N_("Use amssymb package"),
-        N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas")},
-       {"esint",
-        N_("Use esint package &automatically"),
-        N_("Use &esint package"),
-        N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas")},
-       {"mathdots",
-        N_("Use math&dots package automatically"),
-        N_("Use mathdo&ts package"),
-        N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas")},
-       {"mathtools",
-        N_("Use mathtools package automatically"),
-        N_("Use mathtools package"),
-        N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas")},
-       {"mhchem",
-        N_("Use mhchem &package automatically"),
-        N_("Use mh&chem package"),
-        N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas")},
-       {"stackrel",
-        N_("Use stackrel package automatically"),
-        N_("Use stackrel package"),
-        N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas")},
-       {"stmaryrd",
-        N_("Use stmaryrd package automatically"),
-        N_("Use stmaryrd package"),
-        N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas")},
-       {"undertilde",
-        N_("Use u&ndertilde package automatically"),
-        N_("Use undertilde pac&kage"),
-        N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'")},
-       {"", "", "", ""}
-};
-
-
 vector<string> engine_types_;
 vector<pair<string, QString> > pagestyles;
 
@@ -191,6 +152,7 @@ RGBColor set_fontcolor;
 bool is_fontcolor;
 RGBColor set_notefontcolor;
 RGBColor set_boxbgcolor;
+bool forced_fontspec_activation;
 
 namespace {
 // used when sorting the textclass list.
@@ -559,7 +521,7 @@ LocalLayout::LocalLayout() : current_id_(0), validated_(false)
 
 void LocalLayout::update(BufferParams const & params, BufferId id)
 {
-       QString layout = toqstr(params.local_layout);
+       QString layout = toqstr(params.getLocalLayout(false));
        // Nothing to do if the params and preamble are unchanged.
        if (id == current_id_
                && layout == locallayoutTE->document()->toPlainText())
@@ -575,7 +537,7 @@ void LocalLayout::update(BufferParams const & params, BufferId id)
 void LocalLayout::apply(BufferParams & params)
 {
        string const layout = fromqstr(locallayoutTE->document()->toPlainText());
-       params.local_layout = layout;
+       params.setLocalLayout(layout, false);
 }
 
 
@@ -669,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);
 
@@ -1191,49 +1154,71 @@ GuiDocument::GuiDocument(GuiView & lv)
 
 
        // maths
-       // FIXME This UI has problems:
-       //       1) It is not generic, packages_gui needs to be changed for each new package
-       //       2) Two checkboxes have 4 states, but one is invalid (both pressed)
-       //       3) The auto cb is not disabled if the use cb is checked
        mathsModule = new UiWidget<Ui::MathsUi>;
-       vector<string> const & packages = BufferParams::auto_packages();
-        for (size_t i = 0; i < packages.size(); ++i) {
-               // Use the order of BufferParams::auto_packages() for easier
-               // access in applyView() and paramsToDialog()
-               int n = 0;
-               for (n = 0; packages_gui[n][0][0]; n++)
-                       if (packages_gui[n][0] == packages[i])
-                               break;
-               // If this fires somebody changed
-               // BufferParams::auto_packages() without adjusting packages_gui
-               LASSERT(packages_gui[n][0][0], /**/);
-               QString autoText = qt_(packages_gui[n][1]);
-               QString alwaysText = qt_(packages_gui[n][2]);
-               QString autoTooltip = qt_(packages_gui[n][3]);
+       QStringList headers;
+       headers << qt_("Package") << qt_("Load automatically")
+               << qt_("Load always") << qt_("Do not load");
+       mathsModule->packagesTW->setHorizontalHeaderLabels(headers);
+       setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch);
+       map<string, string> const & packages = BufferParams::auto_packages();
+       mathsModule->packagesTW->setRowCount(packages.size());
+       int i = 0;
+       for (map<string, string>::const_iterator it = packages.begin();
+            it != packages.end(); ++it) {
+               docstring const package = from_ascii(it->first);
+               QString autoTooltip = qt_(it->second);
                QString alwaysTooltip;
-               if (packages[i] == "amsmath")
+               if (package == "amsmath")
                        alwaysTooltip =
                                qt_("The AMS LaTeX packages are always used");
                else
                        alwaysTooltip = toqstr(bformat(
                                _("The LaTeX package %1$s is always used"),
-                               from_ascii(packages[i])));
-               QCheckBox * autoCB = new QCheckBox(autoText, mathsModule);
-               QCheckBox * alwaysCB = new QCheckBox(alwaysText, mathsModule);
-               mathsModule->gridLayout->addWidget(autoCB, 2 * i, 0);
-               mathsModule->gridLayout->addWidget(alwaysCB, 2 * i + 1, 0);
-               autoCB->setToolTip(autoTooltip);
-               alwaysCB->setToolTip(alwaysTooltip);
-               connect(autoCB, SIGNAL(toggled(bool)),
-                       alwaysCB, SLOT(setDisabled(bool)));
-               connect(autoCB, SIGNAL(clicked()),
+                               package));
+               QString neverTooltip;
+               if (package == "amsmath")
+                       neverTooltip =
+                               qt_("The AMS LaTeX packages are never used");
+               else
+                       neverTooltip = toqstr(bformat(
+                               _("The LaTeX package %1$s is never used"),
+                               package));
+               QRadioButton * autoRB = new QRadioButton(mathsModule);
+               QRadioButton * alwaysRB = new QRadioButton(mathsModule);
+               QRadioButton * neverRB = new QRadioButton(mathsModule);
+               QButtonGroup * packageGroup = new QButtonGroup(mathsModule);
+               packageGroup->addButton(autoRB);
+               packageGroup->addButton(alwaysRB);
+               packageGroup->addButton(neverRB);
+               autoRB->setToolTip(autoTooltip);
+               alwaysRB->setToolTip(alwaysTooltip);
+               neverRB->setToolTip(neverTooltip);
+               QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package));
+               mathsModule->packagesTW->setItem(i, 0, pack);
+               mathsModule->packagesTW->setCellWidget(i, 1, autoRB);
+               mathsModule->packagesTW->setCellWidget(i, 2, alwaysRB);
+               mathsModule->packagesTW->setCellWidget(i, 3, neverRB);
+
+               connect(autoRB, SIGNAL(clicked()),
+                       this, SLOT(change_adaptor()));
+               connect(alwaysRB, SIGNAL(clicked()),
                        this, SLOT(change_adaptor()));
-               connect(alwaysCB, SIGNAL(clicked()),
+               connect(neverRB, SIGNAL(clicked()),
                        this, SLOT(change_adaptor()));
+               ++i;
        }
-       QSpacerItem * spacer = new QSpacerItem(20, 20, QSizePolicy::Minimum,
-                                              QSizePolicy::Expanding);
-       mathsModule->gridLayout->addItem(spacer, 2 * packages.size(), 0);
+       connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()),
+               this, SLOT(allPackagesAuto()));
+       connect(mathsModule->allPackagesAlwaysPB, SIGNAL(clicked()),
+               this, SLOT(allPackagesAlways()));
+       connect(mathsModule->allPackagesNotPB, SIGNAL(clicked()),
+               this, SLOT(allPackagesNot()));
+       connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
+       connect(mathsModule->allPackagesAlwaysPB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
+       connect(mathsModule->allPackagesNotPB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
 
 
        // latex class
@@ -1245,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()),
@@ -1340,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()));
 
@@ -1417,28 +1400,28 @@ GuiDocument::GuiDocument(GuiView & lv)
 
 
        // add the panels
-       docPS->addPanel(latexModule, qt_("Document Class"));
-       docPS->addPanel(masterChildModule, qt_("Child Documents"));
-       docPS->addPanel(modulesModule, qt_("Modules"));
-       docPS->addPanel(localLayout, qt_("Local Layout"));
-       docPS->addPanel(fontModule, qt_("Fonts"));
-       docPS->addPanel(textLayoutModule, qt_("Text Layout"));
-       docPS->addPanel(pageLayoutModule, qt_("Page Layout"));
-       docPS->addPanel(marginsModule, qt_("Page Margins"));
-       docPS->addPanel(langModule, qt_("Language"));
-       docPS->addPanel(colorModule, qt_("Colors"));
-       docPS->addPanel(numberingModule, qt_("Numbering & TOC"));
-       docPS->addPanel(biblioModule, qt_("Bibliography"));
-       docPS->addPanel(indicesModule, qt_("Indexes"));
-       docPS->addPanel(pdfSupportModule, qt_("PDF Properties"));
-       docPS->addPanel(mathsModule, qt_("Math Options"));
-       docPS->addPanel(floatModule, qt_("Float Placement"));
-       docPS->addPanel(listingsModule, qt_("Listings[[inset]]"));
-       docPS->addPanel(bulletsModule, qt_("Bullets"));
-       docPS->addPanel(branchesModule, qt_("Branches"));
-       docPS->addPanel(outputModule, qt_("Output"));
-       docPS->addPanel(preambleModule, qt_("LaTeX Preamble"));
-       docPS->setCurrentPanel(qt_("Document Class"));
+       docPS->addPanel(latexModule, N_("Document Class"));
+       docPS->addPanel(masterChildModule, N_("Child Documents"));
+       docPS->addPanel(modulesModule, N_("Modules"));
+       docPS->addPanel(localLayout, N_("Local Layout"));
+       docPS->addPanel(fontModule, N_("Fonts"));
+       docPS->addPanel(textLayoutModule, N_("Text Layout"));
+       docPS->addPanel(pageLayoutModule, N_("Page Layout"));
+       docPS->addPanel(marginsModule, N_("Page Margins"));
+       docPS->addPanel(langModule, N_("Language"));
+       docPS->addPanel(colorModule, N_("Colors"));
+       docPS->addPanel(numberingModule, N_("Numbering & TOC"));
+       docPS->addPanel(biblioModule, N_("Bibliography"));
+       docPS->addPanel(indicesModule, N_("Indexes"));
+       docPS->addPanel(pdfSupportModule, N_("PDF Properties"));
+       docPS->addPanel(mathsModule, N_("Math Options"));
+       docPS->addPanel(floatModule, N_("Float Placement"));
+       docPS->addPanel(listingsModule, N_("Listings[[inset]]"));
+       docPS->addPanel(bulletsModule, N_("Bullets"));
+       docPS->addPanel(branchesModule, N_("Branches"));
+       docPS->addPanel(outputModule, N_("Output"));
+       docPS->addPanel(preambleModule, N_("LaTeX Preamble"));
+       docPS->setCurrentPanel("Document Class");
 // FIXME: hack to work around resizing bug in Qt >= 4.2
 // bug verified with Qt 4.2.{0-3} (JSpitzm)
 #if QT_VERSION >= 0x040200
@@ -1461,6 +1444,7 @@ void GuiDocument::useDefaultsClicked()
 
 void GuiDocument::change_adaptor()
 {
+       nonModuleChanged_ = true;
        changed();
 }
 
@@ -1481,7 +1465,7 @@ void GuiDocument::includeonlyClicked(QTreeWidgetItem * item, int)
                includeonlys_.push_back(child);
 
        updateIncludeonlys();
-       changed();
+       change_adaptor();
 }
 
 
@@ -1489,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;
 
@@ -1506,6 +1491,7 @@ QString GuiDocument::validateListingsParameters()
 
 void GuiDocument::setListingsMessage()
 {
+       // FIXME THREAD
        static bool isOK = true;
        QString msg = validateListingsParameters();
        if (msg.isEmpty()) {
@@ -1515,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");
@@ -1658,7 +1644,7 @@ void GuiDocument::changeBackgroundColor()
        // save color
        set_backgroundcolor = rgbFromHexName(fromqstr(newColor.name()));
        is_backgroundcolor = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1671,7 +1657,7 @@ void GuiDocument::deleteBackgroundColor()
        // save default color (white)
        set_backgroundcolor = rgbFromHexName("#ffffff");
        is_backgroundcolor = false;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1688,7 +1674,7 @@ void GuiDocument::changeFontColor()
        // save color
        set_fontcolor = rgbFromHexName(fromqstr(newColor.name()));
        is_fontcolor = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1701,7 +1687,7 @@ void GuiDocument::deleteFontColor()
        // save default color (black)
        set_fontcolor = rgbFromHexName("#000000");
        is_fontcolor = false;
-       changed();
+       change_adaptor();
 }
 
 
@@ -1716,7 +1702,7 @@ void GuiDocument::changeNoteFontColor()
                colorButtonStyleSheet(newColor));
        // save color
        set_notefontcolor = rgbFromHexName(fromqstr(newColor.name()));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1726,7 +1712,7 @@ void GuiDocument::deleteNoteFontColor()
        theApp()->getRgbColor(Color_greyedouttext, set_notefontcolor);
        colorModule->noteFontColorPB->setStyleSheet(
                colorButtonStyleSheet(rgb2qcolor(set_notefontcolor)));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1741,7 +1727,7 @@ void GuiDocument::changeBoxBackgroundColor()
                colorButtonStyleSheet(newColor));
        // save color
        set_boxbgcolor = rgbFromHexName(fromqstr(newColor.name()));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1751,7 +1737,7 @@ void GuiDocument::deleteBoxBackgroundColor()
        theApp()->getRgbColor(Color_shadedbg, set_boxbgcolor);
        colorModule->boxBackgroundPB->setStyleSheet(
                colorButtonStyleSheet(rgb2qcolor(set_boxbgcolor)));
-       changed();
+       change_adaptor();
 }
 
 
@@ -1761,11 +1747,22 @@ void GuiDocument::languageChanged(int i)
        Language const * lang = lyx::languages.getLanguage(
                fromqstr(langModule->languageCO->itemData(i).toString()));
        if (lang->babel().empty() && !lang->polyglossia().empty()) {
+                       // If we force to switch fontspec on, store
+                       // current state (#8717)
+                       if (fontModule->osFontsCB->isEnabled())
+                               forced_fontspec_activation =
+                                       !fontModule->osFontsCB->isChecked();
                        fontModule->osFontsCB->setChecked(true);
                        fontModule->osFontsCB->setEnabled(false);
        }
-       else
+       else {
                fontModule->osFontsCB->setEnabled(true);
+               // If we have forced to switch fontspec on,
+               // restore previous state (#8717)
+               if (forced_fontspec_activation)
+                       fontModule->osFontsCB->setChecked(false);
+               forced_fontspec_activation = false;
+       }
 
        // set appropriate quotation mark style
        if (!lang->quoteStyle().empty()) {
@@ -1806,7 +1803,7 @@ void GuiDocument::osFontsChanged(bool nontexfonts)
        if (!tex_fonts)
                fontModule->fontencLE->setEnabled(false);
        else
-               fontencChanged(fontModule->fontencCO->currentIndex()); 
+               fontencChanged(fontModule->fontencCO->currentIndex());
 }
 
 
@@ -1942,7 +1939,7 @@ void GuiDocument::updateFontlist()
        fontModule->fontsTypewriterCO->clear();
        fontModule->fontsMathCO->clear();
 
-       // With XeTeX, we have access to all system fonts, but not the LaTeX fonts
+       // With fontspec (XeTeX, LuaTeX), we have access to all system fonts, but not the LaTeX fonts
        if (fontModule->osFontsCB->isChecked()) {
                fontModule->fontsRomanCO->addItem(qt_("Default"), QString("default"));
                fontModule->fontsSansCO->addItem(qt_("Default"), QString("default"));
@@ -1972,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()) {
@@ -2107,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;
@@ -2118,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"),
@@ -2128,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;
@@ -2166,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();
@@ -2173,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
@@ -2232,7 +2221,7 @@ void GuiDocument::languagePackageChanged(int i)
 void GuiDocument::biblioChanged()
 {
        biblioChanged_ = true;
-       changed();
+       change_adaptor();
 }
 
 
@@ -2277,6 +2266,7 @@ void GuiDocument::updateEngineType(string const & items, CiteEngineType const &
                        biblioModule->citeStyleCO->setCurrentIndex(0);
                        break;
                case ENGINE_TYPE_NUMERICAL:
+               case ENGINE_TYPE_DEFAULT:
                        biblioModule->citeStyleCO->setCurrentIndex(1);
                        break;
        }
@@ -2381,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();
 }
 
 
@@ -2498,7 +2499,7 @@ void GuiDocument::updateDefaultFormat()
        if (idx >= 0) {
                string const classname = fromqstr(latexModule->classCO->getData(idx));
                param_copy.setBaseClass(classname);
-               param_copy.makeDocumentClass();
+               param_copy.makeDocumentClass(true);
        }
        outputModule->defaultFormatCO->blockSignals(true);
        outputModule->defaultFormatCO->clear();
@@ -2506,6 +2507,7 @@ void GuiDocument::updateDefaultFormat()
                                QVariant(QString("default")));
        typedef vector<Format const *> Formats;
        Formats formats = param_copy.exportableFormats(true);
+       sort(formats.begin(), formats.end(), Format::formatSorter);
        Formats::const_iterator cit = formats.begin();
        Formats::const_iterator end = formats.end();
        for (; cit != end; ++cit)
@@ -2539,9 +2541,11 @@ void GuiDocument::applyView()
                bp_.setCiteEngine("natbib");
        else if (biblioModule->citeJurabibRB->isChecked())
                bp_.setCiteEngine("jurabib");
-       else
+       if (biblioModule->citeDefaultRB->isChecked()) {
                bp_.setCiteEngine("basic");
-
+               bp_.setCiteEngineType(ENGINE_TYPE_DEFAULT);
+       }
+       else
        if (biblioModule->citeStyleCO->currentIndex())
                bp_.setCiteEngineType(ENGINE_TYPE_NUMERICAL);
        else
@@ -2586,7 +2590,7 @@ void GuiDocument::applyView()
                        for (; it != end; ++it) {
                                if (qt_(it->guiName()) == enc_gui &&
                                    !it->unsafe()) {
-                                       bp_.inputenc = it->latexName();
+                                       bp_.inputenc = it->name();
                                        found = true;
                                        break;
                                }
@@ -2602,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();
@@ -2649,20 +2660,26 @@ void GuiDocument::applyView()
        modulesToParams(bp_);
 
        // Math
-       vector<string> const & packages = BufferParams::auto_packages();
-        for (size_t n = 0; n < packages.size(); ++n) {
-               QCheckBox * autoCB = static_cast<QCheckBox *>(
-                       mathsModule->gridLayout->itemAtPosition(2 * n, 0)->widget());
-               if (autoCB->isChecked())
-                       bp_.use_package(packages[n], BufferParams::package_auto);
-               else {
-                       QCheckBox * alwaysCB = static_cast<QCheckBox *>(
-                               mathsModule->gridLayout->itemAtPosition(2 * n + 1, 0)->widget());
-                       if (alwaysCB->isChecked())
-                               bp_.use_package(packages[n], BufferParams::package_on);
-                       else
-                               bp_.use_package(packages[n], BufferParams::package_off);
+       map<string, string> const & packages = BufferParams::auto_packages();
+       for (map<string, string>::const_iterator it = packages.begin();
+            it != packages.end(); ++it) {
+               QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
+               if (!item)
+                       continue;
+               int row = mathsModule->packagesTW->row(item);
+               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1);
+               if (rb->isChecked()) {
+                       bp_.use_package(it->first, BufferParams::package_auto);
+                       continue;
+               }
+               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2);
+               if (rb->isChecked()) {
+                       bp_.use_package(it->first, BufferParams::package_on);
+                       continue;
                }
+               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3);
+               if (rb->isChecked())
+                       bp_.use_package(it->first, BufferParams::package_off);
        }
 
        // Page Layout
@@ -2791,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();
@@ -2803,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 =
@@ -2913,6 +2931,9 @@ void GuiDocument::applyView()
                pdf.pagemode.clear();
        pdf.quoted_options = pdf.quoted_options_check(
                                fromqstr(pdfSupportModule->optionsLE->text()));
+
+       // reset tracker
+       nonModuleChanged_ = false;
 }
 
 
@@ -2942,7 +2963,7 @@ void GuiDocument::paramsToDialog()
                cite_engine == "natbib");
 
        biblioModule->citeStyleCO->setCurrentIndex(
-               bp_.citeEngineType() == ENGINE_TYPE_NUMERICAL);
+               bp_.citeEngineType() & ENGINE_TYPE_NUMERICAL);
 
        updateEngineType(documentClass().opt_enginetype(),
                bp_.citeEngineType());
@@ -2973,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(
@@ -2993,7 +3014,7 @@ void GuiDocument::paramsToDialog()
                        Encodings::const_iterator it = encodings.begin();
                        Encodings::const_iterator const end = encodings.end();
                        for (; it != end; ++it) {
-                               if (it->latexName() == bp_.inputenc &&
+                               if (it->name() == bp_.inputenc &&
                                    !it->unsafe()) {
                                        enc_gui = it->guiName();
                                        break;
@@ -3074,14 +3095,30 @@ void GuiDocument::paramsToDialog()
                latexModule->psdriverCO->setCurrentIndex(nitem);
        updateModuleInfo();
 
-       vector<string> const & packages = BufferParams::auto_packages();
-        for (size_t n = 0; n < packages.size(); ++n) {
-               QCheckBox * alwaysCB = static_cast<QCheckBox *>(
-                       mathsModule->gridLayout->itemAtPosition(2 * n + 1, 0)->widget());
-               alwaysCB->setChecked(bp_.use_package(packages[n]) == BufferParams::package_on);
-               QCheckBox * autoCB = static_cast<QCheckBox *>(
-                       mathsModule->gridLayout->itemAtPosition(2 * n, 0)->widget());
-               autoCB->setChecked(bp_.use_package(packages[n]) == BufferParams::package_auto);
+       map<string, string> const & packages = BufferParams::auto_packages();
+       for (map<string, string>::const_iterator it = packages.begin();
+            it != packages.end(); ++it) {
+               QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
+               if (!item)
+                       continue;
+               int row = mathsModule->packagesTW->row(item);
+               switch (bp_.use_package(it->first)) {
+                       case BufferParams::package_off: {
+                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3);
+                               rb->setChecked(true);
+                               break;
+                       }
+                       case BufferParams::package_on: {
+                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2);
+                               rb->setChecked(true);
+                               break;
+                       }
+                       case BufferParams::package_auto: {
+                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1);
+                               rb->setChecked(true);
+                               break;
+                       }
+               }
        }
 
        switch (bp_.spacing().getSpace()) {
@@ -3195,11 +3232,11 @@ void GuiDocument::paramsToDialog()
        if (!bufferview() || !buffer().hasChildren()) {
                masterChildModule->childrenTW->clear();
                includeonlys_.clear();
-               docPS->showPanel(qt_("Child Documents"), false);
-               if (docPS->isCurrentPanel(qt_("Child Documents")))
-                       docPS->setCurrentPanel(qt_("Document Class"));
+               docPS->showPanel("Child Documents", false);
+               if (docPS->isCurrentPanel("Child Documents"))
+                       docPS->setCurrentPanel("Document Class");
        } else {
-               docPS->showPanel(qt_("Child Documents"), true);
+               docPS->showPanel("Child Documents", true);
                masterChildModule->setEnabled(true);
                includeonlys_ = bp_.getIncludedChildren();
                updateIncludeonlys();
@@ -3217,12 +3254,18 @@ void GuiDocument::paramsToDialog()
        listingsModule->listingsED->setPlainText(toqstr(lstparams));
 
        // Fonts
+       // some languages only work with polyglossia/XeTeX
+       Language const * lang = lyx::languages.getLanguage(
+               fromqstr(langModule->languageCO->itemData(
+                       langModule->languageCO->currentIndex()).toString()));
+       bool const need_fontspec =
+               lang->babel().empty() && !lang->polyglossia().empty();
        bool const os_fonts_available =
                bp_.baseClass()->outputType() == lyx::LATEX
                && LaTeXFeatures::isAvailable("fontspec");
-       fontModule->osFontsCB->setEnabled(os_fonts_available);
+       fontModule->osFontsCB->setEnabled(os_fonts_available && !need_fontspec);
        fontModule->osFontsCB->setChecked(
-               os_fonts_available && bp_.useNonTeXFonts);
+               (os_fonts_available && bp_.useNonTeXFonts) || need_fontspec);
        updateFontsize(documentClass().opt_fontsize(),
                        bp_.fontsize);
 
@@ -3410,6 +3453,9 @@ void GuiDocument::paramsToDialog()
 
        // clear changed branches cache
        changedBranches_.clear();
+
+       // reset tracker
+       nonModuleChanged_ = false;
 }
 
 
@@ -3643,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()));
 }
@@ -3655,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,
@@ -3724,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();
 }
 
 
@@ -3740,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());
 }
 
 
@@ -3865,6 +3920,33 @@ void GuiDocument::executeBranchRenaming() const
 }
 
 
+void GuiDocument::allPackagesAuto()
+{
+       allPackages(1);
+}
+
+
+void GuiDocument::allPackagesAlways()
+{
+       allPackages(2);
+}
+
+
+void GuiDocument::allPackagesNot()
+{
+       allPackages(3);
+}
+
+
+void GuiDocument::allPackages(int col)
+{
+       for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) {
+               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col);
+               rb->setChecked(true);
+       }
+}
+
+
 Dialog * createGuiDocument(GuiView & lv) { return new GuiDocument(lv); }