]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiDocument.cpp
Use <cstdint> instead of <boost/cstdint.hpp>
[lyx.git] / src / frontends / qt4 / GuiDocument.cpp
index b607231043babad542a27f1d51b8f3d0f5d967b5..0f143b2cc032e4be23a0e9a96949e2ab5a14a456 100644 (file)
 #include "insets/InsetListingsParams.h"
 
 #include "support/debug.h"
+#include "support/docstream.h"
 #include "support/FileName.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
+#include "support/Package.h"
+#include "support/TempFile.h"
 
 #include "frontends/alert.h"
 
 #include <QAbstractItemModel>
-#include <QHeaderView>
+#include <QButtonGroup>
 #include <QColor>
 #include <QColorDialog>
 #include <QCloseEvent>
+#include <QDirIterator>
 #include <QFontDatabase>
+#include <QHeaderView>
+#include <QPixmap>
 #include <QScrollBar>
 #include <QTextBoundaryFinder>
 #include <QTextCursor>
@@ -150,6 +156,11 @@ QMap<QString, QString> sffonts_;
 QMap<QString, QString> ttfonts_;
 QMap<QString, QString> mathfonts_;
 
+enum EncodingSets {
+       unicode = 0,
+       legacy = 1,
+       custom = 2
+};
 
 } // anonymous namespace
 
@@ -259,12 +270,12 @@ public:
        ///
        ModuleSelectionManager(QObject * parent,
                               QTreeView * availableLV,
-                              QListView * selectedLV,
+                              QTreeView * selectedLV,
                               QPushButton * addPB,
                               QPushButton * delPB,
                               QPushButton * upPB,
                               QPushButton * downPB,
-                              GuiIdListModel * availableModel,
+                              QStandardItemModel * availableModel,
                               GuiIdListModel * selectedModel,
                               GuiDocument const * container)
                : GuiSelectionManager(parent, availableLV, selectedLV, addPB, delPB,
@@ -287,9 +298,9 @@ private:
        ///
        virtual void updateDelPB();
        /// returns availableModel as a GuiIdListModel
-       GuiIdListModel * getAvailableModel()
+       QStandardItemModel * getAvailableModel()
        {
-               return dynamic_cast<GuiIdListModel *>(availableModel);
+               return dynamic_cast<QStandardItemModel *>(availableModel);
        }
        /// returns selectedModel as a GuiIdListModel
        GuiIdListModel * getSelectedModel()
@@ -308,7 +319,7 @@ void ModuleSelectionManager::updateAddPB()
 {
        int const arows = availableModel->rowCount();
        QModelIndexList const avail_sels =
-                       availableLV->selectionModel()->selectedIndexes();
+                       availableLV->selectionModel()->selectedRows(0);
 
        // disable if there aren't any modules (?), if none of them is chosen
        // in the dialog, or if the chosen one is already selected for use.
@@ -318,7 +329,14 @@ void ModuleSelectionManager::updateAddPB()
        }
 
        QModelIndex const & idx = availableLV->selectionModel()->currentIndex();
-       string const modname = getAvailableModel()->getIDString(idx.row());
+
+       if (getAvailableModel()->itemFromIndex(idx)->hasChildren()) {
+               // This is a category header
+               addPB->setEnabled(false);
+               return;
+       }
+
+       string const modname = fromqstr(getAvailableModel()->data(idx, Qt::UserRole).toString());
 
        bool const enable =
                container_->params().layoutModuleCanBeAdded(modname);
@@ -469,6 +487,34 @@ PreambleModule::PreambleModule(QWidget * parent)
        preambleTE->setWordWrapMode(QTextOption::NoWrap);
        setFocusProxy(preambleTE);
        connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed()));
+       connect(findLE, SIGNAL(textEdited(const QString &)), this, SLOT(checkFindButton()));
+       connect(findButtonPB, SIGNAL(clicked()), this, SLOT(findText()));
+       connect(editPB, SIGNAL(clicked()), this, SLOT(editExternal()));
+       connect(findLE, SIGNAL(returnPressed()), this, SLOT(findText()));
+       checkFindButton();
+       // https://stackoverflow.com/questions/13027091/how-to-override-tab-width-in-qt
+       const int tabStop = 4;
+       QFontMetrics metrics(preambleTE->currentFont());
+       preambleTE->setTabStopWidth(tabStop * metrics.width(' '));
+}
+
+
+void PreambleModule::checkFindButton()
+{
+       findButtonPB->setEnabled(!findLE->text().isEmpty());
+}
+
+
+void PreambleModule::findText()
+{
+       bool const found = preambleTE->find(findLE->text());
+       if (!found) {
+               // wrap
+               QTextCursor qtcur = preambleTE->textCursor();
+               qtcur.movePosition(QTextCursor::Start);
+               preambleTE->setTextCursor(qtcur);
+               preambleTE->find(findLE->text());
+       }
 }
 
 
@@ -518,6 +564,36 @@ void PreambleModule::closeEvent(QCloseEvent * e)
 }
 
 
+void PreambleModule::editExternal() {
+       if (!current_id_)
+               return;
+
+       if (tempfile_) {
+               preambleTE->setReadOnly(false);
+               FileName const tempfilename = tempfile_->name();
+               docstring const s = tempfilename.fileContents("UTF-8");
+               preambleTE->document()->setPlainText(toqstr(s));
+               tempfile_.reset();
+               editPB->setText(qt_("&Edit"));
+               changed();
+               return;
+       }
+
+       string const format =
+               current_id_->params().documentClass().outputFormat();
+       string const ext = theFormats().extension(format);
+       tempfile_.reset(new TempFile("preamble_editXXXXXX." + ext));
+       FileName const tempfilename = tempfile_->name();
+       string const name = tempfilename.toFilesystemEncoding();
+       ofdocstream os(name.c_str());
+       os << qstring_to_ucs4(preambleTE->document()->toPlainText());
+       os.close();
+       preambleTE->setReadOnly(true);
+       theFormats().edit(*current_id_, tempfilename, format);
+       editPB->setText(qt_("&End Edit"));
+       changed();
+}
+
 /////////////////////////////////////////////////////////////////////
 //
 // LocalLayout
@@ -528,9 +604,12 @@ void PreambleModule::closeEvent(QCloseEvent * e)
 LocalLayout::LocalLayout(QWidget * parent)
        : UiWidget<Ui::LocalLayoutUi>(parent), current_id_(0), validated_(false)
 {
+       locallayoutTE->setFont(guiApp->typewriterSystemFont());
+       locallayoutTE->setWordWrapMode(QTextOption::NoWrap);
        connect(locallayoutTE, SIGNAL(textChanged()), this, SLOT(textChanged()));
        connect(validatePB, SIGNAL(clicked()), this, SLOT(validatePressed()));
        connect(convertPB, SIGNAL(clicked()), this, SLOT(convertPressed()));
+       connect(editPB, SIGNAL(clicked()), this, SLOT(editExternal()));
 }
 
 
@@ -568,8 +647,10 @@ void LocalLayout::hideConvert()
 
 void LocalLayout::textChanged()
 {
-       static const QString message =
-               qt_("Press button to check validity...");
+       // Flashy red bold text
+       static const QString ivpar("<p style=\"color: #c00000; font-weight: bold; text-align:left\">"
+                                  "%1</p>");
+       static const QString message = ivpar.arg(qt_("Validation required!"));
        string const layout =
                fromqstr(locallayoutTE->document()->toPlainText().trimmed());
 
@@ -609,9 +690,9 @@ void LocalLayout::convertPressed() {
 
 void LocalLayout::validate() {
        // Bold text
-       static const QString vpar("<p style=\"font-weight: bold;\">%1</p>");
+       static const QString vpar("<p style=\"font-weight: bold; text-align:left\">%1</p>");
        // Flashy red bold text
-       static const QString ivpar("<p style=\"color: #c00000; font-weight: bold; \">"
+       static const QString ivpar("<p style=\"color: #c00000; font-weight: bold; text-align:left\">"
                                   "%1</p>");
        string const layout =
                fromqstr(locallayoutTE->document()->toPlainText().trimmed());
@@ -655,6 +736,38 @@ void LocalLayout::validatePressed() {
 }
 
 
+void LocalLayout::editExternal() {
+       if (!current_id_)
+               return;
+
+       if (tempfile_) {
+               locallayoutTE->setReadOnly(false);
+               FileName const tempfilename = tempfile_->name();
+               docstring const s = tempfilename.fileContents("UTF-8");
+               locallayoutTE->document()->setPlainText(toqstr(s));
+               tempfile_.reset();
+               editPB->setText(qt_("&Edit"));
+               changed();
+               return;
+       }
+
+       string const format =
+               current_id_->params().documentClass().outputFormat();
+       string const ext = theFormats().extension(format);
+       tempfile_.reset(new TempFile("preamble_editXXXXXX." + ext));
+       FileName const tempfilename = tempfile_->name();
+       string const name = tempfilename.toFilesystemEncoding();
+       ofdocstream os(name.c_str());
+       os << qstring_to_ucs4(locallayoutTE->document()->toPlainText());
+       os.close();
+       locallayoutTE->setReadOnly(true);
+       theFormats().edit(*current_id_, tempfilename, format);
+       editPB->setText(qt_("&End Edit"));
+       validatePB->setEnabled(false);
+       hideConvert();
+       changed();
+}
+
 /////////////////////////////////////////////////////////////////////
 //
 // DocumentDialog
@@ -669,20 +782,18 @@ GuiDocument::GuiDocument(GuiView & lv)
 {
        setupUi(this);
 
-       connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
-       connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
-       connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
-       connect(restorePB, SIGNAL(clicked()), this, SLOT(slotRestore()));
+       connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
+               this, SLOT(slotButtonBox(QAbstractButton *)));
 
        connect(savePB, SIGNAL(clicked()), this, SLOT(saveDefaultClicked()));
        connect(defaultPB, SIGNAL(clicked()), this, SLOT(useDefaultsClicked()));
 
        // Manage the restore, ok, apply, restore and cancel/close buttons
        bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
-       bc().setOK(okPB);
-       bc().setApply(applyPB);
-       bc().setCancel(closePB);
-       bc().setRestore(restorePB);
+       bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
+       bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
+       bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
+       bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
 
 
        // text layout
@@ -732,6 +843,9 @@ GuiDocument::GuiDocument(GuiView & lv)
        connect(textLayoutModule->justCB, SIGNAL(clicked()),
                this, SLOT(change_adaptor()));
 
+       connect(textLayoutModule->tableStyleCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+
        textLayoutModule->lspacingLE->setValidator(new QDoubleValidator(
                textLayoutModule->lspacingLE));
        textLayoutModule->indentLE->setValidator(new LengthValidator(
@@ -757,6 +871,9 @@ GuiDocument::GuiDocument(GuiView & lv)
        bc().addCheckedLineEdit(textLayoutModule->indentLE);
        bc().addCheckedLineEdit(textLayoutModule->skipLE);
 
+       textLayoutModule->tableStyleCO->addItem(qt_("Default"), toqstr("default"));
+       getTableStyles();
+
 
        // master/child handling
        masterChildModule = new UiWidget<Ui::MasterChildUi>(this);
@@ -811,6 +928,95 @@ GuiDocument::GuiDocument(GuiView & lv)
        connect(outputModule->saveTransientPropertiesCB, SIGNAL(clicked()),
                this, SLOT(change_adaptor()));
 
+
+       // language & quote
+       // this must preceed font, since fonts depend on this
+       langModule = new UiWidget<Ui::LanguageUi>(this);
+       connect(langModule->languageCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->languageCO, SIGNAL(activated(int)),
+               this, SLOT(languageChanged(int)));
+       connect(langModule->encodingCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->encodingCO, SIGNAL(activated(int)),
+               this, SLOT(encodingSwitched(int)));
+       connect(langModule->unicodeEncodingCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->customEncodingCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->noInputencCB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
+       connect(langModule->quoteStyleCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->languagePackageCO, SIGNAL(activated(int)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->languagePackageLE, SIGNAL(textChanged(QString)),
+               this, SLOT(change_adaptor()));
+       connect(langModule->languagePackageCO, SIGNAL(currentIndexChanged(int)),
+               this, SLOT(languagePackageChanged(int)));
+       connect(langModule->dynamicQuotesCB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
+
+       langModule->languagePackageLE->setValidator(new NoNewLineValidator(
+               langModule->languagePackageLE));
+
+       QAbstractItemModel * language_model = guiApp->languageModel();
+       // FIXME: it would be nice if sorting was enabled/disabled via a checkbox.
+       language_model->sort(0);
+       langModule->languageCO->setModel(language_model);
+       langModule->languageCO->setModelColumn(0);
+
+       langModule->encodingCO->addItem(qt_("Unicode (utf8)"));
+       langModule->encodingCO->addItem(qt_("Traditional (auto-selected)"));
+       langModule->encodingCO->addItem(qt_("Custom"));
+       langModule->encodingCO->setItemData(EncodingSets::unicode,
+               "Use Unicode (utf8) for the latex source.", Qt::ToolTipRole);
+       langModule->encodingCO->setItemData(EncodingSets::legacy,
+               "Use legacy default encodings depending on text language.", Qt::ToolTipRole);
+       langModule->encodingCO->setItemData(EncodingSets::custom,
+               "Select a custom, document-wide encoding.", Qt::ToolTipRole);
+       
+       QMap<QString,QString> encodingmap_utf8;
+       for (auto const & encvar : encodings) {
+               if (!encvar.unsafe() && !encvar.guiName().empty()
+                       && std::string(encvar.name()).find("utf8") == 0)
+                       encodingmap_utf8.insert(qt_(encvar.guiName()), qt_(encvar.name()));
+       }
+       QMap<QString, QString>::const_iterator it8 = encodingmap_utf8.constBegin();
+       while (it8 != encodingmap_utf8.constEnd()) {
+               langModule->unicodeEncodingCO->addItem(it8.key(), it8.value());
+               ++it8;
+       }
+
+       QMap<QString,QString> encodingmap;
+       for (auto const & encvar : encodings) {
+               if (!encvar.unsafe() && !encvar.guiName().empty()
+                       && std::string(encvar.name()).find("utf8") != 0)
+                       encodingmap.insert(qt_(encvar.guiName()), qt_(encvar.name()));
+       }
+       QMap<QString, QString>::const_iterator it = encodingmap.constBegin();
+       while (it != encodingmap.constEnd()) {
+               langModule->customEncodingCO->addItem(it.key(), it.value());
+               ++it;
+       }
+       // equalise the width of encoding selectors
+       langModule->unicodeEncodingCO->setMinimumSize(
+               langModule->customEncodingCO->minimumSizeHint());
+       langModule->noInputencCB->setMinimumSize(
+               langModule->customEncodingCO->minimumSizeHint());
+
+       langModule->languagePackageCO->addItem(
+               qt_("Default"), toqstr("default"));
+       langModule->languagePackageCO->addItem(
+               qt_("Automatic"), toqstr("auto"));
+       langModule->languagePackageCO->addItem(
+               qt_("Always Babel"), toqstr("babel"));
+       langModule->languagePackageCO->addItem(
+               qt_("Custom"), toqstr("custom"));
+       langModule->languagePackageCO->addItem(
+               qt_("None[[language package]]"), toqstr("none"));
+
+
        // fonts
        fontModule = new FontModule(this);
        connect(fontModule->osFontsCB, SIGNAL(clicked()),
@@ -874,9 +1080,9 @@ GuiDocument::GuiDocument(GuiView & lv)
        fontModule->fontsizeCO->addItem(qt_("11"));
        fontModule->fontsizeCO->addItem(qt_("12"));
 
-       fontModule->fontencCO->addItem(qt_("Default"), QString("global"));
+       fontModule->fontencCO->addItem(qt_("Automatic"), QString("auto"));
+       fontModule->fontencCO->addItem(qt_("Class Default"), QString("default"));
        fontModule->fontencCO->addItem(qt_("Custom"), QString("custom"));
-       fontModule->fontencCO->addItem(qt_("None (no fontenc)"), QString("default"));
 
        for (int n = 0; GuiDocument::fontfamilies_gui[n][0]; ++n)
                fontModule->fontsDefaultCO->addItem(
@@ -1041,62 +1247,6 @@ GuiDocument::GuiDocument(GuiView & lv)
                marginsModule->columnsepL);
 
 
-       // language & quote
-       langModule = new UiWidget<Ui::LanguageUi>(this);
-       connect(langModule->languageCO, SIGNAL(activated(int)),
-               this, SLOT(change_adaptor()));
-       connect(langModule->languageCO, SIGNAL(activated(int)),
-               this, SLOT(languageChanged(int)));
-       connect(langModule->defaultencodingRB, SIGNAL(clicked()),
-               this, SLOT(change_adaptor()));
-       connect(langModule->otherencodingRB, SIGNAL(clicked()),
-               this, SLOT(change_adaptor()));
-       connect(langModule->encodingCO, SIGNAL(activated(int)),
-               this, SLOT(change_adaptor()));
-       connect(langModule->quoteStyleCO, SIGNAL(activated(int)),
-               this, SLOT(change_adaptor()));
-       connect(langModule->languagePackageCO, SIGNAL(activated(int)),
-               this, SLOT(change_adaptor()));
-       connect(langModule->languagePackageLE, SIGNAL(textChanged(QString)),
-               this, SLOT(change_adaptor()));
-       connect(langModule->languagePackageCO, SIGNAL(currentIndexChanged(int)),
-               this, SLOT(languagePackageChanged(int)));
-       connect(langModule->dynamicQuotesCB, SIGNAL(clicked()),
-               this, SLOT(change_adaptor()));
-
-       langModule->languagePackageLE->setValidator(new NoNewLineValidator(
-               langModule->languagePackageLE));
-
-       QAbstractItemModel * language_model = guiApp->languageModel();
-       // FIXME: it would be nice if sorting was enabled/disabled via a checkbox.
-       language_model->sort(0);
-       langModule->languageCO->setModel(language_model);
-       langModule->languageCO->setModelColumn(0);
-
-       // Always put the default encoding in the first position.
-       langModule->encodingCO->addItem(qt_("Language Default (no inputenc)"));
-       QStringList encodinglist;
-       Encodings::const_iterator it = encodings.begin();
-       Encodings::const_iterator const end = encodings.end();
-       for (auto const & encvar : encodings) {
-               if (!encvar.unsafe())
-                       encodinglist.append(qt_(encvar.guiName()));
-       }
-       encodinglist.sort();
-       langModule->encodingCO->addItems(encodinglist);
-
-       langModule->languagePackageCO->addItem(
-               qt_("Default"), toqstr("default"));
-       langModule->languagePackageCO->addItem(
-               qt_("Automatic"), toqstr("auto"));
-       langModule->languagePackageCO->addItem(
-               qt_("Always Babel"), toqstr("babel"));
-       langModule->languagePackageCO->addItem(
-               qt_("Custom"), toqstr("custom"));
-       langModule->languagePackageCO->addItem(
-               qt_("None[[language package]]"), toqstr("none"));
-
-
        // color
        colorModule = new UiWidget<Ui::ColorUi>(this);
        connect(colorModule->fontColorPB, SIGNAL(clicked()),
@@ -1132,6 +1282,13 @@ GuiDocument::GuiDocument(GuiView & lv)
        numberingModule->tocTW->headerItem()->setText(1, qt_("Numbered"));
        numberingModule->tocTW->headerItem()->setText(2, qt_("Appears in TOC"));
        setSectionResizeMode(numberingModule->tocTW->header(), QHeaderView::ResizeToContents);
+       connect(numberingModule->linenoCB, SIGNAL(toggled(bool)),
+               this, SLOT(linenoToggled(bool)));
+       connect(numberingModule->linenoCB, SIGNAL(clicked()),
+               this, SLOT(change_adaptor()));
+       connect(numberingModule->linenoLE, SIGNAL(textChanged(QString)),
+               this, SLOT(change_adaptor()));
+
 
        // biblio
        biblioModule = new UiWidget<Ui::BiblioUi>(this);
@@ -1157,10 +1314,14 @@ GuiDocument::GuiDocument(GuiView & lv)
                this, SLOT(updateResetDefaultBiblio()));
        connect(biblioModule->biblatexBbxCO, SIGNAL(activated(int)),
                this, SLOT(biblioChanged()));
+       connect(biblioModule->biblatexBbxCO, SIGNAL(editTextChanged(QString)),
+               this, SLOT(biblioChanged()));
        connect(biblioModule->biblatexBbxCO, SIGNAL(editTextChanged(QString)),
                this, SLOT(updateResetDefaultBiblio()));
        connect(biblioModule->biblatexCbxCO, SIGNAL(activated(int)),
                this, SLOT(biblioChanged()));
+       connect(biblioModule->biblatexCbxCO, SIGNAL(editTextChanged(QString)),
+               this, SLOT(biblioChanged()));
        connect(biblioModule->biblatexCbxCO, SIGNAL(editTextChanged(QString)),
                this, SLOT(updateResetDefaultBiblio()));
        connect(biblioModule->rescanBibliosPB, SIGNAL(clicked()),
@@ -1210,7 +1371,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::ResizeToContents);
+       setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch);
        map<string, string> const & packages = BufferParams::auto_packages();
        mathsModule->packagesTW->setRowCount(packages.size());
        int packnum = 0;
@@ -1243,15 +1404,34 @@ GuiDocument::GuiDocument(GuiView & lv)
                autoRB->setToolTip(autoTooltip);
                alwaysRB->setToolTip(alwaysTooltip);
                neverRB->setToolTip(neverTooltip);
+
+               // Pack the buttons in a layout in order to get proper alignment
+               QWidget * autoRBWidget = new QWidget();
+               QHBoxLayout * autoRBLayout = new QHBoxLayout(autoRBWidget);
+               autoRBLayout->addWidget(autoRB);
+               autoRBLayout->setAlignment(Qt::AlignCenter);
+               autoRBLayout->setContentsMargins(0, 0, 0, 0);
+               autoRBWidget->setLayout(autoRBLayout);
+
+               QWidget * alwaysRBWidget = new QWidget();
+               QHBoxLayout * alwaysRBLayout = new QHBoxLayout(alwaysRBWidget);
+               alwaysRBLayout->addWidget(alwaysRB);
+               alwaysRBLayout->setAlignment(Qt::AlignCenter);
+               alwaysRBLayout->setContentsMargins(0, 0, 0, 0);
+               alwaysRBWidget->setLayout(alwaysRBLayout);
+
+               QWidget * neverRBWidget = new QWidget();
+               QHBoxLayout * neverRBLayout = new QHBoxLayout(neverRBWidget);
+               neverRBLayout->addWidget(neverRB);
+               neverRBLayout->setAlignment(Qt::AlignCenter);
+               neverRBLayout->setContentsMargins(0, 0, 0, 0);
+               neverRBWidget->setLayout(neverRBLayout);
+
                QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package));
                mathsModule->packagesTW->setItem(packnum, 0, pack);
-               mathsModule->packagesTW->setCellWidget(packnum, 1, autoRB);
-               mathsModule->packagesTW->setCellWidget(packnum, 2, alwaysRB);
-               mathsModule->packagesTW->setCellWidget(packnum, 3, neverRB);
-               //center the radio buttons
-               autoRB->setStyleSheet("margin-left:50%; margin-right:50%;");
-               alwaysRB->setStyleSheet("margin-left:50%; margin-right:50%;");
-               neverRB->setStyleSheet("margin-left:50%; margin-right:50%;");
+               mathsModule->packagesTW->setCellWidget(packnum, 1, autoRBWidget);
+               mathsModule->packagesTW->setCellWidget(packnum, 2, alwaysRBWidget);
+               mathsModule->packagesTW->setCellWidget(packnum, 3, neverRBWidget);
 
                connect(autoRB, SIGNAL(clicked()),
                        this, SLOT(change_adaptor()));
@@ -1396,6 +1576,9 @@ GuiDocument::GuiDocument(GuiView & lv)
        modulesModule->availableLV->header()->setVisible(false);
        setSectionResizeMode(modulesModule->availableLV->header(), QHeaderView::ResizeToContents);
        modulesModule->availableLV->header()->setStretchLastSection(false);
+       modulesModule->selectedLV->header()->setVisible(false);
+       setSectionResizeMode(modulesModule->selectedLV->header(), QHeaderView::ResizeToContents);
+       modulesModule->selectedLV->header()->setStretchLastSection(false);
        selectionManager =
                new ModuleSelectionManager(this, modulesModule->availableLV,
                                           modulesModule->selectedLV,
@@ -1403,11 +1586,34 @@ GuiDocument::GuiDocument(GuiView & lv)
                                           modulesModule->deletePB,
                                           modulesModule->upPB,
                                           modulesModule->downPB,
-                                          availableModel(), selectedModel(), this);
+                                          availableModel(), selectedModel(), this);
        connect(selectionManager, SIGNAL(updateHook()),
                this, SLOT(updateModuleInfo()));
        connect(selectionManager, SIGNAL(selectionChanged()),
                this, SLOT(modulesChanged()));
+       // The filter bar
+       filter_ = new FancyLineEdit(this);
+       filter_->setButtonPixmap(FancyLineEdit::Right, getPixmap("images/", "editclear", "svgz,png"));
+       filter_->setButtonVisible(FancyLineEdit::Right, true);
+       filter_->setButtonToolTip(FancyLineEdit::Right, qt_("Clear text"));
+       filter_->setAutoHideButton(FancyLineEdit::Right, true);
+       filter_->setPlaceholderText(qt_("All avail. modules"));
+       modulesModule->moduleFilterBarL->addWidget(filter_, 0);
+       modulesModule->findModulesLA->setBuddy(filter_);
+
+       connect(filter_, SIGNAL(rightButtonClicked()),
+               this, SLOT(resetModuleFilter()));
+       connect(filter_, SIGNAL(textEdited(QString)),
+               this, SLOT(moduleFilterChanged(QString)));
+       connect(filter_, SIGNAL(returnPressed()),
+               this, SLOT(moduleFilterPressed()));
+#if (QT_VERSION < 0x050000)
+       connect(filter_, SIGNAL(downPressed()),
+               modulesModule->availableLV, SLOT(setFocus()));
+#else
+       connect(filter_, &FancyLineEdit::downPressed,
+               modulesModule->availableLV, [=](){ focusAndHighlight(modulesModule->availableLV); });
+#endif
 
 
        // PDF support
@@ -1503,7 +1709,7 @@ GuiDocument::GuiDocument(GuiView & lv)
        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(floatModule, N_("Float Settings"));
        docPS->addPanel(listingsModule, N_("Listings[[inset]]"));
        docPS->addPanel(bulletsModule, N_("Bullets"));
        docPS->addPanel(branchesModule, N_("Branches"));
@@ -1573,6 +1779,86 @@ void GuiDocument::slotOK()
 }
 
 
+void GuiDocument::slotButtonBox(QAbstractButton * button)
+{
+       switch (buttonBox->standardButton(button)) {
+       case QDialogButtonBox::Ok:
+               slotOK();
+               break;
+       case QDialogButtonBox::Apply:
+               slotApply();
+               break;
+       case QDialogButtonBox::Cancel:
+               slotClose();
+               break;
+       case QDialogButtonBox::Reset:
+       case QDialogButtonBox::RestoreDefaults:
+               slotRestore();
+               break;
+       default:
+               break;
+       }
+}
+
+
+void GuiDocument::filterModules(QString const & str)
+{
+       updateAvailableModules();
+       if (str.isEmpty())
+               return;
+
+       modules_av_model_.clear();
+       list<modInfoStruct> modInfoList = getModuleInfo();
+       // Sort names according to the locale
+       modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
+                       return 0 < b.name.localeAwareCompare(a.name);
+               });
+
+       QIcon user_icon(getPixmap("images/", "lyxfiles-user", "svgz,png"));
+       QIcon system_icon(getPixmap("images/", "lyxfiles-system", "svgz,png"));
+
+       int i = 0;
+       for (modInfoStruct const & m : modInfoList) {
+               if (m.name.contains(str, Qt::CaseInsensitive) || contains(m.id, fromqstr(str))) {
+                       QStandardItem * item = new QStandardItem();
+                       item->setData(m.name, Qt::DisplayRole);
+                       item->setData(toqstr(m.id), Qt::UserRole);
+                       item->setData(m.description, Qt::ToolTipRole);
+                       if (m.local)
+                               item->setIcon(user_icon);
+                       else
+                               item->setIcon(system_icon);
+                       modules_av_model_.insertRow(i, item);
+                       ++i;
+               }
+       }
+}
+
+
+void GuiDocument::moduleFilterChanged(const QString & text)
+{
+       if (!text.isEmpty()) {
+               filterModules(filter_->text());
+               return;
+       }
+       filterModules(filter_->text());
+       filter_->setFocus();
+}
+
+
+void GuiDocument::moduleFilterPressed()
+{
+       filterModules(filter_->text());
+}
+
+
+void GuiDocument::resetModuleFilter()
+{
+       filter_->setText(QString());
+       filterModules(filter_->text());
+}
+
+
 void GuiDocument::includeonlyClicked(QTreeWidgetItem * item, int)
 {
        if (item == 0)
@@ -1930,10 +2216,11 @@ void GuiDocument::updateQuoteStyles(bool const set)
 
 void GuiDocument::languageChanged(int i)
 {
-       // some languages only work with polyglossia
+       // some languages only work with Polyglossia
        Language const * lang = lyx::languages.getLanguage(
                fromqstr(langModule->languageCO->itemData(i).toString()));
-       if (lang->babel().empty() && !lang->polyglossia().empty()) {
+       if (lang->babel().empty() && !lang->polyglossia().empty()
+               && lang->requires() != "CJK" && lang->requires() != "japanese") {
                        // If we force to switch fontspec on, store
                        // current state (#8717)
                        if (fontModule->osFontsCB->isEnabled())
@@ -2004,10 +2291,9 @@ void GuiDocument::osFontsChanged(bool nontexfonts)
        fontModule->font_sf_scale = font_sf_scale;
        fontModule->font_tt_scale = font_tt_scale;
 
-       langModule->encodingCO->setEnabled(tex_fonts &&
-               !langModule->defaultencodingRB->isChecked());
-       langModule->defaultencodingRB->setEnabled(tex_fonts);
-       langModule->otherencodingRB->setEnabled(tex_fonts);
+       // non-tex fonts override the "\inputencoding" option with "utf8-plain"
+       langModule->encodingCO->setEnabled(tex_fonts);
+       inputencodingToDialog();
 
        fontModule->fontsDefaultCO->setEnabled(tex_fonts);
        fontModule->fontsDefaultLA->setEnabled(tex_fonts);
@@ -2025,12 +2311,50 @@ void GuiDocument::osFontsChanged(bool nontexfonts)
 }
 
 
+void GuiDocument::encodingSwitched(int i)
+{
+       bool const tex_fonts = !fontModule->osFontsCB->isChecked();
+       langModule->unicodeEncodingCO->setEnabled(tex_fonts);
+       langModule->customEncodingCO->setEnabled(tex_fonts);
+       langModule->noInputencCB->setEnabled(tex_fonts);
+       langModule->unicodeEncodingCO->setVisible(i == EncodingSets::unicode);
+       langModule->noInputencCB->setVisible(i == EncodingSets::legacy);
+       langModule->customEncodingCO->setVisible(i == EncodingSets::custom);
+}
+
+void GuiDocument::inputencodingToDialog()
+{
+       QString inputenc = toqstr(bp_.inputenc);
+       int p;
+       if (fontModule->osFontsCB->isChecked()) { // non-tex fonts require utf8-plain
+               langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
+               langModule->unicodeEncodingCO->setCurrentIndex(
+                       langModule->unicodeEncodingCO->findData("utf8-plain"));
+       } else if (inputenc.startsWith("utf8")) {
+               langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
+               p = langModule->unicodeEncodingCO->findData(inputenc);
+               if (p != -1)
+                       langModule->unicodeEncodingCO->setCurrentIndex(p);
+       } else if (inputenc.startsWith("auto")) {
+               langModule->encodingCO->setCurrentIndex(EncodingSets::legacy);
+               langModule->noInputencCB->setChecked(inputenc == "auto-legacy-plain");
+       } else {
+               langModule->encodingCO->setCurrentIndex(EncodingSets::custom);
+               p = langModule->customEncodingCO->findData(inputenc);
+               if (p != -1)
+                       langModule->customEncodingCO->setCurrentIndex(p);
+               else
+                       langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
+       }
+       encodingSwitched(langModule->encodingCO->currentIndex());
+}
+
+
 void GuiDocument::mathFontChanged(int)
 {
        updateFontOptions();
 }
 
-
 void GuiDocument::fontOsfToggled(bool state)
 {
        if (fontModule->osFontsCB->isChecked())
@@ -2074,7 +2398,6 @@ void GuiDocument::updateFontOptions()
                                fontModule->fontsRomanCO->currentIndex()).toString();
        fontModule->fontScCB->setEnabled(providesSC(font));
        fontModule->fontOsfCB->setEnabled(providesOSF(font));
-       fontModule->dashesCB->setEnabled(tex_fonts);
        updateMathFonts(font);
 }
 
@@ -2101,8 +2424,13 @@ bool GuiDocument::ot1() const
 {
        QString const fontenc =
                fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString();
+       int const i = langModule->languageCO->currentIndex();
+       if (i == -1)
+               return false;
+       QString const langname = langModule->languageCO->itemData(i).toString();
+       Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
        return (fontenc == "default"
-               || (fontenc == "global" && (lyxrc.fontenc == "default" || lyxrc.fontenc == "OT1"))
+               || (fontenc == "auto" && newlang->fontenc(buffer().params()) == "OT1")
                || (fontenc == "custom" && fontModule->fontencLE->text() == "OT1"));
 }
 
@@ -2308,7 +2636,7 @@ void GuiDocument::updatePagestyle(string const & items, string const & sel)
 
 void GuiDocument::browseLayout()
 {
-       QString const label1 = qt_("Layouts|#o#O");
+       QString const label1 = qt_("Lay&outs");
        QString const dir1 = toqstr(lyxrc.document_path);
        QStringList const filter(qt_("LyX Layout (*.layout)"));
        QString file = browseRelToParent(QString(), bufferFilePath(),
@@ -2377,7 +2705,7 @@ void GuiDocument::browseMaster()
        QString const docpath = toqstr(support::onlyPath(buffer().absFileName()));
        QStringList const filter(qt_("LyX Files (*.lyx)"));
        QString file = browseRelToSub(old, docpath, title, filter, false,
-               qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
+               qt_("D&ocuments"), toqstr(lyxrc.document_path));
 
        if (!file.isEmpty())
                latexModule->childDocLE->setText(file);
@@ -2398,7 +2726,7 @@ void GuiDocument::classChanged()
                return;
        string const classname = fromqstr(latexModule->classCO->getData(idx));
 
-       if (applyPB->isEnabled()) {
+       if (buttonBox->button(QDialogButtonBox::Apply)->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."),
@@ -2412,7 +2740,7 @@ void GuiDocument::classChanged()
        // according to the new class. Note, however, that, if you use
        // the scroll wheel when sitting on the combo box, we'll load a
        // lot of TextClass objects very quickly....
-       if (!bp_.setBaseClass(classname)) {
+       if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
                Alert::error(_("Error"), _("Unable to set document class."));
                return;
        }
@@ -2444,6 +2772,28 @@ void GuiDocument::biblioChanged()
 }
 
 
+void GuiDocument::checkPossibleCiteEngines()
+{
+       // Check if the class provides a specific engine,
+       // and if so, enforce this.
+       string force_engine;
+       if (documentClass().provides("natbib")
+           || documentClass().provides("natbib-internal"))
+               force_engine = "natbib";
+       else if (documentClass().provides("jurabib"))
+               force_engine = "jurabib";
+       else if (documentClass().provides("biblatex"))
+               force_engine = "biblatex";
+       else if (documentClass().provides("biblatex-natbib"))
+               force_engine = "biblatex-natbib";
+
+       if (!force_engine.empty())
+               biblioModule->citeEngineCO->setCurrentIndex(
+                       biblioModule->citeEngineCO->findData(toqstr(force_engine)));
+       biblioModule->citeEngineCO->setEnabled(force_engine.empty());
+}
+
+
 void GuiDocument::rescanBibFiles()
 {
        if (isBiblatex())
@@ -2649,6 +2999,7 @@ void GuiDocument::modulesToParams(BufferParams & bp)
        int const srows = modules_sel_model_.rowCount();
        for (int i = 0; i < srows; ++i)
                bp.addLayoutModule(modules_sel_model_.getIDString(i));
+       updateSelectedModules();
 
        // update the list of removed modules
        bp.clearRemovedModules();
@@ -2678,7 +3029,8 @@ void GuiDocument::modulesChanged()
 {
        modulesToParams(bp_);
 
-       if (applyPB->isEnabled() && (nonModuleChanged_ || shellescapeChanged_)) {
+       if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()
+           && (nonModuleChanged_ || shellescapeChanged_)) {
                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."),
@@ -2701,18 +3053,28 @@ void GuiDocument::updateModuleInfo()
        //Module description
        bool const focus_on_selected = selectionManager->selectedFocused();
        QAbstractItemView * lv;
-       if (focus_on_selected)
+       bool category = false;
+       if (focus_on_selected) {
                lv = modulesModule->selectedLV;
-       else
+               category = true;
+       } else
                lv = modulesModule->availableLV;
        if (lv->selectionModel()->selectedIndexes().isEmpty()) {
                modulesModule->infoML->document()->clear();
                return;
        }
        QModelIndex const & idx = lv->selectionModel()->currentIndex();
-       GuiIdListModel const & id_model =
-                       focus_on_selected  ? modules_sel_model_ : modules_av_model_;
-       string const modName = id_model.getIDString(idx.row());
+
+       if (!focus_on_selected
+           && modules_av_model_.itemFromIndex(idx)->hasChildren()) {
+               // This is a category header
+               modulesModule->infoML->document()->clear();
+               return;
+       }
+
+       string const modName = focus_on_selected ?
+                               modules_sel_model_.getIDString(idx.row())
+                             : fromqstr(modules_av_model_.data(idx, Qt::UserRole).toString());
        docstring desc = getModuleDescription(modName);
 
        LayoutModuleList const & provmods = bp_.baseClass()->providedModules();
@@ -2722,11 +3084,14 @@ void GuiDocument::updateModuleInfo()
                desc += _("Module provided by document class.");
        }
 
-       docstring cat = getModuleCategory(modName);
-       if (!cat.empty()) {
-               if (!desc.empty())
-                       desc += "\n";
-               desc += bformat(_("Category: %1$s."), cat);
+       if (category) {
+               docstring cat = getModuleCategory(modName);
+               if (!cat.empty()) {
+                       if (!desc.empty())
+                               desc += "\n";
+                       desc += bformat(_("<p><b>Category:</b> %1$s.</p>"),
+                                       translateIfPossible(cat));
+               }
        }
 
        vector<string> pkglist = getPackageList(modName);
@@ -2734,7 +3099,7 @@ void GuiDocument::updateModuleInfo()
        if (!pkgdesc.empty()) {
                if (!desc.empty())
                        desc += "\n";
-               desc += bformat(_("Package(s) required: %1$s."), pkgdesc);
+               desc += bformat(_("<p><b>Package(s) required:</b> %1$s.</p>"), pkgdesc);
        }
 
        pkglist = getRequiredList(modName);
@@ -2743,7 +3108,7 @@ void GuiDocument::updateModuleInfo()
                pkgdesc = formatStrVec(reqdescs, _("or"));
                if (!desc.empty())
                        desc += "\n";
-               desc += bformat(_("Modules required: %1$s."), pkgdesc);
+               desc += bformat(_("<p><b>Modules required:</b> %1$s.</p>"), pkgdesc);
        }
 
        pkglist = getExcludedList(modName);
@@ -2752,16 +3117,20 @@ void GuiDocument::updateModuleInfo()
                pkgdesc = formatStrVec(reqdescs, _( "and"));
                if (!desc.empty())
                        desc += "\n";
-               desc += bformat(_("Modules excluded: %1$s."), pkgdesc);
+               desc += bformat(_("<p><b>Modules excluded:</b> %1$s.</p>"), pkgdesc);
        }
 
+       if (!desc.empty())
+               desc += "\n";
+       desc += bformat(_("<p><b>Filename:</b> <tt>%1$s.module</tt>.</p>"), from_utf8(modName));
+
        if (!isModuleAvailable(modName)) {
                if (!desc.empty())
                        desc += "\n";
-               desc += _("WARNING: Some required packages are unavailable!");
+               desc += _("<p><font color=red><b>WARNING: Some required packages are unavailable!</b></font></p>");
        }
 
-       modulesModule->infoML->document()->setPlainText(toqstr(desc));
+       modulesModule->infoML->document()->setHtml(toqstr(desc));
 }
 
 
@@ -2795,6 +3164,45 @@ void GuiDocument::updateNumbering()
 }
 
 
+void GuiDocument::getTableStyles()
+{
+       // We look for lyx files in the subdirectory dir of
+       //   1) user_lyxdir
+       //   2) build_lyxdir (if not empty)
+       //   3) system_lyxdir
+       // in this order. Files with a given sub-hierarchy will
+       // only be listed once.
+       // We also consider i18n subdirectories and store them separately.
+       QStringList dirs;
+
+       // The three locations to look at.
+       string const user = addPath(package().user_support().absFileName(), "tabletemplates");
+       string const build = addPath(package().build_support().absFileName(), "tabletemplates");
+       string const system = addPath(package().system_support().absFileName(), "tabletemplates");
+
+       dirs << toqstr(user)
+            << toqstr(build)
+            << toqstr(system);
+
+       for (int i = 0; i < dirs.size(); ++i) {
+               QString const dir = dirs.at(i);
+               QDirIterator it(dir, QDir::Files, QDirIterator::Subdirectories);
+               while (it.hasNext()) {
+                       QString fn = QFileInfo(it.next()).fileName();
+                       if (!fn.endsWith(".lyx") || fn.contains("_1x"))
+                               continue;
+                       QString data = fn.left(fn.lastIndexOf(".lyx"));
+                       QString guiname = data;
+                       guiname = toqstr(translateIfPossible(qstring_to_ucs4(guiname.replace('_', ' '))));
+                       QString relpath = toqstr(makeRelPath(qstring_to_ucs4(fn),
+                                                            qstring_to_ucs4(dir)));
+                       if (textLayoutModule->tableStyleCO->findData(data) == -1)
+                               textLayoutModule->tableStyleCO->addItem(guiname, data);
+               }
+       }
+}
+
+
 void GuiDocument::updateDefaultFormat()
 {
        if (!bufferview())
@@ -2805,7 +3213,7 @@ void GuiDocument::updateDefaultFormat()
        int const idx = latexModule->classCO->currentIndex();
        if (idx >= 0) {
                string const classname = fromqstr(latexModule->classCO->getData(idx));
-               param_copy.setBaseClass(classname);
+               param_copy.setBaseClass(classname, buffer().layoutPos());
                param_copy.makeDocumentClass(true);
        }
        outputModule->defaultFormatCO->blockSignals(true);
@@ -2884,34 +3292,27 @@ void GuiDocument::applyView()
        indicesModule->apply(bp_);
 
        // language & quotes
-       if (langModule->defaultencodingRB->isChecked()) {
-               bp_.inputenc = "auto";
-       } else {
-               int i = langModule->encodingCO->currentIndex();
-               if (i == 0)
-                       bp_.inputenc = "default";
-               else {
-                       QString const enc_gui =
-                               langModule->encodingCO->currentText();
-                       Encodings::const_iterator it = encodings.begin();
-                       Encodings::const_iterator const end = encodings.end();
-                       bool found = false;
-                       for (; it != end; ++it) {
-                               if (qt_(it->guiName()) == enc_gui &&
-                                   !it->unsafe()) {
-                                       bp_.inputenc = it->name();
-                                       found = true;
-                                       break;
-                               }
-                       }
-                       if (!found) {
-                               // should not happen
-                               lyxerr << "GuiDocument::apply: Unknown encoding! Resetting to default" << endl;
-                               bp_.inputenc = "default";
-                       }
+       switch (langModule->encodingCO->currentIndex()) {
+               case EncodingSets::unicode: {
+                       bp_.inputenc = fromqstr(langModule->unicodeEncodingCO->itemData(
+                               langModule->unicodeEncodingCO->currentIndex()).toString());
+                       break;
+               }
+               case EncodingSets::legacy: {
+                       bp_.inputenc = "auto-legacy";
+                       if (langModule->noInputencCB->isChecked())
+                               bp_.inputenc = "auto-legacy-plain";
+                       break;
+               }
+               case EncodingSets::custom: {
+                       bp_.inputenc = fromqstr(langModule->customEncodingCO->itemData(
+                               langModule->customEncodingCO->currentIndex()).toString());
+                       break;
                }
+               default:
+                       // this should never happen
+                       bp_.inputenc = "utf8";
        }
-
        bp_.quotes_style = (InsetQuotesParams::QuoteStyle) langModule->quoteStyleCO->itemData(
                langModule->quoteStyleCO->currentIndex()).toInt();
        bp_.dynamic_quotes = langModule->dynamicQuotesCB->isChecked();
@@ -2948,6 +3349,8 @@ void GuiDocument::applyView()
                bp_.tocdepth = numberingModule->tocSL->value();
                bp_.secnumdepth = numberingModule->depthSL->value();
        }
+       bp_.use_lineno = numberingModule->linenoCB->isChecked();
+       bp_.lineno_opts = fromqstr(numberingModule->linenoLE->text());
 
        // bullets
        bp_.user_defined_bullet(0) = bulletsModule->bullet(0);
@@ -2963,7 +3366,7 @@ void GuiDocument::applyView()
        int idx = latexModule->classCO->currentIndex();
        if (idx >= 0) {
                string const classname = fromqstr(latexModule->classCO->getData(idx));
-               bp_.setBaseClass(classname);
+               bp_.setBaseClass(classname, buffer().layoutPos());
        }
 
        // Modules
@@ -2977,17 +3380,19 @@ void GuiDocument::applyView()
                if (!item)
                        continue;
                int row = mathsModule->packagesTW->row(item);
-               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1);
+
+               QRadioButton * rb =
+                       (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
                if (rb->isChecked()) {
                        bp_.use_package(it->first, BufferParams::package_auto);
                        continue;
                }
-               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2);
+               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
                if (rb->isChecked()) {
                        bp_.use_package(it->first, BufferParams::package_on);
                        continue;
                }
-               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3);
+               rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
                if (rb->isChecked())
                        bp_.use_package(it->first, BufferParams::package_off);
        }
@@ -3111,6 +3516,8 @@ void GuiDocument::applyView()
                        break;
                }
        }
+       bp_.tablestyle = fromqstr(textLayoutModule->tableStyleCO->itemData(
+                                     textLayoutModule->tableStyleCO->currentIndex()).toString());
 
        bp_.options =
                fromqstr(latexModule->optionsLE->text());
@@ -3135,8 +3542,9 @@ void GuiDocument::applyView()
        bp_.maintain_unincluded_children =
                masterChildModule->maintainAuxCB->isChecked();
 
-       // Float Placement
-       bp_.float_placement = floatModule->get();
+       // Float Settings
+       bp_.float_placement = floatModule->getPlacement();
+       bp_.float_alignment = floatModule->getAlignment();
 
        // Listings
        // text should have passed validation
@@ -3210,7 +3618,7 @@ void GuiDocument::applyView()
                fromqstr(fontModule->cjkFontLE->text());
 
        bp_.use_microtype = fontModule->microtypeCB->isChecked();
-       bp_.use_dash_ligatures = fontModule->dashesCB->isChecked();
+       bp_.use_dash_ligatures = !fontModule->dashesCB->isChecked();
 
        bp_.fonts_sans_scale[nontexfonts] = fontModule->scaleSansSB->value();
        bp_.fonts_sans_scale[!nontexfonts] = fontModule->font_sf_scale;
@@ -3317,7 +3725,7 @@ void GuiDocument::paramsToDialog()
        latexModule->refstyleCB->setChecked(bp_.use_refstyle);
 
        // biblio
-       string const cite_engine = bp_.citeEngine().list().front();
+       string const cite_engine = bp_.citeEngine();
 
        biblioModule->citeEngineCO->setCurrentIndex(
                biblioModule->citeEngineCO->findData(toqstr(cite_engine)));
@@ -3325,6 +3733,8 @@ void GuiDocument::paramsToDialog()
        updateEngineType(documentClass().opt_enginetype(),
                bp_.citeEngineType());
 
+       checkPossibleCiteEngines();
+
        biblioModule->citeStyleCO->setCurrentIndex(
                biblioModule->citeStyleCO->findData(bp_.citeEngineType()));
 
@@ -3395,35 +3805,9 @@ void GuiDocument::paramsToDialog()
                langModule->quoteStyleCO->findData(bp_.quotes_style));
        langModule->dynamicQuotesCB->setChecked(bp_.dynamic_quotes);
 
-       bool default_enc = true;
-       if (bp_.inputenc != "auto") {
-               default_enc = false;
-               if (bp_.inputenc == "default") {
-                       langModule->encodingCO->setCurrentIndex(0);
-               } else {
-                       string enc_gui;
-                       Encodings::const_iterator it = encodings.begin();
-                       Encodings::const_iterator const end = encodings.end();
-                       for (; it != end; ++it) {
-                               if (it->name() == bp_.inputenc &&
-                                   !it->unsafe()) {
-                                       enc_gui = it->guiName();
-                                       break;
-                               }
-                       }
-                       int const i = langModule->encodingCO->findText(
-                                       qt_(enc_gui));
-                       if (i >= 0)
-                               langModule->encodingCO->setCurrentIndex(i);
-                       else
-                               // unknown encoding. Set to default.
-                               default_enc = true;
-               }
-       }
-       langModule->defaultencodingRB->setChecked(default_enc);
-       langModule->otherencodingRB->setChecked(!default_enc);
+       // LaTeX input encoding: set after the fonts (see below)
 
-       int const p = langModule->languagePackageCO->findData(toqstr(bp_.lang_package));
+       int p = langModule->languagePackageCO->findData(toqstr(bp_.lang_package));
        if (p == -1) {
                langModule->languagePackageCO->setCurrentIndex(
                          langModule->languagePackageCO->findData("custom"));
@@ -3473,6 +3857,11 @@ void GuiDocument::paramsToDialog()
                numberingModule->tocTW->clear();
        }
 
+       numberingModule->linenoCB->setChecked(bp_.use_lineno);
+       numberingModule->linenoLE->setEnabled(bp_.use_lineno);
+       numberingModule->linenoLA->setEnabled(bp_.use_lineno);
+       numberingModule->linenoLE->setText(toqstr(bp_.lineno_opts));
+
        // bullets
        bulletsModule->setBullet(0, bp_.user_defined_bullet(0));
        bulletsModule->setBullet(1, bp_.user_defined_bullet(1));
@@ -3520,17 +3909,20 @@ void GuiDocument::paramsToDialog()
                int row = mathsModule->packagesTW->row(item);
                switch (bp_.use_package(it->first)) {
                        case BufferParams::package_off: {
-                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3);
+                               QRadioButton * rb =
+                                       (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
                                rb->setChecked(true);
                                break;
                        }
                        case BufferParams::package_on: {
-                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2);
+                               QRadioButton * rb =
+                                       (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
                                rb->setChecked(true);
                                break;
                        }
                        case BufferParams::package_auto: {
-                               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1);
+                               QRadioButton * rb =
+                                       (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
                                rb->setChecked(true);
                                break;
                        }
@@ -3557,6 +3949,9 @@ void GuiDocument::paramsToDialog()
                        bp_.spacing().getValueAsString());
        }
        setLSpacing(nitem);
+       int ts = textLayoutModule->tableStyleCO->findData(toqstr(bp_.tablestyle));
+       if (ts != -1)
+               textLayoutModule->tableStyleCO->setCurrentIndex(ts);
 
        if (bp_.paragraph_separation == BufferParams::ParagraphIndentSeparation) {
                textLayoutModule->indentRB->setChecked(true);
@@ -3661,7 +4056,8 @@ void GuiDocument::paramsToDialog()
                bp_.maintain_unincluded_children);
 
        // Float Settings
-       floatModule->set(bp_.float_placement);
+       floatModule->setPlacement(bp_.float_placement);
+       floatModule->setAlignment(bp_.float_alignment);
 
        // ListingsSettings
        // break listings_params to multiple lines
@@ -3672,14 +4068,14 @@ void GuiDocument::paramsToDialog()
        if (nn >= 0)
                listingsModule->packageCO->setCurrentIndex(nn);
 
-
        // Fonts
-       // some languages only work with polyglossia/XeTeX
+       // some languages only work with Polyglossia (which requires non-TeX fonts)
        Language const * lang = lyx::languages.getLanguage(
                fromqstr(langModule->languageCO->itemData(
                        langModule->languageCO->currentIndex()).toString()));
        bool const need_fontspec =
-               lang->babel().empty() && !lang->polyglossia().empty();
+               lang->babel().empty() && !lang->polyglossia().empty()
+               && lang->requires() != "CJK" && lang->requires() != "japanese";
        bool const os_fonts_available =
                bp_.baseClass()->outputType() == lyx::LATEX
                && LaTeXFeatures::isAvailable("fontspec");
@@ -3745,7 +4141,7 @@ void GuiDocument::paramsToDialog()
                fontModule->cjkFontLE->setText(QString());
 
        fontModule->microtypeCB->setChecked(bp_.use_microtype);
-       fontModule->dashesCB->setChecked(bp_.use_dash_ligatures);
+       fontModule->dashesCB->setChecked(!bp_.use_dash_ligatures);
 
        fontModule->fontScCB->setChecked(bp_.fonts_expert_sc);
        fontModule->fontOsfCB->setChecked(bp_.fonts_old_figures);
@@ -3758,15 +4154,20 @@ void GuiDocument::paramsToDialog()
        if (nn >= 0)
                fontModule->fontsDefaultCO->setCurrentIndex(nn);
 
-       if (bp_.fontenc == "global" || bp_.fontenc == "default") {
+       if (bp_.fontenc == "auto" || bp_.fontenc == "default") {
                fontModule->fontencCO->setCurrentIndex(
                        fontModule->fontencCO->findData(toqstr(bp_.fontenc)));
                fontModule->fontencLE->setEnabled(false);
        } else {
-               fontModule->fontencCO->setCurrentIndex(1);
+               fontModule->fontencCO->setCurrentIndex(
+                                       fontModule->fontencCO->findData("custom"));
                fontModule->fontencLE->setText(toqstr(bp_.fontenc));
        }
 
+       // LaTeX input encoding
+       // Set after fonts because non-tex fonts override "\inputencoding".
+       inputencodingToDialog();
+
        // Formats
        // This must be set _after_ fonts since updateDefaultFormat()
        // checks osFontsCB settings.
@@ -3909,11 +4310,40 @@ void GuiDocument::updateAvailableModules()
        modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
                        return 0 < b.name.localeAwareCompare(a.name);
                });
+       QIcon user_icon(getPixmap("images/", "lyxfiles-user", "svgz,png"));
+       QIcon system_icon(getPixmap("images/", "lyxfiles-system", "svgz,png"));
        int i = 0;
+       QFont catfont;
+       catfont.setBold(true);
+       QBrush unavbrush;
+       unavbrush.setColor(Qt::gray);
        for (modInfoStruct const & m : modInfoList) {
-               modules_av_model_.insertRow(i, m.name, m.id, m.description);
-               ++i;
+               QStandardItem * item = new QStandardItem();
+               QStandardItem * catItem = new QStandardItem();
+               QString const catname = m.category;
+               QList<QStandardItem *> fcats = modules_av_model_.findItems(catname, Qt::MatchExactly);
+               if (!fcats.empty())
+                       catItem = fcats.first();
+               else {
+                       catItem->setText(catname);
+                       catItem->setFont(catfont);
+                       modules_av_model_.insertRow(i, catItem);
+                       ++i;
+               }
+               item->setEditable(false);
+               catItem->setEditable(false);
+               item->setData(m.name, Qt::DisplayRole);
+               if (m.missingreqs)
+                       item->setForeground(unavbrush);
+               item->setData(toqstr(m.id), Qt::UserRole);
+               item->setData(m.description, Qt::ToolTipRole);
+               if (m.local)
+                       item->setIcon(user_icon);
+               else
+                       item->setIcon(system_icon);
+               catItem->appendRow(item);
        }
+       modules_av_model_.sort(0);
 }
 
 
@@ -3982,6 +4412,12 @@ bool GuiDocument::isBiblatex() const
                biblioModule->citeEngineCO->itemData(
                                biblioModule->citeEngineCO->currentIndex()).toString();
 
+       // this can happen if the cite engine is unknown, which can happen
+       // if one is using a file that came from someone else, etc. in that
+       // case, we crash if we proceed.
+       if (engine.isEmpty())
+           return false;
+
        return theCiteEnginesList[fromqstr(engine)]->getCiteFramework() == "biblatex";
 }
 
@@ -4133,7 +4569,7 @@ void GuiDocument::updateContents()
 
 void GuiDocument::useClassDefaults()
 {
-       if (applyPB->isEnabled()) {
+       if (buttonBox->button(QDialogButtonBox::Apply)->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."),
@@ -4144,7 +4580,7 @@ void GuiDocument::useClassDefaults()
 
        int idx = latexModule->classCO->currentIndex();
        string const classname = fromqstr(latexModule->classCO->getData(idx));
-       if (!bp_.setBaseClass(classname)) {
+       if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
                Alert::error(_("Error"), _("Unable to set document class."));
                return;
        }
@@ -4167,6 +4603,8 @@ bool GuiDocument::isValid()
        return
                validateListingsParameters().isEmpty() &&
                localLayout->isValid() &&
+               !localLayout->editing() &&
+               !preambleModule->editing() &&
                (
                        // if we're asking for skips between paragraphs
                        !textLayoutModule->skipRB->isChecked() ||
@@ -4255,6 +4693,8 @@ GuiDocument::makeModuleInfo(LayoutModuleList const & mods)
                else {
                        m.id = name;
                        m.name = toqstr(name + " (") + qt_("Not Found") + toqstr(")");
+                       m.local = false;
+                       m.missingreqs = true;
                }
                mInfo.push_back(m);
        }
@@ -4302,10 +4742,9 @@ void GuiDocument::dispatchParams()
        // 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, &buffer());
-
+       // We need to load the master before we formally update the params,
+       // since otherwise we run updateBuffer, etc, before the child's master
+       // has been set.
        if (!params().master.empty()) {
                FileName const master_file = support::makeAbsPath(params().master,
                           support::onlyPath(buffer().absFileName()));
@@ -4327,6 +4766,10 @@ void GuiDocument::dispatchParams()
                }
        }
 
+       // 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, &buffer());
+
        // Generate the colours requested by each new branch.
        BranchList & branchlist = params().branchlist();
        if (!branchlist.empty()) {
@@ -4447,18 +4890,29 @@ GuiDocument::modInfoStruct GuiDocument::modInfo(LyXModule const & mod)
        // change requires a lot of others
        modInfoStruct m;
        m.id = mod.getID();
-       m.name = toqstr(translateIfPossible(from_utf8(mod.getName())));
+       QString const guiname = toqstr(translateIfPossible(from_utf8(mod.getName())));
+       m.missingreqs = !isModuleAvailable(mod.getID());
+       if (m.missingreqs) {
+               m.name = QString(qt_("%1 (missing req.)")).arg(guiname);
+       } else
+               m.name = guiname;
+       m.category = mod.category().empty() ? qt_("Miscellaneous")
+                                           : toqstr(translateIfPossible(from_utf8(mod.category())));
        QString desc = toqstr(translateIfPossible(from_utf8(mod.getDescription())));
        // Find the first sentence of the description
        QTextBoundaryFinder bf(QTextBoundaryFinder::Sentence, desc);
        int pos = bf.toNextBoundary();
        if (pos > 0)
                desc.truncate(pos);
-       QString modulename = QString(qt_("(Module name: %1)")).arg(toqstr(m.id));
-       // Tooltip is the desc followed by the module name
-       m.description = QString("%1<i>%2</i>")
+       m.local = mod.isLocal();
+       QString const mtype = m.local ? qt_("personal module") : qt_("distributed module");
+       QString modulename = QString(qt_("<b>Module name:</b> <i>%1</i> (%2)")).arg(toqstr(m.id)).arg(mtype);
+       // Tooltip is the desc followed by the module name and the type
+       m.description = QString("%1%2")
                .arg(desc.isEmpty() ? QString() : QString("<p>%1</p>").arg(desc),
                     modulename);
+       if (m.missingreqs)
+               m.description += QString("<p>%1</p>").arg(qt_("<b>Note:</b> Some requirements for this module are missing!"));
        return m;
 }
 
@@ -4467,8 +4921,7 @@ void GuiDocument::loadModuleInfo()
 {
        moduleNames_.clear();
        for (LyXModule const & mod : theModuleList)
-               if (mod.category().substr(0, 8) != "Citation")
-                       moduleNames_.push_back(modInfo(mod));
+               moduleNames_.push_back(modInfo(mod));
 }
 
 
@@ -4534,12 +4987,21 @@ void GuiDocument::allPackagesNot()
 void GuiDocument::allPackages(int col)
 {
        for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) {
-               QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col);
+               QRadioButton * rb =
+                       (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col)->layout()->itemAt(0)->widget();
                rb->setChecked(true);
        }
 }
 
 
+void GuiDocument::linenoToggled(bool on)
+{
+       numberingModule->linenoLE->setEnabled(on);
+       numberingModule->linenoLA->setEnabled(on);
+}
+
+
+
 Dialog * createGuiDocument(GuiView & lv) { return new GuiDocument(lv); }