]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiDocument.cpp
bd87d9a38e09cca24fa7e539b8ce43fda8253702
[lyx.git] / src / frontends / qt / GuiDocument.cpp
1 /**
2  * \file GuiDocument.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Edwin Leuven
7  * \author Richard Kimberly Heck (modules)
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiDocument.h"
15
16 #include "BulletsModule.h"
17 #include "CategorizedCombo.h"
18 #include "FancyLineEdit.h"
19 #include "GuiApplication.h"
20 #include "GuiBranches.h"
21 #include "GuiIndices.h"
22 #include "GuiView.h"
23 #include "GuiSelectionManager.h"
24 #include "Validator.h"
25
26 #include "LayoutFile.h"
27 #include "BranchList.h"
28 #include "buffer_funcs.h"
29 #include "Buffer.h"
30 #include "BufferView.h"
31 #include "CiteEnginesList.h"
32 #include "Color.h"
33 #include "ColorCache.h"
34 #include "Converter.h"
35 #include "Cursor.h"
36 #include "Encoding.h"
37 #include "FloatPlacement.h"
38 #include "Format.h"
39 #include "FuncRequest.h"
40 #include "IndicesList.h"
41 #include "Language.h"
42 #include "LaTeXFeatures.h"
43 #include "LaTeXFonts.h"
44 #include "Layout.h"
45 #include "LayoutEnums.h"
46 #include "LayoutModuleList.h"
47 #include "LyXRC.h"
48 #include "ModuleList.h"
49 #include "PDFOptions.h"
50 #include "qt_helpers.h"
51 #include "Session.h"
52 #include "Spacing.h"
53 #include "TextClass.h"
54 #include "Undo.h"
55 #include "VSpace.h"
56
57 #include "insets/InsetListingsParams.h"
58 #include "insets/InsetQuotes.h"
59
60 #include "support/debug.h"
61 #include "support/docstream.h"
62 #include "support/FileName.h"
63 #include "support/filetools.h"
64 #include "support/gettext.h"
65 #include "support/lassert.h"
66 #include "support/lstrings.h"
67 #include "support/Package.h"
68 #include "support/TempFile.h"
69
70 #include "frontends/alert.h"
71
72 #include <QAbstractItemModel>
73 #include <QButtonGroup>
74 #include <QColor>
75 #include <QCloseEvent>
76 #include <QDirIterator>
77 #include <QFontDatabase>
78 #include <QHeaderView>
79 #include <QPixmap>
80 #include <QScrollBar>
81 #include <QTextBoundaryFinder>
82 #include <QTextCursor>
83
84 #include <sstream>
85 #include <vector>
86
87
88 // a style sheet for color frame widgets
89 static inline QString colorFrameStyleSheet(QColor const & bgColor)
90 {
91         if (bgColor.isValid()) {
92                 QString rc = QLatin1String("background-color:");
93                 rc += bgColor.name();
94                 return rc;
95         }
96         return QString();
97 }
98
99
100 using namespace std;
101 using namespace lyx::support;
102
103
104 namespace {
105
106 char const * const tex_graphics[] =
107 {
108         "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
109         "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
110         "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
111         "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
112         "xetex", "none", ""
113 };
114
115
116 char const * const tex_graphics_gui[] =
117 {
118         N_("Default"), "dvialw", "DviLaser", "dvipdf", "DVIPDFM", "DVIPDFMx",
119         "Dvips", "DVIPSONE", "DVItoPS", "DVIWIN", "DVIWindo", "dvi2ps", "EmTeX",
120         "LN", "OzTeX", "pctexhp", "pctexps", "pctexwin", "PCTeX32", "pdfTeX",
121         "psprint", "pubps", "tcidvi", "Textures", "TrueTeX", "VTeX", "xdvi",
122         "XeTeX", N_("None"), ""
123 };
124
125
126 char const * backref_opts[] =
127 {
128         "false", "section", "slide", "page", ""
129 };
130
131
132 char const * backref_opts_gui[] =
133 {
134         N_("Off"), N_("Section"), N_("Slide"), N_("Page"), ""
135 };
136
137
138 char const * lst_packages[] =
139 {
140         "Listings", "Minted", ""
141 };
142
143
144 vector<string> engine_types_;
145 vector<pair<string, QString> > pagestyles;
146
147 QMap<QString, QString> rmfonts_;
148 QMap<QString, QString> sffonts_;
149 QMap<QString, QString> ttfonts_;
150 QMap<QString, QString> mathfonts_;
151
152 enum EncodingSets {
153         unicode = 0,
154         legacy = 1,
155         custom = 2
156 };
157
158 lyx::RGBColor set_backgroundcolor;
159 bool is_backgroundcolor;
160 lyx::RGBColor set_fontcolor;
161 bool is_fontcolor;
162 lyx::RGBColor set_notefontcolor;
163 bool is_notefontcolor;
164 lyx::RGBColor set_boxbgcolor;
165 bool is_boxbgcolor;
166 bool forced_fontspec_activation;
167
168 } // anonymous namespace
169
170 namespace lyx {
171
172 namespace {
173 // used when sorting the textclass list.
174 class less_textclass_avail_desc
175 {
176 public:
177         bool operator()(string const & lhs, string const & rhs) const
178         {
179                 // Ordering criteria:
180                 //   1. Availability of text class
181                 //   2. Description (lexicographic)
182                 LayoutFile const & tc1 = LayoutFileList::get()[lhs];
183                 LayoutFile const & tc2 = LayoutFileList::get()[rhs];
184                 int const order = compare_no_case(
185                         translateIfPossible(from_utf8(tc1.description())),
186                         translateIfPossible(from_utf8(tc2.description())));
187                 return (tc1.isTeXClassAvailable() && !tc2.isTeXClassAvailable()) ||
188                         (tc1.isTeXClassAvailable() == tc2.isTeXClassAvailable() && order < 0);
189         }
190 };
191
192 } // namespace
193
194 namespace frontend {
195 namespace {
196
197 vector<string> getRequiredList(string const & modName)
198 {
199         LyXModule const * const mod = theModuleList[modName];
200         if (!mod)
201                 return vector<string>(); //empty such thing
202         return mod->getRequiredModules();
203 }
204
205
206 vector<string> getExcludedList(string const & modName)
207 {
208         LyXModule const * const mod = theModuleList[modName];
209         if (!mod)
210                 return vector<string>(); //empty such thing
211         return mod->getExcludedModules();
212 }
213
214
215 docstring getModuleCategory(string const & modName)
216 {
217         LyXModule const * const mod = theModuleList[modName];
218         if (!mod)
219                 return docstring();
220         return from_utf8(mod->category());
221 }
222
223
224 docstring getModuleDescription(string const & modName)
225 {
226         LyXModule const * const mod = theModuleList[modName];
227         if (!mod)
228                 return _("Module not found!");
229         // FIXME Unicode
230         return translateIfPossible(from_utf8(mod->getDescription()));
231 }
232
233
234 vector<string> getPackageList(string const & modName)
235 {
236         LyXModule const * const mod = theModuleList[modName];
237         if (!mod)
238                 return vector<string>(); //empty such thing
239         return mod->getPackageList();
240 }
241
242
243 bool isModuleAvailable(string const & modName)
244 {
245         LyXModule const * const mod = theModuleList[modName];
246         if (!mod)
247                 return false;
248         return mod->isAvailable();
249 }
250
251 } // anonymous namespace
252
253
254 /////////////////////////////////////////////////////////////////////
255 //
256 // ModuleSelectionManager
257 //
258 /////////////////////////////////////////////////////////////////////
259
260 /// SelectionManager for use with modules
261 class ModuleSelectionManager : public GuiSelectionManager
262 {
263 public:
264         ///
265         ModuleSelectionManager(QObject * parent,
266                                QTreeView * availableLVarg,
267                                QTreeView * selectedLVarg,
268                                QPushButton * addPBarg,
269                                QPushButton * delPBarg,
270                                QPushButton * upPBarg,
271                                QPushButton * downPBarg,
272                                QStandardItemModel * availableModelarg,
273                                GuiIdListModel * selectedModelarg,
274                                GuiDocument const * container)
275                 : GuiSelectionManager(parent, availableLVarg, selectedLVarg, addPBarg, delPBarg,
276                                                           upPBarg, downPBarg, availableModelarg, selectedModelarg),
277                   container_(container)
278                 {}
279         ///
280         void updateProvidedModules(LayoutModuleList const & pm)
281                         { provided_modules_ = pm.list(); }
282         ///
283         void updateExcludedModules(LayoutModuleList const & em)
284                         { excluded_modules_ = em.list(); }
285 private:
286         ///
287         void updateAddPB() override;
288         ///
289         void updateUpPB() override;
290         ///
291         void updateDownPB() override;
292         ///
293         void updateDelPB() override;
294         /// returns availableModel as a GuiIdListModel
295         QStandardItemModel * getAvailableModel()
296         {
297                 return dynamic_cast<QStandardItemModel *>(availableModel);
298         }
299         /// returns selectedModel as a GuiIdListModel
300         GuiIdListModel * getSelectedModel()
301         {
302                 return dynamic_cast<GuiIdListModel *>(selectedModel);
303         }
304         /// keeps a list of the modules the text class provides
305         list<string> provided_modules_;
306         /// similarly...
307         list<string> excluded_modules_;
308         ///
309         GuiDocument const * container_;
310 };
311
312 void ModuleSelectionManager::updateAddPB()
313 {
314         int const arows = availableModel->rowCount();
315         QModelIndexList const avail_sels =
316                         availableLV->selectionModel()->selectedRows(0);
317
318         // disable if there aren't any modules (?), if none of them is chosen
319         // in the dialog, or if the chosen one is already selected for use.
320         if (arows == 0 || avail_sels.isEmpty() || isSelected(avail_sels.first())) {
321                 addPB->setEnabled(false);
322                 return;
323         }
324
325         QModelIndex const & idx = availableLV->selectionModel()->currentIndex();
326         
327         if (!idx.isValid())
328                 return;
329
330         if (getAvailableModel()->itemFromIndex(idx)->hasChildren()) {
331                 // This is a category header
332                 addPB->setEnabled(false);
333                 return;
334         }
335
336         string const modname = fromqstr(getAvailableModel()->data(idx, Qt::UserRole).toString());
337
338         bool const enable =
339                 container_->params().layoutModuleCanBeAdded(modname);
340         addPB->setEnabled(enable);
341 }
342
343
344 void ModuleSelectionManager::updateDownPB()
345 {
346         int const srows = selectedModel->rowCount();
347         if (srows == 0) {
348                 downPB->setEnabled(false);
349                 return;
350         }
351         QModelIndex const & curidx = selectedLV->selectionModel()->currentIndex();
352         int const curRow = curidx.row();
353         if (curRow < 0 || curRow >= srows - 1) { // invalid or last item
354                 downPB->setEnabled(false);
355                 return;
356         }
357
358         // determine whether immediately succeeding element requires this one
359         string const curmodname = getSelectedModel()->getIDString(curRow);
360         string const nextmodname = getSelectedModel()->getIDString(curRow + 1);
361
362         vector<string> reqs = getRequiredList(nextmodname);
363
364         // if it doesn't require anything....
365         if (reqs.empty()) {
366                 downPB->setEnabled(true);
367                 return;
368         }
369
370         // Enable it if this module isn't required.
371         // FIXME This should perhaps be more flexible and check whether, even
372         // if the next one is required, there is also an earlier one that will do.
373         downPB->setEnabled(
374                         find(reqs.begin(), reqs.end(), curmodname) == reqs.end());
375 }
376
377 void ModuleSelectionManager::updateUpPB()
378 {
379         int const srows = selectedModel->rowCount();
380         if (srows == 0) {
381                 upPB->setEnabled(false);
382                 return;
383         }
384
385         QModelIndex const & curIdx = selectedLV->selectionModel()->currentIndex();
386         int curRow = curIdx.row();
387         if (curRow <= 0 || curRow > srows - 1) { // first item or invalid
388                 upPB->setEnabled(false);
389                 return;
390         }
391         string const curmodname = getSelectedModel()->getIDString(curRow);
392
393         // determine whether immediately preceding element is required by this one
394         vector<string> reqs = getRequiredList(curmodname);
395
396         // if this one doesn't require anything....
397         if (reqs.empty()) {
398                 upPB->setEnabled(true);
399                 return;
400         }
401
402
403         // Enable it if the preceding module isn't required.
404         // NOTE This is less flexible than it might be. We could check whether, even
405         // if the previous one is required, there is an earlier one that would do.
406         string const premod = getSelectedModel()->getIDString(curRow - 1);
407         upPB->setEnabled(find(reqs.begin(), reqs.end(), premod) == reqs.end());
408 }
409
410 void ModuleSelectionManager::updateDelPB()
411 {
412         int const srows = selectedModel->rowCount();
413         if (srows == 0) {
414                 deletePB->setEnabled(false);
415                 return;
416         }
417
418         QModelIndex const & curidx =
419                 selectedLV->selectionModel()->currentIndex();
420         int const curRow = curidx.row();
421         if (curRow < 0 || curRow >= srows) { // invalid index?
422                 deletePB->setEnabled(false);
423                 return;
424         }
425
426         string const curmodname = getSelectedModel()->getIDString(curRow);
427
428         // We're looking here for a reason NOT to enable the button. If we
429         // find one, we disable it and return. If we don't, we'll end up at
430         // the end of the function, and then we enable it.
431         for (int i = curRow + 1; i < srows; ++i) {
432                 string const thisMod = getSelectedModel()->getIDString(i);
433                 vector<string> reqs = getRequiredList(thisMod);
434                 //does this one require us?
435                 if (find(reqs.begin(), reqs.end(), curmodname) == reqs.end())
436                         //no...
437                         continue;
438
439                 // OK, so this module requires us
440                 // is there an EARLIER module that also satisfies the require?
441                 // NOTE We demand that it be earlier to keep the list of modules
442                 // consistent with the rule that a module must be proceeded by a
443                 // required module. There would be more flexible ways to proceed,
444                 // but that would be a lot more complicated, and the logic here is
445                 // already complicated. (That's why I've left the debugging code.)
446                 // lyxerr << "Testing " << thisMod << endl;
447                 bool foundone = false;
448                 for (int j = 0; j < curRow; ++j) {
449                         string const mod = getSelectedModel()->getIDString(j);
450                         // lyxerr << "In loop: Testing " << mod << endl;
451                         // do we satisfy the require?
452                         if (find(reqs.begin(), reqs.end(), mod) != reqs.end()) {
453                                 // lyxerr << mod << " does the trick." << endl;
454                                 foundone = true;
455                                 break;
456                         }
457                 }
458                 // did we find a module to satisfy the require?
459                 if (!foundone) {
460                         // lyxerr << "No matching module found." << endl;
461                         deletePB->setEnabled(false);
462                         return;
463                 }
464         }
465         // lyxerr << "All's well that ends well." << endl;
466         deletePB->setEnabled(true);
467 }
468
469
470 /////////////////////////////////////////////////////////////////////
471 //
472 // PreambleModule
473 //
474 /////////////////////////////////////////////////////////////////////
475
476 PreambleModule::PreambleModule(QWidget * parent)
477         : UiWidget<Ui::PreambleUi>(parent), current_id_(nullptr),
478           highlighter_(new LaTeXHighlighter(preambleTE->document(), true))
479 {
480         // This is not a memory leak. The object will be destroyed
481         // with this.
482         // @ is letter in the LyX user preamble
483         preambleTE->setFont(guiApp->typewriterSystemFont());
484         preambleTE->setWordWrapMode(QTextOption::NoWrap);
485         setFocusProxy(preambleTE);
486         // Install event filter on find line edit to capture return/enter key
487         findLE->installEventFilter(this);
488         connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed()));
489         connect(findLE, SIGNAL(textEdited(const QString &)), this, SLOT(checkFindButton()));
490         connect(findButtonPB, SIGNAL(clicked()), this, SLOT(findText()));
491         connect(editPB, SIGNAL(clicked()), this, SLOT(editExternal()));
492         connect(findLE, SIGNAL(returnPressed()), this, SLOT(findText()));
493         checkFindButton();
494         int const tabStop = 4;
495         QFontMetrics metrics(preambleTE->currentFont());
496 #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
497         // horizontalAdvance() is available starting in 5.11.0
498         // setTabStopDistance() is available starting in 5.10.0
499         preambleTE->setTabStopDistance(tabStop * metrics.horizontalAdvance(' '));
500 #else
501         preambleTE->setTabStopWidth(tabStop * metrics.width(' '));
502 #endif
503 }
504
505
506 bool PreambleModule::eventFilter(QObject * sender, QEvent * event)
507 {
508         if (sender == findLE) {
509                 if (event->type() == QEvent::KeyPress) {
510                         QKeyEvent * key = static_cast<QKeyEvent *>(event);
511                         if ((key->key() == Qt::Key_Enter) || (key->key() == Qt::Key_Return)) {
512                                 findText();
513                                 // Return true to filter out the event
514                                 return true;
515                         }
516                 }
517         }
518         if (event->type() == QEvent::ApplicationPaletteChange) {
519                 // mode switch: colors need to be updated
520                 // and the highlighting redone
521                 if (highlighter_) {
522                         highlighter_->setupColors();
523                         highlighter_->rehighlight();
524                 }
525         }
526         return QWidget::eventFilter(sender, event);
527 }
528
529
530
531 void PreambleModule::checkFindButton()
532 {
533         findButtonPB->setEnabled(!findLE->text().isEmpty());
534 }
535
536
537 void PreambleModule::findText()
538 {
539         bool const found = preambleTE->find(findLE->text());
540         if (!found) {
541                 // wrap
542                 QTextCursor qtcur = preambleTE->textCursor();
543                 qtcur.movePosition(QTextCursor::Start);
544                 preambleTE->setTextCursor(qtcur);
545                 preambleTE->find(findLE->text());
546         }
547 }
548
549
550 void PreambleModule::update(BufferParams const & params, BufferId id)
551 {
552         QString preamble = toqstr(params.preamble);
553         // Nothing to do if the params and preamble are unchanged.
554         if (id == current_id_
555                 && preamble == preambleTE->document()->toPlainText())
556                 return;
557
558         QTextCursor cur = preambleTE->textCursor();
559         // Save the coords before switching to the new one.
560         preamble_coords_[current_id_] =
561                 make_pair(cur.position(), preambleTE->verticalScrollBar()->value());
562
563         // Save the params address for further use.
564         current_id_ = id;
565         preambleTE->document()->setPlainText(preamble);
566         Coords::const_iterator it = preamble_coords_.find(current_id_);
567         if (it == preamble_coords_.end())
568                 // First time we open this one.
569                 preamble_coords_[current_id_] = make_pair(0, 0);
570         else {
571                 // Restore saved coords.
572                 cur = preambleTE->textCursor();
573                 cur.setPosition(it->second.first);
574                 preambleTE->setTextCursor(cur);
575                 preambleTE->verticalScrollBar()->setValue(it->second.second);
576         }
577 }
578
579
580 void PreambleModule::apply(BufferParams & params)
581 {
582         params.preamble = qstring_to_ucs4(preambleTE->document()->toPlainText());
583 }
584
585
586 void PreambleModule::closeEvent(QCloseEvent * e)
587 {
588         // Save the coords before closing.
589         QTextCursor cur = preambleTE->textCursor();
590         preamble_coords_[current_id_] =
591                 make_pair(cur.position(), preambleTE->verticalScrollBar()->value());
592         e->accept();
593 }
594
595
596 void PreambleModule::editExternal() {
597         if (!current_id_)
598                 return;
599
600         if (tempfile_) {
601                 preambleTE->setReadOnly(false);
602                 FileName const tempfilename = tempfile_->name();
603                 docstring const s = tempfilename.fileContents("UTF-8");
604                 preambleTE->document()->setPlainText(toqstr(s));
605                 tempfile_.reset();
606                 editPB->setText(qt_("&Edit Externally"));
607                 editPB->setIcon(QIcon());
608                 changed();
609                 return;
610         }
611
612         string const format =
613                 current_id_->params().documentClass().outputFormat();
614         string const ext = theFormats().extension(format);
615         tempfile_.reset(new TempFile("preamble_editXXXXXX." + ext));
616         FileName const tempfilename = tempfile_->name();
617         string const name = tempfilename.toFilesystemEncoding();
618         ofdocstream os(name.c_str());
619         os << qstring_to_ucs4(preambleTE->document()->toPlainText());
620         os.close();
621         preambleTE->setReadOnly(true);
622         theFormats().edit(*current_id_, tempfilename, format);
623         editPB->setText(qt_("&End Edit"));
624         QIcon warn(guiApp ? guiApp->getScaledPixmap("images/", "emblem-shellescape-user")
625                           : getPixmap("images/", "emblem-shellescape", "svgz,png"));
626         editPB->setIcon(warn);
627         changed();
628 }
629
630 /////////////////////////////////////////////////////////////////////
631 //
632 // LocalLayout
633 //
634 /////////////////////////////////////////////////////////////////////
635
636
637 LocalLayout::LocalLayout(QWidget * parent)
638         : UiWidget<Ui::LocalLayoutUi>(parent), current_id_(nullptr), validated_(false)
639 {
640         locallayoutTE->setFont(guiApp->typewriterSystemFont());
641         locallayoutTE->setWordWrapMode(QTextOption::NoWrap);
642         connect(locallayoutTE, SIGNAL(textChanged()), this, SLOT(textChanged()));
643         connect(validatePB, SIGNAL(clicked()), this, SLOT(validatePressed()));
644         connect(convertPB, SIGNAL(clicked()), this, SLOT(convertPressed()));
645         connect(editPB, SIGNAL(clicked()), this, SLOT(editExternal()));
646         int const tabStop = 4;
647         QFontMetrics metrics(locallayoutTE->currentFont());
648 #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
649         // horizontalAdvance() is available starting in 5.11.0
650         // setTabStopDistance() is available starting in 5.10.0
651         locallayoutTE->setTabStopDistance(tabStop * metrics.horizontalAdvance(' '));
652 #else
653         locallayoutTE->setTabStopWidth(tabStop * metrics.width(' '));
654 #endif
655 }
656
657
658 void LocalLayout::update(BufferParams const & params, BufferId id)
659 {
660         QString layout = toqstr(params.getLocalLayout(false));
661         // Nothing to do if the params and preamble are unchanged.
662         if (id == current_id_
663                 && layout == locallayoutTE->document()->toPlainText())
664                 return;
665
666         // Save the params address for further use.
667         current_id_ = id;
668         locallayoutTE->document()->setPlainText(layout);
669         validate();
670 }
671
672
673 void LocalLayout::apply(BufferParams & params)
674 {
675         docstring const layout =
676                 qstring_to_ucs4(locallayoutTE->document()->toPlainText());
677         params.setLocalLayout(layout, false);
678 }
679
680
681 void LocalLayout::hideConvert()
682 {
683         convertPB->setEnabled(false);
684         convertLB->setText("");
685         convertPB->hide();
686         convertLB->hide();
687 }
688
689
690 void LocalLayout::textChanged()
691 {
692         validLB->setText("");
693         string const layout =
694                 fromqstr(locallayoutTE->document()->toPlainText().trimmed());
695
696         if (layout.empty()) {
697                 validated_ = true;
698                 validatePB->setEnabled(false);
699                 hideConvert();
700                 changed();
701         } else if (!validatePB->isEnabled()) {
702                 // if that's already enabled, we shouldn't need to do anything.
703                 validated_ = false;
704                 validatePB->setEnabled(true);
705                 hideConvert();
706                 changed();
707         }
708 }
709
710
711 void LocalLayout::convert() {
712         string const layout =
713                 fromqstr(locallayoutTE->document()->toPlainText().trimmed());
714         string const newlayout = TextClass::convert(layout);
715         if (!newlayout.empty())
716                 locallayoutTE->setPlainText(toqstr(newlayout));
717         validate();
718 }
719
720
721 void LocalLayout::convertPressed() {
722         convert();
723         hideConvert();
724         changed();
725 }
726
727
728 void LocalLayout::validate() {
729         // Bold text
730         static const QString vpar("<p style=\"font-weight: bold; text-align:left\">%1</p>");
731         // Flashy red bold text
732         static const QString ivpar("<p style=\"color: #c00000; font-weight: bold; text-align:left\">"
733                                    "%1</p>");
734         string const layout =
735                 fromqstr(locallayoutTE->document()->toPlainText().trimmed());
736         if (!layout.empty()) {
737                 TextClass::ReturnValues const ret = TextClass::validate(layout);
738                 validated_ = (ret == TextClass::OK) || (ret == TextClass::OK_OLDFORMAT);
739                 validatePB->setEnabled(false);
740                 validLB->setText(validated_ ? vpar.arg(qt_("Layout is valid!"))
741                                             : ivpar.arg(qt_("Layout is invalid!")));
742                 if (ret == TextClass::OK_OLDFORMAT) {
743                         convertPB->show();
744                         // Testing conversion to LYXFILE_LAYOUT_FORMAT at this point
745                         // already.
746                         if (TextClass::convert(layout).empty()) {
747                                 // Conversion failed. If LAYOUT_FORMAT > LYXFILE_LAYOUT_FORMAT,
748                                 // then maybe the layout is still valid, but its format is more
749                                 // recent than LYXFILE_LAYOUT_FORMAT. However, if LAYOUT_FORMAT
750                                 // == LYXFILE_LAYOUT_FORMAT then something is definitely wrong.
751                                 convertPB->setEnabled(false);
752                                 const QString text = (LAYOUT_FORMAT == LYXFILE_LAYOUT_FORMAT)
753                                         ? ivpar.arg(qt_("Conversion to current format impossible!"))
754                                         : vpar.arg(qt_("Conversion to current stable format "
755                                                        "impossible."));
756                                 convertLB->setText(text);
757                         } else {
758                                 convertPB->setEnabled(true);
759                                 convertLB->setText(qt_("Convert to current format"));
760                         }
761                         convertLB->show();
762                 } else {
763                         convertPB->hide();
764                         convertLB->hide();
765                 }
766         }
767 }
768
769
770 void LocalLayout::validatePressed() {
771         validate();
772         changed();
773 }
774
775
776 void LocalLayout::editExternal() {
777         if (!current_id_)
778                 return;
779
780         if (tempfile_) {
781                 locallayoutTE->setReadOnly(false);
782                 FileName const tempfilename = tempfile_->name();
783                 docstring const s = tempfilename.fileContents("UTF-8");
784                 locallayoutTE->document()->setPlainText(toqstr(s));
785                 tempfile_.reset();
786                 editPB->setText(qt_("&Edit Externally"));
787                 editPB->setIcon(QIcon());
788                 changed();
789                 return;
790         }
791
792         string const format =
793                 current_id_->params().documentClass().outputFormat();
794         string const ext = theFormats().extension(format);
795         tempfile_.reset(new TempFile("preamble_editXXXXXX." + ext));
796         FileName const tempfilename = tempfile_->name();
797         string const name = tempfilename.toFilesystemEncoding();
798         ofdocstream os(name.c_str());
799         os << qstring_to_ucs4(locallayoutTE->document()->toPlainText());
800         os.close();
801         locallayoutTE->setReadOnly(true);
802         theFormats().edit(*current_id_, tempfilename, format);
803         editPB->setText(qt_("&End Edit"));
804         QIcon warn(guiApp ? guiApp->getScaledPixmap("images/", "emblem-shellescape-user")
805                           : getPixmap("images/", "emblem-shellescape", "svgz,png"));
806         editPB->setIcon(warn);
807         validatePB->setEnabled(false);
808         hideConvert();
809         changed();
810 }
811
812 /////////////////////////////////////////////////////////////////////
813 //
814 // DocumentDialog
815 //
816 /////////////////////////////////////////////////////////////////////
817
818
819 GuiDocument::GuiDocument(GuiView & lv)
820         : GuiDialog(lv, "document", qt_("Document Settings")),
821           biblioChanged_(false), nonModuleChanged_(false),
822           modulesChanged_(false), shellescapeChanged_(false),
823           switchback_(false), prompted_(false)
824 {
825         setupUi(this);
826
827         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
828                 this, SLOT(slotButtonBox(QAbstractButton *)));
829
830         connect(savePB, SIGNAL(clicked()), this, SLOT(saveDefaultClicked()));
831         connect(defaultPB, SIGNAL(clicked()), this, SLOT(useDefaultsClicked()));
832
833         // Manage the restore, ok, apply, restore and cancel/close buttons
834         bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
835         bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
836         bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
837         bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
838         bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
839
840
841         // text layout
842         textLayoutModule = new UiWidget<Ui::TextLayoutUi>(this);
843         connect(textLayoutModule->lspacingCO, SIGNAL(activated(int)),
844                 this, SLOT(change_adaptor()));
845         connect(textLayoutModule->lspacingCO, SIGNAL(activated(int)),
846                 this, SLOT(setLSpacing(int)));
847         connect(textLayoutModule->lspacingLE, SIGNAL(textChanged(const QString &)),
848                 this, SLOT(change_adaptor()));
849
850         connect(textLayoutModule->indentRB, SIGNAL(clicked()),
851                 this, SLOT(change_adaptor()));
852         connect(textLayoutModule->indentRB, SIGNAL(toggled(bool)),
853                 textLayoutModule->indentCO, SLOT(setEnabled(bool)));
854         connect(textLayoutModule->indentCO, SIGNAL(activated(int)),
855                 this, SLOT(change_adaptor()));
856         connect(textLayoutModule->indentCO, SIGNAL(activated(int)),
857                 this, SLOT(setIndent(int)));
858         connect(textLayoutModule->indentLE, SIGNAL(textChanged(const QString &)),
859                 this, SLOT(change_adaptor()));
860         connect(textLayoutModule->indentLengthCO, SIGNAL(activated(int)),
861                 this, SLOT(change_adaptor()));
862
863         connect(textLayoutModule->skipRB, SIGNAL(clicked()),
864                 this, SLOT(change_adaptor()));
865         connect(textLayoutModule->skipRB, SIGNAL(toggled(bool)),
866                 textLayoutModule->skipCO, SLOT(setEnabled(bool)));
867         connect(textLayoutModule->skipCO, SIGNAL(activated(int)),
868                 this, SLOT(change_adaptor()));
869         connect(textLayoutModule->skipCO, SIGNAL(activated(int)),
870                 this, SLOT(setSkip(int)));
871         connect(textLayoutModule->skipLE, SIGNAL(textChanged(const QString &)),
872                 this, SLOT(change_adaptor()));
873         connect(textLayoutModule->skipLengthCO, SIGNAL(activated(int)),
874                 this, SLOT(change_adaptor()));
875
876         connect(textLayoutModule->indentRB, SIGNAL(toggled(bool)),
877                 this, SLOT(enableIndent(bool)));
878         connect(textLayoutModule->skipRB, SIGNAL(toggled(bool)),
879                 this, SLOT(enableSkip(bool)));
880
881         connect(textLayoutModule->twoColumnCB, SIGNAL(clicked()),
882                 this, SLOT(change_adaptor()));
883         connect(textLayoutModule->twoColumnCB, SIGNAL(clicked()),
884                 this, SLOT(setColSep()));
885         connect(textLayoutModule->justCB, SIGNAL(clicked()),
886                 this, SLOT(change_adaptor()));
887
888         connect(textLayoutModule->tableStyleCO, SIGNAL(activated(int)),
889                 this, SLOT(change_adaptor()));
890
891         textLayoutModule->lspacingLE->setValidator(new QDoubleValidator(
892                 textLayoutModule->lspacingLE));
893         textLayoutModule->indentLE->setValidator(new LengthValidator(
894                 textLayoutModule->indentLE, false));
895         textLayoutModule->skipLE->setValidator(new LengthValidator(
896                 textLayoutModule->skipLE, false));
897
898         textLayoutModule->indentCO->addItem(qt_("Default"), toqstr("default"));
899         textLayoutModule->indentCO->addItem(qt_("Custom"), toqstr("custom"));
900         textLayoutModule->skipCO->addItem(qt_("Half line height"), VSpace::HALFLINE);
901         textLayoutModule->skipCO->addItem(qt_("Line height"), VSpace::FULLLINE);
902         textLayoutModule->skipCO->addItem(qt_("Small Skip"), VSpace::SMALLSKIP);
903         textLayoutModule->skipCO->addItem(qt_("Medium Skip"), VSpace::MEDSKIP);
904         textLayoutModule->skipCO->addItem(qt_("Big Skip"), VSpace::BIGSKIP);
905         textLayoutModule->skipCO->addItem(qt_("Custom"), VSpace::LENGTH);
906         textLayoutModule->lspacingCO->insertItem(
907                 Spacing::Single, qt_("Single"));
908         textLayoutModule->lspacingCO->insertItem(
909                 Spacing::Onehalf, qt_("OneHalf"));
910         textLayoutModule->lspacingCO->insertItem(
911                 Spacing::Double, qt_("Double"));
912         textLayoutModule->lspacingCO->insertItem(
913                 Spacing::Other, qt_("Custom"));
914         // initialize the length validator
915         bc().addCheckedLineEdit(textLayoutModule->indentLE, textLayoutModule->indentRB);
916         bc().addCheckedLineEditPanel(textLayoutModule->indentLE, docPS, N_("Text Layout"));
917         bc().addCheckedLineEdit(textLayoutModule->skipLE, textLayoutModule->skipRB);
918         bc().addCheckedLineEditPanel(textLayoutModule->skipLE, docPS, N_("Text Layout"));
919
920         textLayoutModule->tableStyleCO->addItem(qt_("Default"), toqstr("default"));
921         getTableStyles();
922
923
924         // master/child handling
925         masterChildModule = new UiWidget<Ui::MasterChildUi>(this);
926
927         connect(masterChildModule->childrenTW, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
928                 this, SLOT(includeonlyClicked(QTreeWidgetItem *, int)));
929         connect(masterChildModule->includeonlyRB, SIGNAL(toggled(bool)),
930                 masterChildModule->childrenTW, SLOT(setEnabled(bool)));
931         connect(masterChildModule->includeonlyRB, SIGNAL(toggled(bool)),
932                 masterChildModule->maintainGB, SLOT(setEnabled(bool)));
933         connect(masterChildModule->includeallRB, SIGNAL(clicked()),
934                 this, SLOT(change_adaptor()));
935         connect(masterChildModule->includeonlyRB, SIGNAL(clicked()),
936                 this, SLOT(change_adaptor()));
937         connect(masterChildModule->maintainCRNoneRB, SIGNAL(clicked()),
938                 this, SLOT(change_adaptor()));
939         connect(masterChildModule->maintainCRMostlyRB, SIGNAL(clicked()),
940                 this, SLOT(change_adaptor()));
941         connect(masterChildModule->maintainCRStrictRB, SIGNAL(clicked()),
942                 this, SLOT(change_adaptor()));
943         masterChildModule->childrenTW->setColumnCount(2);
944         masterChildModule->childrenTW->headerItem()->setText(0, qt_("Child Document"));
945         masterChildModule->childrenTW->headerItem()->setText(1, qt_("Include to Output"));
946         masterChildModule->childrenTW->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
947         masterChildModule->childrenTW->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
948
949         // Formats
950         outputModule = new UiWidget<Ui::OutputUi>(this);
951
952         connect(outputModule->defaultFormatCO, SIGNAL(activated(int)),
953                 this, SLOT(change_adaptor()));
954         connect(outputModule->mathimgSB, SIGNAL(valueChanged(double)),
955                 this, SLOT(change_adaptor()));
956         connect(outputModule->strictCB, SIGNAL(stateChanged(int)),
957                 this, SLOT(change_adaptor()));
958         connect(outputModule->cssCB, SIGNAL(stateChanged(int)),
959                 this, SLOT(change_adaptor()));
960         connect(outputModule->mathoutCB, SIGNAL(currentIndexChanged(int)),
961                 this, SLOT(change_adaptor()));
962         connect(outputModule->tableoutCB, SIGNAL(currentIndexChanged(int)),
963                 this, SLOT(change_adaptor()));
964         connect(outputModule->mathmlprefixCB, SIGNAL(currentIndexChanged(int)),
965                 this, SLOT(change_adaptor()));
966
967         connect(outputModule->shellescapeCB, SIGNAL(stateChanged(int)),
968                 this, SLOT(shellescapeChanged()));
969         connect(outputModule->outputsyncCB, SIGNAL(toggled(bool)),
970                 this, SLOT(setOutputSync(bool)));
971         connect(outputModule->synccustomCB, SIGNAL(editTextChanged(QString)),
972                 this, SLOT(change_adaptor()));
973         outputModule->synccustomCB->addItem("");
974         outputModule->synccustomCB->addItem("\\synctex=1");
975         outputModule->synccustomCB->addItem("\\synctex=-1");
976         outputModule->synccustomCB->addItem("\\usepackage[active]{srcltx}");
977
978         outputModule->synccustomCB->lineEdit()->setValidator(new NoNewLineValidator(
979                 outputModule->synccustomCB));
980
981         connect(outputModule->saveTransientPropertiesCB, SIGNAL(clicked()),
982                 this, SLOT(change_adaptor()));
983         connect(outputModule->postponeFragileCB, SIGNAL(clicked()),
984                 this, SLOT(change_adaptor()));
985
986
987         // language & quote
988         // this must precede font, since fonts depend on this
989         langModule = new UiWidget<Ui::LanguageUi>(this);
990         connect(langModule->languageCO, SIGNAL(activated(int)),
991                 this, SLOT(change_adaptor()));
992         connect(langModule->languageCO, SIGNAL(activated(int)),
993                 this, SLOT(languageChanged(int)));
994         connect(langModule->encodingCO, SIGNAL(activated(int)),
995                 this, SLOT(change_adaptor()));
996         connect(langModule->encodingCO, SIGNAL(activated(int)),
997                 this, SLOT(encodingSwitched(int)));
998         connect(langModule->unicodeEncodingCO, SIGNAL(activated(int)),
999                 this, SLOT(change_adaptor()));
1000         connect(langModule->autoEncodingCO, SIGNAL(activated(int)),
1001                 this, SLOT(change_adaptor()));
1002         connect(langModule->customEncodingCO, SIGNAL(activated(int)),
1003                 this, SLOT(change_adaptor()));
1004         connect(langModule->quoteStyleCO, SIGNAL(activated(int)),
1005                 this, SLOT(change_adaptor()));
1006         connect(langModule->languagePackageCO, SIGNAL(activated(int)),
1007                 this, SLOT(change_adaptor()));
1008         connect(langModule->languagePackageLE, SIGNAL(textChanged(QString)),
1009                 this, SLOT(change_adaptor()));
1010         connect(langModule->languagePackageCO, SIGNAL(currentIndexChanged(int)),
1011                 this, SLOT(languagePackageChanged(int)));
1012         connect(langModule->dynamicQuotesCB, SIGNAL(clicked()),
1013                 this, SLOT(change_adaptor()));
1014
1015         langModule->languagePackageLE->setValidator(new NoNewLineValidator(
1016                 langModule->languagePackageLE));
1017
1018         QAbstractItemModel * language_model = guiApp->languageModel();
1019         // FIXME: it would be nice if sorting was enabled/disabled via a checkbox.
1020         language_model->sort(0);
1021         langModule->languageCO->setModel(language_model);
1022         langModule->languageCO->setModelColumn(0);
1023
1024         langModule->encodingCO->addItem(qt_("Unicode (utf8)"));
1025         langModule->encodingCO->addItem(qt_("Traditional (auto-selected)"));
1026         langModule->encodingCO->addItem(qt_("Custom"));
1027         langModule->encodingCO->setItemData(EncodingSets::unicode,
1028                 qt_("Select Unicode (utf8) encoding."), Qt::ToolTipRole);
1029         langModule->encodingCO->setItemData(EncodingSets::legacy,
1030                 qt_("Use language-dependent traditional encodings."), Qt::ToolTipRole);
1031         langModule->encodingCO->setItemData(EncodingSets::custom,
1032                 qt_("Select a custom, document-wide encoding."), Qt::ToolTipRole);
1033
1034         // basic Unicode encodings: keep order
1035         const QStringList utf8_base_encodings = {"utf8", "utf8-plain", "utf8x"};
1036         for (auto const & i : utf8_base_encodings) {
1037                 langModule->unicodeEncodingCO->addItem(
1038                                         qt_(encodings.fromLyXName(fromqstr(i))->guiName()), i);
1039         }
1040         langModule->unicodeEncodingCO->setItemData(0,
1041                 qt_("Standard Unicode support by the ``inputenc'' package."),
1042                 Qt::ToolTipRole);
1043         langModule->unicodeEncodingCO->setItemData(1,
1044                 qt_("Use UTF-8 'as-is': do not load any supporting packages, "
1045                         "do not convert any characters to LaTeX macros. "
1046                         "For use with non-TeX fonts (XeTeX/LuaTeX) or custom preamble code."),
1047                 Qt::ToolTipRole);
1048         langModule->unicodeEncodingCO->setItemData(2,
1049                 qt_("Load ``inputenc'' with option 'utf8x' "
1050                         "for extended Unicode support by the ``ucs'' package."),
1051                 Qt::ToolTipRole);
1052         langModule->autoEncodingCO->addItem(qt_("Language Default"), toqstr("auto-legacy"));
1053         langModule->autoEncodingCO->addItem(qt_("Language Default (no inputenc)"), toqstr("auto-legacy-plain"));
1054         langModule->autoEncodingCO->setItemData(0,
1055                 qt_("Use the traditional default encoding of the text language. Switch encoding "
1056                         "if a text part is set to a language with different default."),
1057                 Qt::ToolTipRole);
1058         langModule->autoEncodingCO->setItemData(1,
1059                 qt_("Do not load the 'inputenc' package. Switch encoding if required "
1060                         "but do not write input encoding switch commands to the source."),
1061                 Qt::ToolTipRole);
1062         // sort encodings
1063         QMap<QString,QString> encodingmap;
1064         QMap<QString,QString> encodingmap_utf8;
1065         for (auto const & encvar : encodings) {
1066                 if (encvar.unsafe() ||encvar.guiName().empty()
1067                     || utf8_base_encodings.contains(toqstr(encvar.name())))
1068                         continue;
1069                 if (encvar.name().find("utf8") == 0)
1070                         encodingmap_utf8.insert(qt_(encvar.guiName()), toqstr(encvar.name()));
1071                 else
1072                         encodingmap.insert(qt_(encvar.guiName()), toqstr(encvar.name()));
1073         }
1074         for (auto const & i : encodingmap_utf8.keys()) {
1075                 langModule->unicodeEncodingCO->addItem(i, encodingmap_utf8.value(i));
1076         }
1077         for (auto const & i : encodingmap.keys()) {
1078                 langModule->customEncodingCO->addItem(i, encodingmap.value(i));
1079         }
1080         // equalise the width of encoding selectors
1081         langModule->autoEncodingCO->setMinimumSize(
1082                 langModule->unicodeEncodingCO->minimumSizeHint());
1083         langModule->customEncodingCO->setMinimumSize(
1084                 langModule->unicodeEncodingCO->minimumSizeHint());
1085
1086         langModule->languagePackageCO->addItem(
1087                 qt_("Default"), toqstr("default"));
1088         langModule->languagePackageCO->addItem(
1089                 qt_("Automatic"), toqstr("auto"));
1090         langModule->languagePackageCO->addItem(
1091                 qt_("Always Babel"), toqstr("babel"));
1092         langModule->languagePackageCO->addItem(
1093                 qt_("Custom"), toqstr("custom"));
1094         langModule->languagePackageCO->addItem(
1095                 qt_("None[[language package]]"), toqstr("none"));
1096
1097
1098         // fonts
1099         fontModule = new FontModule(this);
1100         connect(fontModule->osFontsCB, SIGNAL(clicked()),
1101                 this, SLOT(change_adaptor()));
1102         connect(fontModule->osFontsCB, SIGNAL(toggled(bool)),
1103                 this, SLOT(osFontsChanged(bool)));
1104         connect(fontModule->fontsRomanCO, SIGNAL(activated(int)),
1105                 this, SLOT(change_adaptor()));
1106         connect(fontModule->fontsRomanCO, SIGNAL(activated(int)),
1107                 this, SLOT(romanChanged(int)));
1108         connect(fontModule->fontsSansCO, SIGNAL(activated(int)),
1109                 this, SLOT(change_adaptor()));
1110         connect(fontModule->fontsSansCO, SIGNAL(activated(int)),
1111                 this, SLOT(sansChanged(int)));
1112         connect(fontModule->fontsTypewriterCO, SIGNAL(activated(int)),
1113                 this, SLOT(change_adaptor()));
1114         connect(fontModule->fontsTypewriterCO, SIGNAL(activated(int)),
1115                 this, SLOT(ttChanged(int)));
1116         connect(fontModule->fontsMathCO, SIGNAL(activated(int)),
1117                 this, SLOT(change_adaptor()));
1118         connect(fontModule->fontsMathCO, SIGNAL(activated(int)),
1119                 this, SLOT(mathFontChanged(int)));
1120         connect(fontModule->fontsDefaultCO, SIGNAL(activated(int)),
1121                 this, SLOT(change_adaptor()));
1122         connect(fontModule->fontencCO, SIGNAL(activated(int)),
1123                 this, SLOT(change_adaptor()));
1124         connect(fontModule->fontencCO, SIGNAL(activated(int)),
1125                 this, SLOT(fontencChanged(int)));
1126         connect(fontModule->fontencLE, SIGNAL(textChanged(const QString &)),
1127                 this, SLOT(change_adaptor()));
1128         connect(fontModule->fontsizeCO, SIGNAL(activated(int)),
1129                 this, SLOT(change_adaptor()));
1130         connect(fontModule->cjkFontLE, SIGNAL(textChanged(const QString &)),
1131                 this, SLOT(change_adaptor()));
1132         connect(fontModule->microtypeCB, SIGNAL(clicked()),
1133                 this, SLOT(change_adaptor()));
1134         connect(fontModule->dashesCB, SIGNAL(clicked()),
1135                 this, SLOT(change_adaptor()));
1136         connect(fontModule->scaleSansSB, SIGNAL(valueChanged(int)),
1137                 this, SLOT(change_adaptor()));
1138         connect(fontModule->scaleTypewriterSB, SIGNAL(valueChanged(int)),
1139                 this, SLOT(change_adaptor()));
1140         connect(fontModule->fontScCB, SIGNAL(clicked()),
1141                 this, SLOT(change_adaptor()));
1142         connect(fontModule->fontScCB, SIGNAL(toggled(bool)),
1143                 this, SLOT(fontScToggled(bool)));
1144         connect(fontModule->fontOsfCB, SIGNAL(clicked()),
1145                 this, SLOT(change_adaptor()));
1146         connect(fontModule->fontOsfCB, SIGNAL(toggled(bool)),
1147                 this, SLOT(fontOsfToggled(bool)));
1148         connect(fontModule->fontSansOsfCB, SIGNAL(clicked()),
1149                 this, SLOT(change_adaptor()));
1150         connect(fontModule->fontTypewriterOsfCB, SIGNAL(clicked()),
1151                 this, SLOT(change_adaptor()));
1152         connect(fontModule->fontspecRomanLE, SIGNAL(textChanged(const QString &)),
1153                 this, SLOT(change_adaptor()));
1154         connect(fontModule->fontspecSansLE, SIGNAL(textChanged(const QString &)),
1155                 this, SLOT(change_adaptor()));
1156         connect(fontModule->fontspecTypewriterLE, SIGNAL(textChanged(const QString &)),
1157                 this, SLOT(change_adaptor()));
1158
1159         fontModule->fontencLE->setValidator(new NoNewLineValidator(
1160                 fontModule->fontencLE));
1161         fontModule->cjkFontLE->setValidator(new NoNewLineValidator(
1162                 fontModule->cjkFontLE));
1163         fontModule->fontspecRomanLE->setValidator(new NoNewLineValidator(
1164                 fontModule->fontspecRomanLE));
1165         fontModule->fontspecSansLE->setValidator(new NoNewLineValidator(
1166                 fontModule->fontspecSansLE));
1167         fontModule->fontspecTypewriterLE->setValidator(new NoNewLineValidator(
1168                 fontModule->fontspecTypewriterLE));
1169
1170         updateFontlist();
1171
1172         fontModule->fontsizeCO->addItem(qt_("Default"));
1173         fontModule->fontsizeCO->addItem(qt_("10"));
1174         fontModule->fontsizeCO->addItem(qt_("11"));
1175         fontModule->fontsizeCO->addItem(qt_("12"));
1176
1177         fontModule->fontencCO->addItem(qt_("Automatic[[encoding]]"), QString("auto"));
1178         fontModule->fontencCO->addItem(qt_("Class Default"), QString("default"));
1179         fontModule->fontencCO->addItem(qt_("Custom"), QString("custom"));
1180
1181         for (int n = 0; GuiDocument::fontfamilies_gui[n][0]; ++n)
1182                 fontModule->fontsDefaultCO->addItem(
1183                         qt_(GuiDocument::fontfamilies_gui[n]));
1184
1185         if (!LaTeXFeatures::isAvailable("fontspec"))
1186                 fontModule->osFontsCB->setToolTip(
1187                         qt_("Use OpenType and TrueType fonts directly (requires XeTeX or LuaTeX)\n"
1188                             "You need to install the package \"fontspec\" to use this feature"));
1189
1190
1191         // page layout
1192         pageLayoutModule = new UiWidget<Ui::PageLayoutUi>(this);
1193         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
1194                 this, SLOT(papersizeChanged(int)));
1195         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
1196                 this, SLOT(papersizeChanged(int)));
1197         connect(pageLayoutModule->portraitRB, SIGNAL(clicked()),
1198                 this, SLOT(change_adaptor()));
1199         connect(pageLayoutModule->papersizeCO, SIGNAL(activated(int)),
1200                 this, SLOT(change_adaptor()));
1201         connect(pageLayoutModule->paperheightLE, SIGNAL(textChanged(const QString &)),
1202                 this, SLOT(change_adaptor()));
1203         connect(pageLayoutModule->paperwidthLE, SIGNAL(textChanged(const QString &)),
1204                 this, SLOT(change_adaptor()));
1205         connect(pageLayoutModule->paperwidthUnitCO, SIGNAL(activated(int)),
1206                 this, SLOT(change_adaptor()));
1207         connect(pageLayoutModule->paperheightUnitCO, SIGNAL(activated(int)),
1208                 this, SLOT(change_adaptor()));
1209         connect(pageLayoutModule->portraitRB, SIGNAL(clicked()),
1210                 this, SLOT(change_adaptor()));
1211         connect(pageLayoutModule->landscapeRB, SIGNAL(clicked()),
1212                 this, SLOT(change_adaptor()));
1213         connect(pageLayoutModule->facingPagesCB, SIGNAL(clicked()),
1214                 this, SLOT(change_adaptor()));
1215         connect(pageLayoutModule->pagestyleCO, SIGNAL(activated(int)),
1216                 this, SLOT(change_adaptor()));
1217
1218         pageLayoutModule->pagestyleCO->addItem(qt_("Default"));
1219         pageLayoutModule->pagestyleCO->addItem(qt_("empty"));
1220         pageLayoutModule->pagestyleCO->addItem(qt_("plain"));
1221         pageLayoutModule->pagestyleCO->addItem(qt_("headings"));
1222         pageLayoutModule->pagestyleCO->addItem(qt_("fancy"));
1223         bc().addCheckedLineEdit(pageLayoutModule->paperheightLE,
1224                 pageLayoutModule->paperheightL);
1225         bc().addCheckedLineEditPanel(pageLayoutModule->paperheightLE, docPS, N_("Page Layout"));
1226         bc().addCheckedLineEdit(pageLayoutModule->paperwidthLE,
1227                 pageLayoutModule->paperwidthL);
1228         bc().addCheckedLineEditPanel(pageLayoutModule->paperwidthLE, docPS, N_("Page Layout"));
1229
1230         QComboBox * cb = pageLayoutModule->papersizeCO;
1231         cb->addItem(qt_("Default"));
1232         cb->addItem(qt_("Custom"));
1233         cb->addItem(qt_("US letter"));
1234         cb->addItem(qt_("US legal"));
1235         cb->addItem(qt_("US executive"));
1236         cb->addItem(qt_("A0"));
1237         cb->addItem(qt_("A1"));
1238         cb->addItem(qt_("A2"));
1239         cb->addItem(qt_("A3"));
1240         cb->addItem(qt_("A4"));
1241         cb->addItem(qt_("A5"));
1242         cb->addItem(qt_("A6"));
1243         cb->addItem(qt_("B0"));
1244         cb->addItem(qt_("B1"));
1245         cb->addItem(qt_("B2"));
1246         cb->addItem(qt_("B3"));
1247         cb->addItem(qt_("B4"));
1248         cb->addItem(qt_("B5"));
1249         cb->addItem(qt_("B6"));
1250         cb->addItem(qt_("C0"));
1251         cb->addItem(qt_("C1"));
1252         cb->addItem(qt_("C2"));
1253         cb->addItem(qt_("C3"));
1254         cb->addItem(qt_("C4"));
1255         cb->addItem(qt_("C5"));
1256         cb->addItem(qt_("C6"));
1257         cb->addItem(qt_("JIS B0"));
1258         cb->addItem(qt_("JIS B1"));
1259         cb->addItem(qt_("JIS B2"));
1260         cb->addItem(qt_("JIS B3"));
1261         cb->addItem(qt_("JIS B4"));
1262         cb->addItem(qt_("JIS B5"));
1263         cb->addItem(qt_("JIS B6"));
1264         // remove the %-items from the unit choice
1265         pageLayoutModule->paperwidthUnitCO->noPercents();
1266         pageLayoutModule->paperheightUnitCO->noPercents();
1267         pageLayoutModule->paperheightLE->setValidator(unsignedLengthValidator(
1268                 pageLayoutModule->paperheightLE));
1269         pageLayoutModule->paperwidthLE->setValidator(unsignedLengthValidator(
1270                 pageLayoutModule->paperwidthLE));
1271
1272
1273         // margins
1274         marginsModule = new UiWidget<Ui::MarginsUi>(this);
1275         connect(marginsModule->marginCB, SIGNAL(clicked(bool)),
1276                 this, SLOT(setCustomMargins(bool)));
1277         connect(marginsModule->marginCB, SIGNAL(clicked()),
1278                 this, SLOT(change_adaptor()));
1279         connect(marginsModule->topLE, SIGNAL(textChanged(QString)),
1280                 this, SLOT(change_adaptor()));
1281         connect(marginsModule->topUnit, SIGNAL(activated(int)),
1282                 this, SLOT(change_adaptor()));
1283         connect(marginsModule->bottomLE, SIGNAL(textChanged(QString)),
1284                 this, SLOT(change_adaptor()));
1285         connect(marginsModule->bottomUnit, SIGNAL(activated(int)),
1286                 this, SLOT(change_adaptor()));
1287         connect(marginsModule->innerLE, SIGNAL(textChanged(QString)),
1288                 this, SLOT(change_adaptor()));
1289         connect(marginsModule->innerUnit, SIGNAL(activated(int)),
1290                 this, SLOT(change_adaptor()));
1291         connect(marginsModule->outerLE, SIGNAL(textChanged(QString)),
1292                 this, SLOT(change_adaptor()));
1293         connect(marginsModule->outerUnit, SIGNAL(activated(int)),
1294                 this, SLOT(change_adaptor()));
1295         connect(marginsModule->headheightLE, SIGNAL(textChanged(QString)),
1296                 this, SLOT(change_adaptor()));
1297         connect(marginsModule->headheightUnit, SIGNAL(activated(int)),
1298                 this, SLOT(change_adaptor()));
1299         connect(marginsModule->headsepLE, SIGNAL(textChanged(QString)),
1300                 this, SLOT(change_adaptor()));
1301         connect(marginsModule->headsepUnit, SIGNAL(activated(int)),
1302                 this, SLOT(change_adaptor()));
1303         connect(marginsModule->footskipLE, SIGNAL(textChanged(QString)),
1304                 this, SLOT(change_adaptor()));
1305         connect(marginsModule->footskipUnit, SIGNAL(activated(int)),
1306                 this, SLOT(change_adaptor()));
1307         connect(marginsModule->columnsepLE, SIGNAL(textChanged(QString)),
1308                 this, SLOT(change_adaptor()));
1309         connect(marginsModule->columnsepUnit, SIGNAL(activated(int)),
1310                 this, SLOT(change_adaptor()));
1311         marginsModule->topLE->setValidator(new LengthValidator(
1312                 marginsModule->topLE));
1313         marginsModule->bottomLE->setValidator(new LengthValidator(
1314                 marginsModule->bottomLE));
1315         marginsModule->innerLE->setValidator(new LengthValidator(
1316                 marginsModule->innerLE));
1317         marginsModule->outerLE->setValidator(new LengthValidator(
1318                 marginsModule->outerLE));
1319         marginsModule->headsepLE->setValidator(new LengthValidator(
1320                 marginsModule->headsepLE));
1321         marginsModule->headheightLE->setValidator(new LengthValidator(
1322                 marginsModule->headheightLE));
1323         marginsModule->footskipLE->setValidator(new LengthValidator(
1324                 marginsModule->footskipLE));
1325         marginsModule->columnsepLE->setValidator(new LengthValidator(
1326                 marginsModule->columnsepLE));
1327
1328         bc().addCheckedLineEdit(marginsModule->topLE,
1329                 marginsModule->topL);
1330         bc().addCheckedLineEditPanel(marginsModule->topLE,
1331                                      docPS, N_("Page Margins"));
1332         bc().addCheckedLineEdit(marginsModule->bottomLE,
1333                 marginsModule->bottomL);
1334         bc().addCheckedLineEditPanel(marginsModule->bottomLE,
1335                                      docPS, N_("Page Margins"));
1336         bc().addCheckedLineEdit(marginsModule->innerLE,
1337                 marginsModule->innerL);
1338         bc().addCheckedLineEditPanel(marginsModule->innerLE,
1339                                      docPS, N_("Page Margins"));
1340         bc().addCheckedLineEdit(marginsModule->outerLE,
1341                 marginsModule->outerL);
1342         bc().addCheckedLineEditPanel(marginsModule->outerLE,
1343                                      docPS, N_("Page Margins"));
1344         bc().addCheckedLineEdit(marginsModule->headsepLE,
1345                 marginsModule->headsepL);
1346         bc().addCheckedLineEditPanel(marginsModule->headsepLE,
1347                                      docPS, N_("Page Margins"));
1348         bc().addCheckedLineEdit(marginsModule->headheightLE,
1349                 marginsModule->headheightL);
1350         bc().addCheckedLineEditPanel(marginsModule->headheightLE,
1351                                      docPS, N_("Page Margins"));
1352         bc().addCheckedLineEdit(marginsModule->footskipLE,
1353                 marginsModule->footskipL);
1354         bc().addCheckedLineEditPanel(marginsModule->footskipLE,
1355                                      docPS, N_("Page Margins"));
1356         bc().addCheckedLineEdit(marginsModule->columnsepLE,
1357                 marginsModule->columnsepL);
1358         bc().addCheckedLineEditPanel(marginsModule->columnsepLE,
1359                                      docPS, N_("Page Margins"));
1360
1361
1362         // color
1363         colorModule = new UiWidget<Ui::ColorUi>(this);
1364         connect(colorModule->fontColorPB, SIGNAL(clicked()),
1365                 this, SLOT(changeFontColor()));
1366         connect(colorModule->delFontColorTB, SIGNAL(clicked()),
1367                 this, SLOT(deleteFontColor()));
1368         connect(colorModule->noteFontColorPB, SIGNAL(clicked()),
1369                 this, SLOT(changeNoteFontColor()));
1370         connect(colorModule->delNoteFontColorTB, SIGNAL(clicked()),
1371                 this, SLOT(deleteNoteFontColor()));
1372         connect(colorModule->backgroundPB, SIGNAL(clicked()),
1373                 this, SLOT(changeBackgroundColor()));
1374         connect(colorModule->delBackgroundTB, SIGNAL(clicked()),
1375                 this, SLOT(deleteBackgroundColor()));
1376         connect(colorModule->boxBackgroundPB, SIGNAL(clicked()),
1377                 this, SLOT(changeBoxBackgroundColor()));
1378         connect(colorModule->delBoxBackgroundTB, SIGNAL(clicked()),
1379                 this, SLOT(deleteBoxBackgroundColor()));
1380
1381
1382         // change tracking
1383         changesModule = new UiWidget<Ui::ChangeTrackingUi>(this);
1384         connect(changesModule->trackChangesCB, SIGNAL(clicked()),
1385                 this, SLOT(change_adaptor()));
1386         connect(changesModule->outputChangesCB, SIGNAL(toggled(bool)),
1387                 this, SLOT(outputChangesToggled(bool)));
1388         connect(changesModule->changeBarsCB, SIGNAL(clicked()),
1389                 this, SLOT(change_adaptor()));
1390         connect(&lv, SIGNAL(changeTrackingToggled(bool)),
1391                 this, SLOT(changeTrackingChanged(bool)));
1392
1393
1394         // numbering
1395         numberingModule = new UiWidget<Ui::NumberingUi>(this);
1396         connect(numberingModule->depthSL, SIGNAL(valueChanged(int)),
1397                 this, SLOT(change_adaptor()));
1398         connect(numberingModule->tocSL, SIGNAL(valueChanged(int)),
1399                 this, SLOT(change_adaptor()));
1400         connect(numberingModule->depthSL, SIGNAL(valueChanged(int)),
1401                 this, SLOT(updateNumbering()));
1402         connect(numberingModule->tocSL, SIGNAL(valueChanged(int)),
1403                 this, SLOT(updateNumbering()));
1404         numberingModule->tocTW->setColumnCount(3);
1405         numberingModule->tocTW->headerItem()->setText(0, qt_("Example"));
1406         numberingModule->tocTW->headerItem()->setText(1, qt_("Numbered"));
1407         numberingModule->tocTW->headerItem()->setText(2, qt_("Appears in TOC"));
1408         numberingModule->tocTW->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
1409         connect(numberingModule->linenoCB, SIGNAL(toggled(bool)),
1410                 this, SLOT(linenoToggled(bool)));
1411         connect(numberingModule->linenoCB, SIGNAL(clicked()),
1412                 this, SLOT(change_adaptor()));
1413         connect(numberingModule->linenoLE, SIGNAL(textChanged(QString)),
1414                 this, SLOT(change_adaptor()));
1415
1416
1417         // biblio
1418         biblioModule = new UiWidget<Ui::BiblioUi>(this);
1419         connect(biblioModule->citeEngineCO, SIGNAL(activated(int)),
1420                 this, SLOT(citeEngineChanged(int)));
1421         connect(biblioModule->citeStyleCO, SIGNAL(activated(int)),
1422                 this, SLOT(citeStyleChanged()));
1423         connect(biblioModule->bibtopicCB, SIGNAL(clicked()),
1424                 this, SLOT(biblioChanged()));
1425         connect(biblioModule->bibunitsCO, SIGNAL(activated(int)),
1426                 this, SLOT(biblioChanged()));
1427         connect(biblioModule->bibtexCO, SIGNAL(activated(int)),
1428                 this, SLOT(bibtexChanged(int)));
1429         connect(biblioModule->bibtexOptionsLE, SIGNAL(textChanged(QString)),
1430                 this, SLOT(biblioChanged()));
1431         connect(biblioModule->citePackageOptionsLE, SIGNAL(textChanged(QString)),
1432                 this, SLOT(biblioChanged()));
1433         connect(biblioModule->defaultBiblioCO, SIGNAL(activated(int)),
1434                 this, SLOT(biblioChanged()));
1435         connect(biblioModule->defaultBiblioCO, SIGNAL(editTextChanged(QString)),
1436                 this, SLOT(biblioChanged()));
1437         connect(biblioModule->defaultBiblioCO, SIGNAL(editTextChanged(QString)),
1438                 this, SLOT(updateResetDefaultBiblio()));
1439         connect(biblioModule->biblatexBbxCO, SIGNAL(activated(int)),
1440                 this, SLOT(biblioChanged()));
1441         connect(biblioModule->biblatexBbxCO, SIGNAL(editTextChanged(QString)),
1442                 this, SLOT(biblioChanged()));
1443         connect(biblioModule->biblatexBbxCO, SIGNAL(editTextChanged(QString)),
1444                 this, SLOT(updateResetDefaultBiblio()));
1445         connect(biblioModule->biblatexCbxCO, SIGNAL(activated(int)),
1446                 this, SLOT(biblioChanged()));
1447         connect(biblioModule->biblatexCbxCO, SIGNAL(editTextChanged(QString)),
1448                 this, SLOT(biblioChanged()));
1449         connect(biblioModule->biblatexCbxCO, SIGNAL(editTextChanged(QString)),
1450                 this, SLOT(updateResetDefaultBiblio()));
1451         connect(biblioModule->rescanBibliosPB, SIGNAL(clicked()),
1452                 this, SLOT(rescanBibFiles()));
1453         connect(biblioModule->resetDefaultBiblioPB, SIGNAL(clicked()),
1454                 this, SLOT(resetDefaultBibfile()));
1455         connect(biblioModule->resetCbxPB, SIGNAL(clicked()),
1456                 this, SLOT(resetDefaultCbxBibfile()));
1457         connect(biblioModule->resetBbxPB, SIGNAL(clicked()),
1458                 this, SLOT(resetDefaultBbxBibfile()));
1459         connect(biblioModule->matchBbxPB, SIGNAL(clicked()),
1460                 this, SLOT(matchBiblatexStyles()));
1461
1462         biblioModule->citeEngineCO->clear();
1463         for (LyXCiteEngine const & cet : theCiteEnginesList) {
1464                 biblioModule->citeEngineCO->addItem(qt_(cet.getName()), toqstr(cet.getID()));
1465                 int const i = biblioModule->citeEngineCO->findData(toqstr(cet.getID()));
1466                 biblioModule->citeEngineCO->setItemData(i, qt_(cet.getDescription()),
1467                                                         Qt::ToolTipRole);
1468         }
1469
1470         biblioModule->bibtexOptionsLE->setValidator(new NoNewLineValidator(
1471                 biblioModule->bibtexOptionsLE));
1472         biblioModule->defaultBiblioCO->lineEdit()->setValidator(new NoNewLineValidator(
1473                 biblioModule->defaultBiblioCO->lineEdit()));
1474         biblioModule->citePackageOptionsLE->setValidator(new NoNewLineValidator(
1475                 biblioModule->citePackageOptionsLE));
1476
1477         // NOTE: we do not provide "custom" here for security reasons!
1478         biblioModule->bibtexCO->clear();
1479         biblioModule->bibtexCO->addItem(qt_("Default"), QString("default"));
1480         for (auto const & alts : lyxrc.bibtex_alternatives) {
1481                 QString const command = toqstr(alts).left(toqstr(alts).indexOf(" "));
1482                 biblioModule->bibtexCO->addItem(command, command);
1483         }
1484
1485
1486         // indices
1487         indicesModule = new GuiIndices;
1488         connect(indicesModule, SIGNAL(changed()),
1489                 this, SLOT(change_adaptor()));
1490
1491
1492         // maths
1493         mathsModule = new UiWidget<Ui::MathsUi>(this);
1494         QStringList headers;
1495         headers << qt_("Package") << qt_("Load automatically")
1496                 << qt_("Load always") << qt_("Do not load");
1497         mathsModule->packagesTW->setHorizontalHeaderLabels(headers);
1498         mathsModule->packagesTW->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
1499         map<string, string> const & packages = BufferParams::auto_packages();
1500         mathsModule->packagesTW->setRowCount(packages.size());
1501         int packnum = 0;
1502         for (auto const & pkgvar : packages) {
1503                 docstring const package = from_ascii(pkgvar.first);
1504                 QString autoTooltip = qt_(pkgvar.second);
1505                 QString alwaysTooltip;
1506                 if (package == "amsmath")
1507                         alwaysTooltip =
1508                                 qt_("The AMS LaTeX packages are always used");
1509                 else
1510                         alwaysTooltip = toqstr(bformat(
1511                                 _("The LaTeX package %1$s is always used"),
1512                                 package));
1513                 QString neverTooltip;
1514                 if (package == "amsmath")
1515                         neverTooltip =
1516                                 qt_("The AMS LaTeX packages are never used");
1517                 else
1518                         neverTooltip = toqstr(bformat(
1519                                 _("The LaTeX package %1$s is never used"),
1520                                 package));
1521                 QRadioButton * autoRB = new QRadioButton(mathsModule);
1522                 QRadioButton * alwaysRB = new QRadioButton(mathsModule);
1523                 QRadioButton * neverRB = new QRadioButton(mathsModule);
1524                 QButtonGroup * packageGroup = new QButtonGroup(mathsModule);
1525                 packageGroup->addButton(autoRB);
1526                 packageGroup->addButton(alwaysRB);
1527                 packageGroup->addButton(neverRB);
1528                 autoRB->setToolTip(autoTooltip);
1529                 alwaysRB->setToolTip(alwaysTooltip);
1530                 neverRB->setToolTip(neverTooltip);
1531
1532                 // Pack the buttons in a layout in order to get proper alignment
1533                 QWidget * autoRBWidget = new QWidget();
1534                 QHBoxLayout * autoRBLayout = new QHBoxLayout(autoRBWidget);
1535                 autoRBLayout->addWidget(autoRB);
1536                 autoRBLayout->setAlignment(Qt::AlignCenter);
1537                 autoRBLayout->setContentsMargins(0, 0, 0, 0);
1538                 autoRBWidget->setLayout(autoRBLayout);
1539
1540                 QWidget * alwaysRBWidget = new QWidget();
1541                 QHBoxLayout * alwaysRBLayout = new QHBoxLayout(alwaysRBWidget);
1542                 alwaysRBLayout->addWidget(alwaysRB);
1543                 alwaysRBLayout->setAlignment(Qt::AlignCenter);
1544                 alwaysRBLayout->setContentsMargins(0, 0, 0, 0);
1545                 alwaysRBWidget->setLayout(alwaysRBLayout);
1546
1547                 QWidget * neverRBWidget = new QWidget();
1548                 QHBoxLayout * neverRBLayout = new QHBoxLayout(neverRBWidget);
1549                 neverRBLayout->addWidget(neverRB);
1550                 neverRBLayout->setAlignment(Qt::AlignCenter);
1551                 neverRBLayout->setContentsMargins(0, 0, 0, 0);
1552                 neverRBWidget->setLayout(neverRBLayout);
1553
1554                 QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package));
1555                 mathsModule->packagesTW->setItem(packnum, 0, pack);
1556                 mathsModule->packagesTW->setCellWidget(packnum, 1, autoRBWidget);
1557                 mathsModule->packagesTW->setCellWidget(packnum, 2, alwaysRBWidget);
1558                 mathsModule->packagesTW->setCellWidget(packnum, 3, neverRBWidget);
1559
1560                 connect(autoRB, SIGNAL(clicked()),
1561                         this, SLOT(change_adaptor()));
1562                 connect(alwaysRB, SIGNAL(clicked()),
1563                         this, SLOT(change_adaptor()));
1564                 connect(neverRB, SIGNAL(clicked()),
1565                         this, SLOT(change_adaptor()));
1566                 ++packnum;
1567         }
1568         connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()),
1569                 this, SLOT(allPackagesAuto()));
1570         connect(mathsModule->allPackagesAlwaysPB, SIGNAL(clicked()),
1571                 this, SLOT(allPackagesAlways()));
1572         connect(mathsModule->allPackagesNotPB, SIGNAL(clicked()),
1573                 this, SLOT(allPackagesNot()));
1574         connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()),
1575                 this, SLOT(change_adaptor()));
1576         connect(mathsModule->allPackagesAlwaysPB, SIGNAL(clicked()),
1577                 this, SLOT(change_adaptor()));
1578         connect(mathsModule->allPackagesNotPB, SIGNAL(clicked()),
1579                 this, SLOT(change_adaptor()));
1580         connect(mathsModule->MathNumberingPosCO, SIGNAL(activated(int)),
1581                 this, SLOT(change_adaptor()));
1582
1583         connect(mathsModule->MathIndentCB, SIGNAL(toggled(bool)),
1584                 this, SLOT(allowMathIndent()));
1585         connect(mathsModule->MathIndentCB, SIGNAL(toggled(bool)),
1586                 this, SLOT(change_adaptor()));
1587         connect(mathsModule->MathIndentCO, SIGNAL(activated(int)),
1588                 this, SLOT(enableMathIndent(int)));
1589         connect(mathsModule->MathIndentCO, SIGNAL(activated(int)),
1590                 this, SLOT(change_adaptor()));
1591         connect(mathsModule->MathIndentLE, SIGNAL(textChanged(const QString &)),
1592                 this, SLOT(change_adaptor()));
1593         connect(mathsModule->MathIndentLengthCO, SIGNAL(activated(int)),
1594                 this, SLOT(change_adaptor()));
1595
1596
1597         mathsModule->MathIndentCO->addItem(qt_("Default"), toqstr("default"));
1598         mathsModule->MathIndentCO->addItem(qt_("Custom"), toqstr("custom"));
1599         mathsModule->MathIndentLE->setValidator(new LengthValidator(
1600                 mathsModule->MathIndentLE, false));
1601         // initialize the length validator
1602         bc().addCheckedLineEdit(mathsModule->MathIndentLE, mathsModule->MathIndentCB);
1603         bc().addCheckedLineEditPanel(mathsModule->MathIndentLE, docPS, N_("Math Options"));
1604         mathsModule->MathNumberingPosCO->addItem(qt_("Left"));
1605         mathsModule->MathNumberingPosCO->addItem(qt_("Default"));
1606         mathsModule->MathNumberingPosCO->addItem(qt_("Right"));
1607         mathsModule->MathNumberingPosCO->setCurrentIndex(1);
1608
1609
1610         // latex class
1611         latexModule = new UiWidget<Ui::LaTeXUi>(this);
1612         connect(latexModule->optionsLE, SIGNAL(textChanged(QString)),
1613                 this, SLOT(change_adaptor()));
1614         connect(latexModule->defaultOptionsCB, SIGNAL(clicked()),
1615                 this, SLOT(change_adaptor()));
1616         connect(latexModule->psdriverCO, SIGNAL(activated(int)),
1617                 this, SLOT(change_adaptor()));
1618         connect(latexModule->classCO, SIGNAL(activated(int)),
1619                 this, SLOT(classChanged_adaptor()));
1620         connect(latexModule->classCO, SIGNAL(activated(int)),
1621                 this, SLOT(change_adaptor()));
1622         connect(latexModule->layoutPB, SIGNAL(clicked()),
1623                 this, SLOT(browseLayout()));
1624         connect(latexModule->layoutPB, SIGNAL(clicked()),
1625                 this, SLOT(change_adaptor()));
1626         connect(latexModule->childDocGB, SIGNAL(clicked()),
1627                 this, SLOT(change_adaptor()));
1628         connect(latexModule->childDocLE, SIGNAL(textChanged(QString)),
1629                 this, SLOT(change_adaptor()));
1630         connect(latexModule->childDocPB, SIGNAL(clicked()),
1631                 this, SLOT(browseMaster()));
1632         connect(latexModule->suppressDateCB, SIGNAL(clicked()),
1633                 this, SLOT(change_adaptor()));
1634         connect(latexModule->refstyleCB, SIGNAL(clicked()),
1635                 this, SLOT(change_adaptor()));
1636         connect(latexModule->refFormattedCB, SIGNAL(clicked()),
1637                 this, SLOT(change_adaptor()));
1638
1639         latexModule->optionsLE->setValidator(new NoNewLineValidator(
1640                 latexModule->optionsLE));
1641         latexModule->childDocLE->setValidator(new NoNewLineValidator(
1642                 latexModule->childDocLE));
1643
1644         // postscript drivers
1645         for (int n = 0; tex_graphics[n][0]; ++n) {
1646                 QString enc = qt_(tex_graphics_gui[n]);
1647                 latexModule->psdriverCO->addItem(enc);
1648         }
1649         // latex classes
1650         LayoutFileList const & bcl = LayoutFileList::get();
1651         vector<LayoutFileIndex> classList = bcl.classList();
1652         sort(classList.begin(), classList.end(), less_textclass_avail_desc());
1653
1654         for (auto const & cvar : classList) {
1655                 LayoutFile const & tc = bcl[cvar];
1656                 bool const available = tc.isTeXClassAvailable();
1657                 docstring const guiname = translateIfPossible(from_utf8(tc.description()));
1658                 // tooltip sensu "KOMA-Script Article [Class 'scrartcl']"
1659                 QString tooltip = toqstr(bformat(_("%1$s [Class '%2$s']"), guiname, from_utf8(tc.latexname())));
1660                 if (!available) {
1661                         docstring const output_type = _("LaTeX");
1662                         tooltip += '\n' + toqstr(bformat(_("Class not found by LyX. "
1663                                                            "Please check if you have the matching %1$s class "
1664                                                            "and all required packages (%2$s) installed."),
1665                                                          output_type, from_utf8(tc.prerequisites(", "))));
1666                 }
1667                 latexModule->classCO->addItemSort(toqstr(tc.name()),
1668                                                   toqstr(guiname),
1669                                                   toqstr(translateIfPossible(from_utf8(tc.category()))),
1670                                                   tooltip,
1671                                                   true, true, true, available);
1672         }
1673
1674
1675         // branches
1676         branchesModule = new GuiBranches(this);
1677         connect(branchesModule, SIGNAL(changed()),
1678                 this, SLOT(change_adaptor()));
1679         connect(branchesModule, SIGNAL(renameBranches(docstring const &, docstring const &)),
1680                 this, SLOT(branchesRename(docstring const &, docstring const &)));
1681         connect(branchesModule, SIGNAL(okPressed()), this, SLOT(slotOK()));
1682         updateUnknownBranches();
1683
1684
1685         // preamble
1686         preambleModule = new PreambleModule(this);
1687         connect(preambleModule, SIGNAL(changed()),
1688                 this, SLOT(change_adaptor()));
1689
1690         localLayout = new LocalLayout(this);
1691         connect(localLayout, SIGNAL(changed()),
1692                 this, SLOT(change_adaptor()));
1693
1694
1695         // bullets
1696         bulletsModule = new BulletsModule(this);
1697         connect(bulletsModule, SIGNAL(changed()),
1698                 this, SLOT(change_adaptor()));
1699
1700
1701         // Modules
1702         modulesModule = new UiWidget<Ui::ModulesUi>(this);
1703         modulesModule->availableLV->header()->setVisible(false);
1704         modulesModule->availableLV->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
1705         modulesModule->availableLV->header()->setStretchLastSection(false);
1706         modulesModule->selectedLV->header()->setVisible(false);
1707         modulesModule->selectedLV->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
1708         modulesModule->selectedLV->header()->setStretchLastSection(false);
1709         selectionManager =
1710                 new ModuleSelectionManager(this, modulesModule->availableLV,
1711                                            modulesModule->selectedLV,
1712                                            modulesModule->addPB,
1713                                            modulesModule->deletePB,
1714                                            modulesModule->upPB,
1715                                            modulesModule->downPB,
1716                                            availableModel(), selectedModel(), this);
1717         connect(selectionManager, SIGNAL(updateHook()),
1718                 this, SLOT(updateModuleInfo()));
1719         connect(selectionManager, SIGNAL(selectionChanged()),
1720                 this, SLOT(modulesChanged()));
1721         // The filter bar
1722         filter_ = new FancyLineEdit(this);
1723         filter_->setClearButton(true);
1724         filter_->setPlaceholderText(qt_("All avail. modules"));
1725         modulesModule->moduleFilterBarL->addWidget(filter_, 0);
1726         modulesModule->findModulesLA->setBuddy(filter_);
1727
1728         connect(filter_, SIGNAL(rightButtonClicked()),
1729                 this, SLOT(resetModuleFilter()));
1730         connect(filter_, SIGNAL(textEdited(QString)),
1731                 this, SLOT(moduleFilterChanged(QString)));
1732         connect(filter_, SIGNAL(returnPressed()),
1733                 this, SLOT(moduleFilterPressed()));
1734         connect(filter_, &FancyLineEdit::downPressed,
1735                 modulesModule->availableLV, [this](){ focusAndHighlight(modulesModule->availableLV); });
1736
1737
1738         // PDF support
1739         pdfSupportModule = new UiWidget<Ui::PDFSupportUi>(this);
1740         connect(pdfSupportModule->use_hyperrefGB, SIGNAL(toggled(bool)),
1741                 this, SLOT(change_adaptor()));
1742         connect(pdfSupportModule->titleLE, SIGNAL(textChanged(QString)),
1743                 this, SLOT(change_adaptor()));
1744         connect(pdfSupportModule->authorLE, SIGNAL(textChanged(QString)),
1745                 this, SLOT(change_adaptor()));
1746         connect(pdfSupportModule->subjectLE, SIGNAL(textChanged(QString)),
1747                 this, SLOT(change_adaptor()));
1748         connect(pdfSupportModule->keywordsLE, SIGNAL(textChanged(QString)),
1749                 this, SLOT(change_adaptor()));
1750         connect(pdfSupportModule->bookmarksGB, SIGNAL(toggled(bool)),
1751                 this, SLOT(change_adaptor()));
1752         connect(pdfSupportModule->bookmarksnumberedCB, SIGNAL(toggled(bool)),
1753                 this, SLOT(change_adaptor()));
1754         connect(pdfSupportModule->bookmarksopenGB, SIGNAL(toggled(bool)),
1755                 this, SLOT(change_adaptor()));
1756         connect(pdfSupportModule->bookmarksopenGB, SIGNAL(toggled(bool)),
1757                 this, SLOT(bookmarksopenChanged(bool)));
1758         connect(pdfSupportModule->bookmarksopenlevelSB, SIGNAL(valueChanged(int)),
1759                 this, SLOT(change_adaptor()));
1760         connect(pdfSupportModule->breaklinksCB, SIGNAL(toggled(bool)),
1761                 this, SLOT(change_adaptor()));
1762         connect(pdfSupportModule->pdfborderCB, SIGNAL(toggled(bool)),
1763                 this, SLOT(change_adaptor()));
1764         connect(pdfSupportModule->colorlinksCB, SIGNAL(toggled(bool)),
1765                 this, SLOT(change_adaptor()));
1766         connect(pdfSupportModule->backrefCO, SIGNAL(activated(int)),
1767                 this, SLOT(change_adaptor()));
1768         connect(pdfSupportModule->pdfusetitleCB, SIGNAL(toggled(bool)),
1769                 this, SLOT(change_adaptor()));
1770         connect(pdfSupportModule->fullscreenCB, SIGNAL(toggled(bool)),
1771                 this, SLOT(change_adaptor()));
1772         connect(pdfSupportModule->optionsTE, SIGNAL(textChanged()),
1773                 this, SLOT(change_adaptor()));
1774         connect(pdfSupportModule->metadataTE, SIGNAL(textChanged()),
1775                 this, SLOT(change_adaptor()));
1776
1777         pdfSupportModule->titleLE->setValidator(new NoNewLineValidator(
1778                 pdfSupportModule->titleLE));
1779         pdfSupportModule->authorLE->setValidator(new NoNewLineValidator(
1780                 pdfSupportModule->authorLE));
1781         pdfSupportModule->subjectLE->setValidator(new NoNewLineValidator(
1782                 pdfSupportModule->subjectLE));
1783         pdfSupportModule->keywordsLE->setValidator(new NoNewLineValidator(
1784                 pdfSupportModule->keywordsLE));
1785
1786         pdf_options_highlighter_ = new LaTeXHighlighter(
1787                                 pdfSupportModule->optionsTE->document(), true, true);
1788         pdf_metadata_highlighter_ = new LaTeXHighlighter(
1789                                 pdfSupportModule->metadataTE->document(), true, true);
1790
1791         for (int i = 0; backref_opts[i][0]; ++i)
1792                 pdfSupportModule->backrefCO->addItem(qt_(backref_opts_gui[i]));
1793
1794
1795         // float
1796         floatModule = new FloatPlacement;
1797         connect(floatModule, SIGNAL(changed()),
1798                 this, SLOT(change_adaptor()));
1799
1800
1801         // listings
1802         listingsModule = new UiWidget<Ui::ListingsSettingsUi>(this);
1803         connect(listingsModule->listingsED, SIGNAL(textChanged()),
1804                 this, SLOT(change_adaptor()));
1805         connect(listingsModule->bypassCB, SIGNAL(clicked()),
1806                 this, SLOT(change_adaptor()));
1807         connect(listingsModule->bypassCB, SIGNAL(clicked()),
1808                 this, SLOT(setListingsMessage()));
1809         connect(listingsModule->packageCO, SIGNAL(activated(int)),
1810                 this, SLOT(change_adaptor()));
1811         connect(listingsModule->packageCO, SIGNAL(activated(int)),
1812                 this, SLOT(listingsPackageChanged(int)));
1813         connect(listingsModule->listingsED, SIGNAL(textChanged()),
1814                 this, SLOT(setListingsMessage()));
1815         listingsModule->listingsTB->setPlainText(
1816                 qt_("Input listings parameters below. Enter ? for a list of parameters."));
1817
1818         for (int i = 0; lst_packages[i][0]; ++i)
1819                 listingsModule->packageCO->addItem(lst_packages[i]);
1820
1821
1822         // add the panels
1823         docPS->addPanel(latexModule, N_("Document Class"));
1824         docPS->addPanel(masterChildModule, N_("Child Documents"));
1825         docPS->addPanel(modulesModule, N_("Modules"));
1826         docPS->addPanel(localLayout, N_("Local Layout"));
1827         docPS->addPanel(fontModule, N_("Fonts"));
1828         docPS->addPanel(textLayoutModule, N_("Text Layout"));
1829         docPS->addPanel(pageLayoutModule, N_("Page Layout"));
1830         docPS->addPanel(marginsModule, N_("Page Margins"));
1831         docPS->addPanel(langModule, N_("Language"));
1832         docPS->addPanel(colorModule, N_("Colors"));
1833         docPS->addPanel(changesModule, N_("Change Tracking"));
1834         docPS->addPanel(numberingModule, N_("Numbering & TOC"));
1835         docPS->addPanel(biblioModule, N_("Bibliography"));
1836         docPS->addPanel(indicesModule, N_("Indexes"));
1837         docPS->addPanel(pdfSupportModule, N_("PDF Properties"));
1838         docPS->addPanel(mathsModule, N_("Math Options"));
1839         docPS->addPanel(floatModule, N_("Float Settings"));
1840         docPS->addPanel(listingsModule, N_("Listings[[inset]]"));
1841         docPS->addPanel(bulletsModule, N_("Bullets"));
1842         docPS->addPanel(branchesModule, N_("Branches"));
1843         docPS->addPanel(outputModule, N_("Output"));
1844         docPS->addPanel(preambleModule, N_("LaTeX Preamble"));
1845         docPS->setCurrentPanel("Document Class");
1846
1847         // Filter out (dark/light) mode changes
1848         installEventFilter(this);
1849 }
1850
1851
1852 void GuiDocument::onClosing(int const id)
1853 {
1854         if (!guiApp || !guiApp->currentView()
1855             || guiApp->currentView()->id() != id
1856             || !bc().policy().buttonStatus(ButtonPolicy::RESTORE))
1857                 // notthing to do
1858                 return;
1859
1860         int const ret = Alert::prompt(_("Unapplied changes"),
1861                         _("Some changes in the document were not yet applied.\n"
1862                         "Do you want to apply them before closing?"),
1863                         1, 1, _("Yes, &Apply"), _("No, &Dismiss Changes"));
1864         if (ret == 0)
1865                 slotOK();
1866 }
1867
1868
1869 void GuiDocument::onBufferViewChanged()
1870 {
1871         if (switchback_) {
1872                 // We are just switching back. Nothing to do.
1873                 switchback_ = false;
1874                 return;
1875         }
1876         BufferView const * view = bufferview();
1877         string const new_filename = view ? view->buffer().absFileName() : string();
1878         // If we switched buffer really and the previous file name is different to
1879         // the current one, we ask on unapplied changes (#9369)
1880         // FIXME: This is more complicated than it should be. Why do we need these to cycles?
1881         // And ideally, we should propose to apply without having to switch back
1882         // (e.g., via a LFUN_BUFFER_PARAMS_APPLY_OTHER)
1883         if (!prev_buffer_filename_.empty() && prev_buffer_filename_ != new_filename
1884             && buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
1885                 // Only ask if we haven't yet in this cycle
1886                 int const ret = prompted_ ? 3 : Alert::prompt(_("Unapplied changes"),
1887                                 _("Some changes in the previous document were not yet applied.\n"
1888                                 "Do you want to switch back in order to apply them or dismiss the changes?"),
1889                                 1, 1, _("&Switch Back"), _("&Dismiss Changes"));
1890                 if (ret == 0) {
1891                         // Switch to previous buffer view and apply
1892                         switchback_ = true;
1893                         // Record that we have asked.
1894                         prompted_ = true;
1895                         lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH, prev_buffer_filename_));
1896                         return;
1897                 } else if (ret == 3) {
1898                         // We are in the second cycle. Set back.
1899                         prompted_ = false;
1900                         return;
1901                 }
1902         }
1903
1904         if (isVisibleView())
1905                 initialiseParams("");
1906 }
1907
1908
1909 void GuiDocument::saveDefaultClicked()
1910 {
1911         saveDocDefault();
1912 }
1913
1914
1915 void GuiDocument::useDefaultsClicked()
1916 {
1917         useClassDefaults();
1918 }
1919
1920
1921 void GuiDocument::change_adaptor()
1922 {
1923         nonModuleChanged_ = true;
1924         changed();
1925 }
1926
1927
1928 void GuiDocument::shellescapeChanged()
1929 {
1930         shellescapeChanged_ = true;
1931         changed();
1932 }
1933
1934 void GuiDocument::bookmarksopenChanged(bool state)
1935 {
1936         pdfSupportModule->bookmarksopenlevelSB->setEnabled(state);
1937         pdfSupportModule->bookmarksopenlevelLA->setEnabled(state);
1938 }
1939
1940
1941 void GuiDocument::changeTrackingChanged(bool state)
1942 {
1943         // This is triggered if the CT state is toggled outside
1944         // the document dialog (e.g., menu).
1945         changesModule->trackChangesCB->setChecked(state);
1946 }
1947
1948
1949 void GuiDocument::slotApply()
1950 {
1951         bool only_shellescape_changed = !nonModuleChanged_ && !modulesChanged_;
1952         bool wasclean = buffer().isClean();
1953         GuiDialog::slotApply();
1954         if (wasclean && only_shellescape_changed)
1955                 buffer().markClean();
1956         modulesChanged_ = false;
1957         isValid();
1958 }
1959
1960
1961 void GuiDocument::slotOK()
1962 {
1963         bool only_shellescape_changed = !nonModuleChanged_ && !modulesChanged_;
1964         bool wasclean = buffer().isClean();
1965         GuiDialog::slotOK();
1966         if (wasclean && only_shellescape_changed)
1967                 buffer().markClean();
1968         modulesChanged_ = false;
1969 }
1970
1971
1972 void GuiDocument::slotButtonBox(QAbstractButton * button)
1973 {
1974         switch (buttonBox->standardButton(button)) {
1975         case QDialogButtonBox::Ok:
1976                 slotOK();
1977                 break;
1978         case QDialogButtonBox::Apply:
1979                 slotApply();
1980                 break;
1981         case QDialogButtonBox::Cancel:
1982                 slotClose();
1983                 break;
1984         case QDialogButtonBox::Reset:
1985         case QDialogButtonBox::RestoreDefaults:
1986                 slotRestore();
1987                 break;
1988         default:
1989                 break;
1990         }
1991 }
1992
1993
1994 void GuiDocument::filterModules(QString const & str)
1995 {
1996         updateAvailableModules();
1997         if (str.isEmpty())
1998                 return;
1999
2000         modules_av_model_.clear();
2001         list<modInfoStruct> modInfoList = getModuleInfo();
2002         // Sort names according to the locale
2003         modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
2004                         return 0 < b.name.localeAwareCompare(a.name);
2005                 });
2006
2007         QIcon user_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-user")
2008                                : getPixmap("images/", "lyxfiles-user", "svgz,png"));
2009         QIcon system_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-system")
2010                                  : getPixmap("images/", "lyxfiles-system", "svgz,png"));
2011
2012         int i = 0;
2013         for (modInfoStruct const & m : modInfoList) {
2014                 if (m.name.contains(str, Qt::CaseInsensitive) || contains(m.id, fromqstr(str))) {
2015                         QStandardItem * item = new QStandardItem();
2016                         item->setData(m.name, Qt::DisplayRole);
2017                         item->setData(toqstr(m.id), Qt::UserRole);
2018                         item->setData(m.description, Qt::ToolTipRole);
2019                         item->setEditable(false);
2020                         if (m.local)
2021                                 item->setIcon(user_icon);
2022                         else
2023                                 item->setIcon(system_icon);
2024                         modules_av_model_.insertRow(i, item);
2025                         ++i;
2026                 }
2027         }
2028 }
2029
2030
2031 void GuiDocument::moduleFilterChanged(const QString & text)
2032 {
2033         if (!text.isEmpty()) {
2034                 filterModules(filter_->text());
2035                 return;
2036         }
2037         filterModules(filter_->text());
2038         filter_->setFocus();
2039 }
2040
2041
2042 void GuiDocument::moduleFilterPressed()
2043 {
2044         filterModules(filter_->text());
2045 }
2046
2047
2048 void GuiDocument::resetModuleFilter()
2049 {
2050         filter_->setText(QString());
2051         filterModules(filter_->text());
2052 }
2053
2054
2055 void GuiDocument::includeonlyClicked(QTreeWidgetItem * item, int)
2056 {
2057         if (item == nullptr)
2058                 return;
2059
2060         string child = fromqstr(item->text(0));
2061
2062         if (child.empty())
2063                 return;
2064
2065         if (isChildIncluded(child))
2066                 includeonlys_.remove(child);
2067         else
2068                 includeonlys_.push_back(child);
2069
2070         updateIncludeonlys(false);
2071         change_adaptor();
2072 }
2073
2074
2075 QString GuiDocument::validateListingsParameters()
2076 {
2077         if (listingsModule->bypassCB->isChecked())
2078                 return QString();
2079         string const package =
2080             lst_packages[listingsModule->packageCO->currentIndex()];
2081         string params = fromqstr(listingsModule->listingsED->toPlainText());
2082         InsetListingsParams lstparams(params);
2083         lstparams.setMinted(package == "Minted");
2084         return toqstr(lstparams.validate());
2085 }
2086
2087
2088 void GuiDocument::setListingsMessage()
2089 {
2090         // FIXME THREAD
2091         static bool isOK = true;
2092         QString msg = validateListingsParameters();
2093         if (msg.isEmpty()) {
2094                 listingsModule->listingsTB->setTextColor(QColor());
2095                 if (isOK)
2096                         return;
2097                 isOK = true;
2098                 listingsModule->listingsTB->setPlainText(
2099                         qt_("Input listings parameters below. "
2100                             "Enter ? for a list of parameters."));
2101         } else {
2102                 isOK = false;
2103                 listingsModule->listingsTB->setTextColor(QColor(255, 0, 0));
2104                 listingsModule->listingsTB->setPlainText(msg);
2105         }
2106 }
2107
2108
2109 void GuiDocument::listingsPackageChanged(int index)
2110 {
2111         string const package = lst_packages[index];
2112         if (package == "Minted" && lyxrc.pygmentize_command.empty()) {
2113                 Alert::warning(_("Pygments driver command not found!"),
2114                     _("The driver command necessary to use the minted package\n"
2115                       "(pygmentize) has not been found. Make sure you have\n"
2116                       "the python-pygments module installed or, if the driver\n"
2117                       "is named differently, to add the following line to the\n"
2118                       "document preamble:\n\n"
2119                       "\\AtBeginDocument{\\renewcommand{\\MintedPygmentize}{driver}}\n\n"
2120                       "where 'driver' is name of the driver command."));
2121         }
2122 }
2123
2124
2125 void GuiDocument::setLSpacing(int item)
2126 {
2127         textLayoutModule->lspacingLE->setEnabled(item == 3);
2128 }
2129
2130
2131 void GuiDocument::setIndent(int item)
2132 {
2133         bool const enable = (textLayoutModule->indentCO->itemData(item) == "custom");
2134         textLayoutModule->indentLE->setEnabled(enable);
2135         textLayoutModule->indentLengthCO->setEnabled(enable);
2136         textLayoutModule->skipLE->setEnabled(false);
2137         textLayoutModule->skipLengthCO->setEnabled(false);
2138         // needed to catch empty custom case
2139         bc().refresh();
2140         isValid();
2141 }
2142
2143
2144 void GuiDocument::enableIndent(bool indent)
2145 {
2146         textLayoutModule->skipLE->setEnabled(!indent);
2147         textLayoutModule->skipLengthCO->setEnabled(!indent);
2148         if (indent)
2149                 setIndent(textLayoutModule->indentCO->currentIndex());
2150 }
2151
2152
2153 void GuiDocument::setSkip(int item)
2154 {
2155         VSpace::VSpaceKind kind =
2156                 VSpace::VSpaceKind(textLayoutModule->skipCO->itemData(item).toInt());
2157         bool const enable = (kind == VSpace::LENGTH);
2158         textLayoutModule->skipLE->setEnabled(enable);
2159         textLayoutModule->skipLengthCO->setEnabled(enable);
2160         // needed to catch empty custom case
2161         bc().refresh();
2162         isValid();
2163 }
2164
2165
2166 void GuiDocument::enableSkip(bool skip)
2167 {
2168         textLayoutModule->indentLE->setEnabled(!skip);
2169         textLayoutModule->indentLengthCO->setEnabled(!skip);
2170         if (skip)
2171                 setSkip(textLayoutModule->skipCO->currentIndex());
2172 }
2173
2174 void GuiDocument::allowMathIndent() {
2175         // only disable when not checked, checked does not always allow enabling
2176         if (!mathsModule->MathIndentCB->isChecked()) {
2177                 mathsModule->MathIndentLE->setEnabled(false);
2178                 mathsModule->MathIndentLengthCO->setEnabled(false);
2179         }
2180         if (mathsModule->MathIndentCB->isChecked()
2181             && mathsModule->MathIndentCO->itemData(mathsModule->MathIndentCO->currentIndex()) == "custom") {
2182                         mathsModule->MathIndentLE->setEnabled(true);
2183                         mathsModule->MathIndentLengthCO->setEnabled(true);
2184         }
2185         isValid();
2186 }
2187
2188 void GuiDocument::enableMathIndent(int item)
2189 {
2190         bool const enable = (item == 1);
2191         mathsModule->MathIndentLE->setEnabled(enable);
2192         mathsModule->MathIndentLengthCO->setEnabled(enable);
2193         // needed to catch empty custom case
2194         bc().refresh();
2195         isValid();
2196 }
2197
2198
2199 void GuiDocument::setMargins()
2200 {
2201         bool const extern_geometry =
2202                 documentClass().provides("geometry");
2203         marginsModule->marginCB->setEnabled(!extern_geometry);
2204         if (extern_geometry) {
2205                 marginsModule->marginCB->setChecked(false);
2206                 setCustomMargins(true);
2207         } else {
2208                 marginsModule->marginCB->setChecked(!bp_.use_geometry);
2209                 setCustomMargins(!bp_.use_geometry);
2210         }
2211 }
2212
2213
2214 void GuiDocument::papersizeChanged(int paper_size)
2215 {
2216         setCustomPapersize(paper_size == 1);
2217 }
2218
2219
2220 void GuiDocument::setCustomPapersize(bool custom)
2221 {
2222         pageLayoutModule->paperwidthL->setEnabled(custom);
2223         pageLayoutModule->paperwidthLE->setEnabled(custom);
2224         pageLayoutModule->paperwidthUnitCO->setEnabled(custom);
2225         pageLayoutModule->paperheightL->setEnabled(custom);
2226         pageLayoutModule->paperheightLE->setEnabled(custom);
2227         pageLayoutModule->paperheightLE->setFocus();
2228         pageLayoutModule->paperheightUnitCO->setEnabled(custom);
2229 }
2230
2231
2232 void GuiDocument::setColSep()
2233 {
2234         setCustomMargins(marginsModule->marginCB->checkState() == Qt::Checked);
2235 }
2236
2237
2238 void GuiDocument::setCustomMargins(bool cb_checked)
2239 {
2240         bool const custom_margins = !cb_checked;
2241         if (custom_margins) {
2242                 Length::UNIT const default_unit = Length::defaultUnit();
2243                 // fill with chached values
2244                 lengthToWidgets(marginsModule->topLE,
2245                                 marginsModule->topUnit,
2246                                 tmp_topmargin_, default_unit);
2247                 lengthToWidgets(marginsModule->bottomLE,
2248                                 marginsModule->bottomUnit,
2249                                 tmp_bottommargin_, default_unit);
2250                 lengthToWidgets(marginsModule->innerLE,
2251                                 marginsModule->innerUnit,
2252                                 tmp_leftmargin_, default_unit);
2253                 lengthToWidgets(marginsModule->outerLE,
2254                                 marginsModule->outerUnit,
2255                                 tmp_rightmargin_, default_unit);
2256                 lengthToWidgets(marginsModule->headheightLE,
2257                                 marginsModule->headheightUnit,
2258                                 tmp_headheight_, default_unit);
2259                 lengthToWidgets(marginsModule->headsepLE,
2260                                 marginsModule->headsepUnit,
2261                                 tmp_headsep_, default_unit);
2262                 lengthToWidgets(marginsModule->footskipLE,
2263                                 marginsModule->footskipUnit,
2264                                 tmp_footskip_, default_unit);
2265                 lengthToWidgets(marginsModule->columnsepLE,
2266                                 marginsModule->columnsepUnit,
2267                                 tmp_columnsep_, default_unit);
2268         } else { // default margins
2269                 // Cache current values
2270                 tmp_leftmargin_ = widgetsToLength(marginsModule->innerLE,
2271                                                   marginsModule->innerUnit);
2272                 tmp_topmargin_ = widgetsToLength(marginsModule->topLE,
2273                                                  marginsModule->topUnit);
2274                 tmp_rightmargin_ = widgetsToLength(marginsModule->outerLE,
2275                                                    marginsModule->outerUnit);
2276                 tmp_bottommargin_ = widgetsToLength(marginsModule->bottomLE,
2277                                                     marginsModule->bottomUnit);
2278                 tmp_headheight_ = widgetsToLength(marginsModule->headheightLE,
2279                                                   marginsModule->headheightUnit);
2280                 tmp_headsep_ = widgetsToLength(marginsModule->headsepLE,
2281                                                marginsModule->headsepUnit);
2282                 tmp_footskip_ = widgetsToLength(marginsModule->footskipLE,
2283                                                 marginsModule->footskipUnit);
2284                 tmp_columnsep_ = widgetsToLength(marginsModule->columnsepLE,
2285                                                  marginsModule->columnsepUnit);
2286                 // clear widgets
2287                 marginsModule->topLE->clear();
2288                 marginsModule->bottomLE->clear();
2289                 marginsModule->innerLE->clear();
2290                 marginsModule->outerLE->clear();
2291                 marginsModule->headheightLE->clear();
2292                 marginsModule->headsepLE->clear();
2293                 marginsModule->footskipLE->clear();
2294                 marginsModule->columnsepLE->clear();
2295         }
2296
2297         marginsModule->topL->setEnabled(custom_margins);
2298         marginsModule->topLE->setEnabled(custom_margins);
2299         marginsModule->topUnit->setEnabled(custom_margins);
2300
2301         marginsModule->bottomL->setEnabled(custom_margins);
2302         marginsModule->bottomLE->setEnabled(custom_margins);
2303         marginsModule->bottomUnit->setEnabled(custom_margins);
2304
2305         marginsModule->innerL->setEnabled(custom_margins);
2306         marginsModule->innerLE->setEnabled(custom_margins);
2307         marginsModule->innerUnit->setEnabled(custom_margins);
2308
2309         marginsModule->outerL->setEnabled(custom_margins);
2310         marginsModule->outerLE->setEnabled(custom_margins);
2311         marginsModule->outerUnit->setEnabled(custom_margins);
2312
2313         marginsModule->headheightL->setEnabled(custom_margins);
2314         marginsModule->headheightLE->setEnabled(custom_margins);
2315         marginsModule->headheightUnit->setEnabled(custom_margins);
2316
2317         marginsModule->headsepL->setEnabled(custom_margins);
2318         marginsModule->headsepLE->setEnabled(custom_margins);
2319         marginsModule->headsepUnit->setEnabled(custom_margins);
2320
2321         marginsModule->footskipL->setEnabled(custom_margins);
2322         marginsModule->footskipLE->setEnabled(custom_margins);
2323         marginsModule->footskipUnit->setEnabled(custom_margins);
2324
2325         bool const enableColSep = custom_margins &&
2326                         textLayoutModule->twoColumnCB->isChecked();
2327         marginsModule->columnsepL->setEnabled(enableColSep);
2328         marginsModule->columnsepLE->setEnabled(enableColSep);
2329         marginsModule->columnsepUnit->setEnabled(enableColSep);
2330
2331         // set some placeholder text that hint on defaults
2332         QString const placeholder = marginsModule->marginCB->isChecked() ?
2333                 qt_("Default margins") : qt_("Package defaults");
2334         // set tooltip depending on gemoetry state
2335         QString const tooltip = marginsModule->marginCB->isChecked() ?
2336                 qt_("If no value is given, the defaults as set by the class, a package or the preamble are used.")
2337                 : qt_("If no value is given, the defaults as set by the geometry package or a package/class overriding geometry's defaults are used.");
2338         marginsModule->topLE->setPlaceholderText(placeholder);
2339         marginsModule->bottomLE->setPlaceholderText(placeholder);
2340         marginsModule->innerLE->setPlaceholderText(placeholder);
2341         marginsModule->outerLE->setPlaceholderText(placeholder);
2342         marginsModule->headheightLE->setPlaceholderText(placeholder);
2343         marginsModule->headsepLE->setPlaceholderText(placeholder);
2344         marginsModule->footskipLE->setPlaceholderText(placeholder);
2345         marginsModule->columnsepLE->setPlaceholderText(placeholder);
2346         marginsModule->topLE->setToolTip(tooltip);
2347         marginsModule->bottomLE->setToolTip(tooltip);
2348         marginsModule->innerLE->setToolTip(tooltip);
2349         marginsModule->outerLE->setToolTip(tooltip);
2350         marginsModule->headheightLE->setToolTip(tooltip);
2351         marginsModule->headsepLE->setToolTip(tooltip);
2352         marginsModule->footskipLE->setToolTip(tooltip);
2353         marginsModule->columnsepLE->setToolTip(tooltip);
2354 }
2355
2356
2357 void GuiDocument::changeBackgroundColor()
2358 {
2359         QColor const & newColor = getColor(rgb2qcolor(set_backgroundcolor));
2360         if (!newColor.isValid())
2361                 return;
2362         // set the color
2363         colorModule->pageBackgroundCF->setVisible(true);
2364         colorModule->pageBackgroundCF->setStyleSheet(
2365                 colorFrameStyleSheet(newColor));
2366         // save color
2367         set_backgroundcolor = rgbFromHexName(fromqstr(newColor.name()));
2368         is_backgroundcolor = true;
2369         change_adaptor();
2370 }
2371
2372
2373 void GuiDocument::deleteBackgroundColor()
2374 {
2375         // set the color back to default by setting an empty StyleSheet
2376         colorModule->pageBackgroundCF->setStyleSheet(QLatin1String(""));
2377         colorModule->pageBackgroundCF->setVisible(false);
2378         // save default color (white)
2379         set_backgroundcolor = rgbFromHexName("#ffffff");
2380         is_backgroundcolor = false;
2381         change_adaptor();
2382 }
2383
2384
2385 void GuiDocument::changeFontColor()
2386 {
2387         QColor const & newColor = getColor(rgb2qcolor(set_fontcolor));
2388         if (!newColor.isValid())
2389                 return;
2390         //  set the color
2391         colorModule->mainTextCF->setVisible(true);
2392         colorModule->mainTextCF->setStyleSheet(
2393                 colorFrameStyleSheet(newColor));
2394         // save color
2395         set_fontcolor = rgbFromHexName(fromqstr(newColor.name()));
2396         is_fontcolor = true;
2397         change_adaptor();
2398 }
2399
2400
2401 void GuiDocument::deleteFontColor()
2402 {
2403         // set the button color back to default by setting an empty StyleSheet
2404         colorModule->mainTextCF->setStyleSheet(QLatin1String(""));
2405         colorModule->mainTextCF->setVisible(false);
2406         // save default color (black)
2407         set_fontcolor = rgbFromHexName("#000000");
2408         is_fontcolor = false;
2409         change_adaptor();
2410 }
2411
2412
2413 void GuiDocument::changeNoteFontColor()
2414 {
2415         QColor const & newColor = getColor(rgb2qcolor(set_notefontcolor));
2416         if (!newColor.isValid())
2417                 return;
2418         // set the color
2419         colorModule->noteFontCF->setStyleSheet(
2420                 colorFrameStyleSheet(newColor));
2421         // save color
2422         set_notefontcolor = rgbFromHexName(fromqstr(newColor.name()));
2423         is_notefontcolor = true;
2424         change_adaptor();
2425 }
2426
2427
2428 void GuiDocument::deleteNoteFontColor()
2429 {
2430         // set the color back to pref
2431         theApp()->getRgbColor(Color_greyedouttext, set_notefontcolor);
2432         colorModule->noteFontCF->setStyleSheet(
2433                 colorFrameStyleSheet(rgb2qcolor(set_notefontcolor)));
2434         is_notefontcolor = false;
2435         change_adaptor();
2436 }
2437
2438
2439 void GuiDocument::changeBoxBackgroundColor()
2440 {
2441         QColor const & newColor = getColor(rgb2qcolor(set_boxbgcolor));
2442         if (!newColor.isValid())
2443                 return;
2444         // set the color
2445         colorModule->boxBackgroundCF->setStyleSheet(
2446                 colorFrameStyleSheet(newColor));
2447         // save color
2448         set_boxbgcolor = rgbFromHexName(fromqstr(newColor.name()));
2449         is_boxbgcolor = true;
2450         change_adaptor();
2451 }
2452
2453
2454 void GuiDocument::deleteBoxBackgroundColor()
2455 {
2456         // set the color back to pref
2457         theApp()->getRgbColor(Color_shadedbg, set_boxbgcolor);
2458         colorModule->boxBackgroundCF->setStyleSheet(
2459                 colorFrameStyleSheet(rgb2qcolor(set_boxbgcolor)));
2460         is_boxbgcolor = false;
2461         change_adaptor();
2462 }
2463
2464
2465 void GuiDocument::updateQuoteStyles(bool const set)
2466 {
2467         Language const * lang = lyx::languages.getLanguage(
2468                 fromqstr(langModule->languageCO->itemData(
2469                         langModule->languageCO->currentIndex()).toString()));
2470
2471         QuoteStyle def = bp_.getQuoteStyle(lang->quoteStyle());
2472
2473         langModule->quoteStyleCO->clear();
2474
2475         bool has_default = false;
2476         for (int i = 0; i < quoteparams.stylescount(); ++i) {
2477                 QuoteStyle qs = QuoteStyle(i);
2478                 if (qs == QuoteStyle::Dynamic)
2479                         continue;
2480                 bool const langdef = (qs == def);
2481                 if (langdef) {
2482                         // add the default style on top
2483                         langModule->quoteStyleCO->insertItem(0,
2484                                 toqstr(quoteparams.getGuiLabel(qs, langdef)), static_cast<int>(qs));
2485                         has_default = true;
2486                 }
2487                 else
2488                         langModule->quoteStyleCO->addItem(
2489                                 toqstr(quoteparams.getGuiLabel(qs, langdef)), static_cast<int>(qs));
2490         }
2491         // Use document serif font to assure quotation marks are distinguishable
2492         QFont comboFont(toqstr(lyxrc.roman_font_name),
2493                         langModule->quoteStyleCO->fontInfo().pointSize() * 1.4, -1, false);
2494         QFontMetrics fm(comboFont);
2495         // calculate width of the widest item in the set font
2496         int qswidth = 0;
2497         for (int i = 0; i < langModule->quoteStyleCO->count(); ++i) {
2498                 langModule->quoteStyleCO->setItemData(i, QVariant(comboFont), Qt::FontRole);
2499                 QString str = langModule->quoteStyleCO->itemText(i);
2500 #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
2501                 qswidth = max(qswidth, fm.horizontalAdvance(str));
2502 #else
2503                 qswidth = max(qswidth, fm.width(str));
2504 #endif
2505         }
2506         // add scrollbar width and margin to width
2507         qswidth += langModule->quoteStyleCO->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
2508         qswidth += langModule->quoteStyleCO->view()->autoScrollMargin();
2509         langModule->quoteStyleCO->view()->setMinimumWidth(qswidth);
2510         if (set && has_default)
2511                 // (re)set to the default style
2512                 langModule->quoteStyleCO->setCurrentIndex(0);
2513 }
2514
2515
2516 void GuiDocument::languageChanged(int i)
2517 {
2518         // some languages only work with Polyglossia
2519         Language const * lang = lyx::languages.getLanguage(
2520                 fromqstr(langModule->languageCO->itemData(i).toString()));
2521         if (lang->babel().empty() && !lang->polyglossia().empty()
2522                 && lang->required() != "CJK" && lang->required() != "japanese") {
2523                         // If we force to switch fontspec on, store
2524                         // current state (#8717)
2525                         if (fontModule->osFontsCB->isEnabled())
2526                                 forced_fontspec_activation =
2527                                         !fontModule->osFontsCB->isChecked();
2528                         fontModule->osFontsCB->setChecked(true);
2529                         fontModule->osFontsCB->setEnabled(false);
2530         }
2531         else {
2532                 fontModule->osFontsCB->setEnabled(true);
2533                 // If we have forced to switch fontspec on,
2534                 // restore previous state (#8717)
2535                 if (forced_fontspec_activation)
2536                         fontModule->osFontsCB->setChecked(false);
2537                 forced_fontspec_activation = false;
2538         }
2539
2540         // set appropriate quotation mark style
2541         updateQuoteStyles(true);
2542 }
2543
2544
2545 void GuiDocument::osFontsChanged(bool nontexfonts)
2546 {
2547         bool const tex_fonts = !nontexfonts;
2548         // store current fonts
2549         QString const font_roman = fontModule->fontsRomanCO->getData(
2550                         fontModule->fontsRomanCO->currentIndex());
2551         QString const font_sans = fontModule->fontsSansCO->getData(
2552                         fontModule->fontsSansCO->currentIndex());
2553         QString const font_typewriter = fontModule->fontsTypewriterCO->getData(
2554                         fontModule->fontsTypewriterCO->currentIndex());
2555         QString const font_math = fontModule->fontsMathCO->itemData(
2556                         fontModule->fontsMathCO->currentIndex()).toString();
2557         int const font_sf_scale = fontModule->scaleSansSB->value();
2558         int const font_tt_scale = fontModule->scaleTypewriterSB->value();
2559
2560         updateFontlist();
2561         // store default format
2562         QString const dformat = outputModule->defaultFormatCO->itemData(
2563                 outputModule->defaultFormatCO->currentIndex()).toString();
2564         updateDefaultFormat();
2565         // try to restore default format
2566         int index = outputModule->defaultFormatCO->findData(dformat);
2567         // set to default if format is not found
2568         if (index == -1)
2569                 index = 0;
2570         outputModule->defaultFormatCO->setCurrentIndex(index);
2571
2572         // try to restore fonts which were selected two toggles ago
2573         if (!fontModule->font_roman.isEmpty())
2574                 fontModule->fontsRomanCO->set(fontModule->font_roman);
2575         if (!fontModule->font_sans.isEmpty())
2576                 fontModule->fontsSansCO->set(fontModule->font_sans);
2577         if (!fontModule->font_typewriter.isEmpty())
2578                 fontModule->fontsTypewriterCO->set(fontModule->font_typewriter);
2579         index = fontModule->fontsMathCO->findData(fontModule->font_math);
2580         if (index != -1)
2581                 fontModule->fontsMathCO->setCurrentIndex(index);
2582         // save fonts for next next toggle
2583         fontModule->font_roman = font_roman;
2584         fontModule->font_sans = font_sans;
2585         fontModule->font_typewriter = font_typewriter;
2586         fontModule->font_math = font_math;
2587         fontModule->font_sf_scale = font_sf_scale;
2588         fontModule->font_tt_scale = font_tt_scale;
2589
2590         // non-tex fonts override the "\inputencoding" option with "utf8-plain"
2591         langModule->encodingCO->setEnabled(tex_fonts);
2592         inputencodingToDialog();
2593
2594         fontModule->cjkFontLE->setEnabled(tex_fonts);
2595         fontModule->cjkFontLA->setEnabled(tex_fonts);
2596
2597         updateFontOptions();
2598
2599         fontModule->fontencLA->setEnabled(tex_fonts);
2600         fontModule->fontencCO->setEnabled(tex_fonts);
2601         if (!tex_fonts)
2602                 fontModule->fontencLE->setEnabled(false);
2603         else
2604                 fontencChanged(fontModule->fontencCO->currentIndex());
2605 }
2606
2607
2608 void GuiDocument::encodingSwitched(int i)
2609 {
2610         bool const tex_fonts = !fontModule->osFontsCB->isChecked();
2611         langModule->unicodeEncodingCO->setEnabled(tex_fonts);
2612         langModule->customEncodingCO->setEnabled(tex_fonts);
2613         langModule->autoEncodingCO->setEnabled(tex_fonts);
2614         langModule->unicodeEncodingCO->setVisible(i == EncodingSets::unicode);
2615         langModule->autoEncodingCO->setVisible(i == EncodingSets::legacy);
2616         langModule->customEncodingCO->setVisible(i == EncodingSets::custom);
2617         switch (i) {
2618         case EncodingSets::unicode:
2619                 langModule->encodingVariantLA->setBuddy(langModule->unicodeEncodingCO);
2620                 break;
2621         case EncodingSets::legacy:
2622                 langModule->encodingVariantLA->setBuddy(langModule->autoEncodingCO);
2623                 break;
2624         case EncodingSets::custom:
2625                 langModule->encodingVariantLA->setBuddy(langModule->customEncodingCO);
2626                 break;
2627         }
2628  
2629         if (tex_fonts)
2630                 langModule->unicodeEncodingCO->setItemText(1, qt_("Direct (No inputenc)"));
2631         else
2632                 langModule->unicodeEncodingCO->setItemText(1, qt_("Direct (XeTeX/LuaTeX)"));
2633 }
2634
2635 void GuiDocument::inputencodingToDialog()
2636 {
2637         QString inputenc = toqstr(bp_.inputenc);
2638         int p;
2639         if (fontModule->osFontsCB->isChecked()) { // non-tex fonts require utf8-plain
2640                 langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2641                 langModule->unicodeEncodingCO->setCurrentIndex(
2642                         langModule->unicodeEncodingCO->findData("utf8-plain"));
2643         } else if (inputenc.startsWith("utf8")) {
2644                 langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2645                 p = langModule->unicodeEncodingCO->findData(inputenc);
2646                 if (p == -1)
2647                         p = 0;
2648                 langModule->unicodeEncodingCO->setCurrentIndex(p);
2649                 langModule->autoEncodingCO->setCurrentIndex(0);
2650                 langModule->customEncodingCO->setCurrentIndex(0);
2651         } else if (inputenc.startsWith("auto")) {
2652                 langModule->encodingCO->setCurrentIndex(EncodingSets::legacy);
2653                 p = langModule->autoEncodingCO->findData(inputenc);
2654                 if (p == -1)
2655                         p = 0;
2656                 langModule->unicodeEncodingCO->setCurrentIndex(0);
2657                 langModule->autoEncodingCO->setCurrentIndex(p);
2658                 langModule->customEncodingCO->setCurrentIndex(0);
2659         } else {
2660                 langModule->encodingCO->setCurrentIndex(EncodingSets::custom);
2661                 p = langModule->customEncodingCO->findData(inputenc);
2662                 if (p == -1) {
2663                         p = 0;
2664                         langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2665                 }
2666                 langModule->unicodeEncodingCO->setCurrentIndex(0);
2667                 langModule->autoEncodingCO->setCurrentIndex(0);
2668                 langModule->customEncodingCO->setCurrentIndex(p);
2669         }
2670         encodingSwitched(langModule->encodingCO->currentIndex());
2671 }
2672
2673
2674 void GuiDocument::mathFontChanged(int)
2675 {
2676         updateFontOptions();
2677 }
2678
2679 void GuiDocument::fontOsfToggled(bool state)
2680 {
2681         if (fontModule->osFontsCB->isChecked())
2682                 return;
2683         QString font = fontModule->fontsRomanCO->getData(
2684                         fontModule->fontsRomanCO->currentIndex());
2685         if (hasMonolithicExpertSet(font))
2686                 fontModule->fontScCB->setChecked(state);
2687 }
2688
2689
2690 void GuiDocument::fontScToggled(bool state)
2691 {
2692         if (fontModule->osFontsCB->isChecked())
2693                 return;
2694         QString font = fontModule->fontsRomanCO->getData(
2695                         fontModule->fontsRomanCO->currentIndex());
2696         if (hasMonolithicExpertSet(font))
2697                 fontModule->fontOsfCB->setChecked(state);
2698 }
2699
2700
2701 void GuiDocument::updateExtraOpts()
2702 {
2703         QString font = fontModule->fontsRomanCO->getData(
2704                         fontModule->fontsRomanCO->currentIndex());
2705         bool const rm_opts = providesExtraOpts(font);
2706         font = fontModule->fontsSansCO->getData(
2707                         fontModule->fontsSansCO->currentIndex());
2708         bool const sf_opts = providesExtraOpts(font);
2709         font = fontModule->fontsTypewriterCO->getData(
2710                         fontModule->fontsTypewriterCO->currentIndex());
2711         bool const tt_opts = providesExtraOpts(font);
2712         fontModule->fontspecRomanLA->setEnabled(rm_opts);
2713         fontModule->fontspecRomanLE->setEnabled(rm_opts);
2714         fontModule->fontspecSansLA->setEnabled(sf_opts);
2715         fontModule->fontspecSansLE->setEnabled(sf_opts);
2716         fontModule->fontspecTypewriterLA->setEnabled(tt_opts);
2717         fontModule->fontspecTypewriterLE->setEnabled(tt_opts);
2718 }
2719
2720
2721 void GuiDocument::updateFontOptions()
2722 {
2723         QString font = fontModule->fontsSansCO->getData(
2724                         fontModule->fontsSansCO->currentIndex());
2725         bool scalable = providesScale(font);
2726         fontModule->scaleSansSB->setEnabled(scalable);
2727         fontModule->scaleSansLA->setEnabled(scalable);
2728         fontModule->fontSansOsfCB->setEnabled(providesOSF(font));
2729         font = fontModule->fontsTypewriterCO->getData(
2730                         fontModule->fontsTypewriterCO->currentIndex());
2731         scalable = providesScale(font);
2732         fontModule->scaleTypewriterSB->setEnabled(scalable);
2733         fontModule->scaleTypewriterLA->setEnabled(scalable);
2734         fontModule->fontTypewriterOsfCB->setEnabled(providesOSF(font));
2735         font = fontModule->fontsRomanCO->getData(
2736                         fontModule->fontsRomanCO->currentIndex());
2737         fontModule->fontScCB->setEnabled(providesSC(font));
2738         fontModule->fontOsfCB->setEnabled(providesOSF(font));
2739         updateExtraOpts();
2740         updateMathFonts(font);
2741 }
2742
2743
2744 void GuiDocument::updateFontsize(string const & items, string const & sel)
2745 {
2746         fontModule->fontsizeCO->clear();
2747         fontModule->fontsizeCO->addItem(qt_("Default"));
2748
2749         for (int n = 0; !token(items,'|',n).empty(); ++n)
2750                 fontModule->fontsizeCO->
2751                         addItem(toqstr(token(items,'|',n)));
2752
2753         for (int n = 0; n < fontModule->fontsizeCO->count(); ++n) {
2754                 if (fromqstr(fontModule->fontsizeCO->itemText(n)) == sel) {
2755                         fontModule->fontsizeCO->setCurrentIndex(n);
2756                         break;
2757                 }
2758         }
2759 }
2760
2761
2762 bool GuiDocument::ot1() const
2763 {
2764         QString const fontenc =
2765                 fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString();
2766         int const i = langModule->languageCO->currentIndex();
2767         if (i == -1)
2768                 return false;
2769         QString const langname = langModule->languageCO->itemData(i).toString();
2770         Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
2771         return (fontenc == "default"
2772                 || (fontenc == "auto" && newlang->fontenc(buffer().params()) == "OT1")
2773                 || (fontenc == "custom" && fontModule->fontencLE->text() == "OT1"));
2774 }
2775
2776
2777 bool GuiDocument::completeFontset() const
2778 {
2779         return (fontModule->fontsSansCO->getData(
2780                         fontModule->fontsSansCO->currentIndex()) == "default"
2781                 && fontModule->fontsSansCO->getData(
2782                         fontModule->fontsTypewriterCO->currentIndex()) == "default");
2783 }
2784
2785
2786 bool GuiDocument::noMathFont() const
2787 {
2788         return (fontModule->fontsMathCO->itemData(
2789                 fontModule->fontsMathCO->currentIndex()).toString() == "default");
2790 }
2791
2792
2793 void GuiDocument::updateTexFonts()
2794 {
2795         LaTeXFonts::TexFontMap texfontmap = theLaTeXFonts().getLaTeXFonts();
2796
2797         LaTeXFonts::TexFontMap::const_iterator it = texfontmap.begin();
2798         LaTeXFonts::TexFontMap::const_iterator end = texfontmap.end();
2799         for (; it != end; ++it) {
2800                 LaTeXFont lf = it->second;
2801                 if (lf.name().empty()) {
2802                         LYXERR0("Error: Unnamed font: " << it->first);
2803                         continue;
2804                 }
2805                 docstring const family = lf.family();
2806                 docstring guiname = translateIfPossible(lf.guiname());
2807                 if (!lf.available(ot1(), noMathFont()))
2808                         guiname += _(" (not installed)");
2809                 if (family == "rm")
2810                         rmfonts_.insert(toqstr(guiname), toqstr(it->first));
2811                 else if (family == "sf")
2812                         sffonts_.insert(toqstr(guiname), toqstr(it->first));
2813                 else if (family == "tt")
2814                         ttfonts_.insert(toqstr(guiname), toqstr(it->first));
2815                 else if (family == "math")
2816                         mathfonts_.insert(toqstr(guiname), toqstr(it->first));
2817         }
2818 }
2819
2820
2821 void GuiDocument::updateFontlist()
2822 {
2823         // reset the filters of the CategorizedCombos
2824         fontModule->fontsRomanCO->resetFilter();
2825         fontModule->fontsSansCO->resetFilter();
2826         fontModule->fontsTypewriterCO->resetFilter();
2827         fontModule->fontsRomanCO->clear();
2828         fontModule->fontsSansCO->clear();
2829         fontModule->fontsTypewriterCO->clear();
2830         fontModule->fontsMathCO->clear();
2831
2832         // With fontspec (XeTeX, LuaTeX), we have access to all system fonts, but not the LaTeX fonts
2833         if (fontModule->osFontsCB->isChecked()) {
2834                 fontModule->fontsRomanCO->addItemSort(QString("default"), qt_("Default"),
2835                                                       QString(), qt_("Default font (as set by class)"),
2836                                                       false, false, false, true, true);
2837                 fontModule->fontsSansCO->addItemSort(QString("default"), qt_("Default"),
2838                                                      QString(), qt_("Default font (as set by class)"),
2839                                                      false, false, false, true, true);
2840                 fontModule->fontsTypewriterCO->addItemSort(QString("default"), qt_("Default"),
2841                                                            QString(), qt_("Default font (as set by class)"),
2842                                                            false, false, false, true, true);
2843                 QString unimath = qt_("Non-TeX Fonts Default");
2844                 if (!LaTeXFeatures::isAvailable("unicode-math"))
2845                         unimath += qt_(" (not available)");
2846                 fontModule->fontsMathCO->addItem(qt_("Class Default (TeX Fonts)"), QString("auto"));
2847                 fontModule->fontsMathCO->addItem(unimath, QString("default"));
2848
2849 #if QT_VERSION >= 0x060000
2850                 const QStringList families(QFontDatabase::families());
2851 #else
2852                 QFontDatabase fontdb;
2853                 const QStringList families(fontdb.families());
2854 #endif
2855                 for (auto const & family : families) {
2856                         fontModule->fontsRomanCO->addItemSort(family, family,
2857                                                               QString(), QString(),
2858                                                               false, false, false, true, true);
2859                         fontModule->fontsSansCO->addItemSort(family, family,
2860                                                              QString(), QString(),
2861                                                              false, false, false, true, true);
2862                         fontModule->fontsTypewriterCO->addItemSort(family, family,
2863                                                                    QString(), QString(),
2864                                                                    false, false, false, true, true);
2865                 }
2866                 return;
2867         }
2868
2869         if (rmfonts_.empty())
2870                 updateTexFonts();
2871
2872         fontModule->fontsRomanCO->addItemSort(QString("default"), qt_("Default"),
2873                                               QString(), qt_("Default font (as set by class)"),
2874                                               false, false, false, true, true);
2875         QMap<QString, QString>::const_iterator rmi = rmfonts_.constBegin();
2876         while (rmi != rmfonts_.constEnd()) {
2877                 fontModule->fontsRomanCO->addItemSort(rmi.value(), rmi.key(),
2878                                                       QString(), QString(),
2879                                                       false, false, false, true, true);
2880                 ++rmi;
2881         }
2882
2883         fontModule->fontsSansCO->addItemSort(QString("default"), qt_("Default"),
2884                                              QString(), qt_("Default font (as set by class)"),
2885                                              false, false, false, true, true);
2886         QMap<QString, QString>::const_iterator sfi = sffonts_.constBegin();
2887         while (sfi != sffonts_.constEnd()) {
2888                 fontModule->fontsSansCO->addItemSort(sfi.value(), sfi.key(),
2889                                                      QString(), QString(),
2890                                                      false, false, false, true, true);
2891                 ++sfi;
2892         }
2893
2894         fontModule->fontsTypewriterCO->addItemSort(QString("default"), qt_("Default"),
2895                                                    QString(), qt_("Default font (as set by class)"),
2896                                                    false, false, false, true, true);
2897         QMap<QString, QString>::const_iterator tti = ttfonts_.constBegin();
2898         while (tti != ttfonts_.constEnd()) {
2899                 fontModule->fontsTypewriterCO->addItemSort(tti.value(), tti.key(),
2900                                                            QString(), QString(),
2901                                                            false, false, false, true, true);
2902                 ++tti;
2903         }
2904
2905         fontModule->fontsMathCO->addItem(qt_("Automatic"), QString("auto"));
2906         fontModule->fontsMathCO->addItem(qt_("Class Default"), QString("default"));
2907         QMap<QString, QString>::const_iterator mmi = mathfonts_.constBegin();
2908         while (mmi != mathfonts_.constEnd()) {
2909                 fontModule->fontsMathCO->addItem(mmi.key(), mmi.value());
2910                 ++mmi;
2911         }
2912 }
2913
2914
2915 void GuiDocument::fontencChanged(int item)
2916 {
2917         fontModule->fontencLE->setEnabled(
2918                 fontModule->fontencCO->itemData(item).toString() == "custom");
2919         // The availability of TeX fonts depends on the font encoding
2920         updateTexFonts();
2921         updateFontOptions();
2922 }
2923
2924
2925 void GuiDocument::updateMathFonts(QString const & rm)
2926 {
2927         if (fontModule->osFontsCB->isChecked())
2928                 return;
2929         QString const math =
2930                 fontModule->fontsMathCO->itemData(fontModule->fontsMathCO->currentIndex()).toString();
2931         int const i = fontModule->fontsMathCO->findData("default");
2932         if (providesNoMath(rm) && i == -1)
2933                 fontModule->fontsMathCO->insertItem(1, qt_("Class Default"), QString("default"));
2934         else if (!providesNoMath(rm) && i != -1) {
2935                 int const c = fontModule->fontsMathCO->currentIndex();
2936                 fontModule->fontsMathCO->removeItem(i);
2937                 if (c == i)
2938                         fontModule->fontsMathCO->setCurrentIndex(0);
2939         }
2940 }
2941
2942
2943 void GuiDocument::romanChanged(int item)
2944 {
2945         QString const font = fontModule->fontsRomanCO->getData(item);
2946         fontModule->fontOsfCB->setEnabled(providesOSF(font));
2947         updateExtraOpts();
2948         if (fontModule->osFontsCB->isChecked())
2949                 return;
2950         fontModule->fontScCB->setEnabled(providesSC(font));
2951         updateMathFonts(font);
2952 }
2953
2954
2955 void GuiDocument::sansChanged(int item)
2956 {
2957         QString const font = fontModule->fontsSansCO->getData(item);
2958         bool const scalable = providesScale(font);
2959         fontModule->scaleSansSB->setEnabled(scalable);
2960         fontModule->scaleSansLA->setEnabled(scalable);
2961         fontModule->fontSansOsfCB->setEnabled(providesOSF(font));
2962         updateExtraOpts();
2963 }
2964
2965
2966 void GuiDocument::ttChanged(int item)
2967 {
2968         QString const font = fontModule->fontsTypewriterCO->getData(item);
2969         bool scalable = providesScale(font);
2970         fontModule->scaleTypewriterSB->setEnabled(scalable);
2971         fontModule->scaleTypewriterLA->setEnabled(scalable);
2972         fontModule->fontTypewriterOsfCB->setEnabled(providesOSF(font));
2973         updateExtraOpts();
2974 }
2975
2976
2977 void GuiDocument::updatePagestyle(string const & items, string const & sel)
2978 {
2979         pagestyles.clear();
2980         pageLayoutModule->pagestyleCO->clear();
2981         pageLayoutModule->pagestyleCO->addItem(qt_("Default"));
2982
2983         for (int n = 0; !token(items, '|', n).empty(); ++n) {
2984                 string style = token(items, '|', n);
2985                 QString style_gui = qt_(style);
2986                 pagestyles.push_back(pair<string, QString>(style, style_gui));
2987                 pageLayoutModule->pagestyleCO->addItem(style_gui);
2988         }
2989
2990         if (sel == "default") {
2991                 pageLayoutModule->pagestyleCO->setCurrentIndex(0);
2992                 return;
2993         }
2994
2995         int nn = 0;
2996
2997         for (auto const & pagestyle : pagestyles)
2998                 if (pagestyle.first == sel)
2999                         nn = pageLayoutModule->pagestyleCO->findText(pagestyle.second);
3000
3001         if (nn > 0)
3002                 pageLayoutModule->pagestyleCO->setCurrentIndex(nn);
3003 }
3004
3005
3006 void GuiDocument::browseLayout()
3007 {
3008         QString const label1 = qt_("Lay&outs");
3009         QString const dir1 = toqstr(lyxrc.document_path);
3010         QStringList const filter(qt_("LyX Layout (*.layout)"));
3011         QString file = browseRelToParent(QString(), bufferFilePath(),
3012                 qt_("Local layout file"), filter, false,
3013                 label1, dir1);
3014
3015         if (!file.endsWith(".layout"))
3016                 return;
3017
3018         FileName layoutFile = support::makeAbsPath(fromqstr(file),
3019                 fromqstr(bufferFilePath()));
3020
3021         int const ret = Alert::prompt(_("Local layout file"),
3022                 _("The layout file you have selected is a local layout\n"
3023                   "file, not one in the system or user directory.\n"
3024                   "Your document will not work with this layout if you\n"
3025                   "move the layout file to a different directory."),
3026                   1, 1, _("&Set Layout"), _("&Cancel"));
3027         if (ret == 1)
3028                 return;
3029
3030         // load the layout file
3031         LayoutFileList & bcl = LayoutFileList::get();
3032         string classname = layoutFile.onlyFileName();
3033         // this will update an existing layout if that layout has been loaded before.
3034         LayoutFileIndex name = support::onlyFileName(bcl.addLocalLayout(
3035                 classname.substr(0, classname.size() - 7),
3036                 layoutFile.onlyPath().absFileName()));
3037
3038         if (name.empty()) {
3039                 Alert::error(_("Error"),
3040                         _("Unable to read local layout file."));
3041                 return;
3042         }
3043
3044         const_cast<Buffer &>(buffer()).setLayoutPos(layoutFile.onlyPath().absFileName());
3045
3046         // do not trigger classChanged if there is no change.
3047         if (latexModule->classCO->currentText() == toqstr(name))
3048                 return;
3049
3050         // add to combo box
3051         bool const avail = latexModule->classCO->set(toqstr(name));
3052         if (!avail) {
3053                 LayoutFile const & tc = bcl[name];
3054                 docstring const guiname = translateIfPossible(from_utf8(tc.description()));
3055                 // tooltip sensu "KOMA-Script Article [Class 'scrartcl']"
3056                 QString tooltip = toqstr(bformat(_("%1$s [Class '%2$s']"), guiname, from_utf8(tc.latexname())));
3057                 tooltip += '\n' + qt_("This is a local layout file.");
3058                 latexModule->classCO->addItemSort(toqstr(tc.name()), toqstr(guiname),
3059                                                   toqstr(translateIfPossible(from_utf8(tc.category()))),
3060                                                   tooltip,
3061                                                   true, true, true, true);
3062                 latexModule->classCO->set(toqstr(name));
3063         }
3064
3065         classChanged();
3066 }
3067
3068
3069 void GuiDocument::browseMaster()
3070 {
3071         QString const title = qt_("Select master document");
3072         QString const dir1 = toqstr(lyxrc.document_path);
3073         QString const old = latexModule->childDocLE->text();
3074         QString const docpath = toqstr(support::onlyPath(buffer().absFileName()));
3075         QStringList const filter(qt_("LyX Files (*.lyx)"));
3076         QString file = browseRelToSub(old, docpath, title, filter, false,
3077                 qt_("D&ocuments"), toqstr(lyxrc.document_path));
3078
3079         if (!file.isEmpty())
3080                 latexModule->childDocLE->setText(file);
3081 }
3082
3083
3084 void GuiDocument::classChanged_adaptor()
3085 {
3086         const_cast<Buffer &>(buffer()).setLayoutPos(string());
3087         classChanged();
3088 }
3089
3090
3091 void GuiDocument::classChanged()
3092 {
3093         int idx = latexModule->classCO->currentIndex();
3094         if (idx < 0)
3095                 return;
3096         string const classname = fromqstr(latexModule->classCO->getData(idx));
3097
3098         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
3099                 int const ret = Alert::prompt(_("Unapplied changes"),
3100                                 _("Some changes in the dialog were not yet applied.\n"
3101                                 "If you do not apply now, they will be lost after this action."),
3102                                 1, 1, _("&Apply"), _("&Dismiss"));
3103                 if (ret == 0)
3104                         applyView();
3105         }
3106
3107         // We load the TextClass as soon as it is selected. This is
3108         // necessary so that other options in the dialog can be updated
3109         // according to the new class. Note, however, that, if you use
3110         // the scroll wheel when sitting on the combo box, we'll load a
3111         // lot of TextClass objects very quickly....
3112         if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
3113                 Alert::error(_("Error"), _("Unable to set document class."));
3114                 return;
3115         }
3116         if (lyxrc.auto_reset_options)
3117                 bp_.useClassDefaults();
3118
3119         // With the introduction of modules came a distinction between the base
3120         // class and the document class. The former corresponds to the main layout
3121         // file; the latter is that plus the modules (or the document-specific layout,
3122         // or  whatever else there could be). Our parameters come from the document
3123         // class. So when we set the base class, we also need to recreate the document
3124         // class. Otherwise, we still have the old one.
3125         bp_.makeDocumentClass();
3126         paramsToDialog();
3127 }
3128
3129
3130 void GuiDocument::languagePackageChanged(int i)
3131 {
3132          langModule->languagePackageLE->setEnabled(
3133                 langModule->languagePackageCO->itemData(i).toString() == "custom");
3134 }
3135
3136
3137 void GuiDocument::biblioChanged()
3138 {
3139         biblioChanged_ = true;
3140         change_adaptor();
3141 }
3142
3143
3144 void GuiDocument::checkPossibleCiteEngines()
3145 {
3146         // Check if the class provides a specific engine,
3147         // and if so, enforce this.
3148         string force_engine;
3149         if (documentClass().provides("natbib")
3150             || documentClass().provides("natbib-internal"))
3151                 force_engine = "natbib";
3152         else if (documentClass().provides("jurabib"))
3153                 force_engine = "jurabib";
3154         else if (documentClass().provides("biblatex"))
3155                 force_engine = "biblatex";
3156         else if (documentClass().provides("biblatex-natbib"))
3157                 force_engine = "biblatex-natbib";
3158
3159         if (!force_engine.empty())
3160                 biblioModule->citeEngineCO->setCurrentIndex(
3161                         biblioModule->citeEngineCO->findData(toqstr(force_engine)));
3162         biblioModule->citeEngineCO->setEnabled(force_engine.empty());
3163 }
3164
3165
3166 void GuiDocument::rescanBibFiles()
3167 {
3168         if (isBiblatex())
3169                 rescanTexStyles("bbx cbx");
3170         else
3171                 rescanTexStyles("bst");
3172 }
3173
3174
3175 void GuiDocument::resetDefaultBibfile(string const & which)
3176 {
3177         QString const engine =
3178                 biblioModule->citeEngineCO->itemData(
3179                                 biblioModule->citeEngineCO->currentIndex()).toString();
3180
3181         CiteEngineType const cet =
3182                 CiteEngineType(biblioModule->citeStyleCO->itemData(
3183                                                           biblioModule->citeStyleCO->currentIndex()).toInt());
3184
3185         updateDefaultBiblio(theCiteEnginesList[fromqstr(engine)]->getDefaultBiblio(cet), which);
3186 }
3187
3188
3189 void GuiDocument::resetDefaultBbxBibfile()
3190 {
3191         resetDefaultBibfile("bbx");
3192 }
3193
3194
3195 void GuiDocument::resetDefaultCbxBibfile()
3196 {
3197         resetDefaultBibfile("cbx");
3198 }
3199
3200
3201 void GuiDocument::citeEngineChanged(int n)
3202 {
3203         QString const engine =
3204                 biblioModule->citeEngineCO->itemData(n).toString();
3205
3206         vector<string> const engs =
3207                 theCiteEnginesList[fromqstr(engine)]->getEngineType();
3208
3209         updateCiteStyles(engs);
3210         updateEngineDependends();
3211         resetDefaultBibfile();
3212         biblioChanged();
3213 }
3214
3215
3216 void GuiDocument::updateEngineDependends()
3217 {
3218         bool const biblatex = isBiblatex();
3219
3220         // These are only useful with BibTeX
3221         biblioModule->defaultBiblioCO->setEnabled(!biblatex);
3222         biblioModule->bibtexStyleLA->setEnabled(!biblatex);
3223         biblioModule->resetDefaultBiblioPB->setEnabled(!biblatex);
3224         biblioModule->bibtopicCB->setEnabled(!biblatex);
3225
3226         // These are only useful with Biblatex
3227         biblioModule->biblatexBbxCO->setEnabled(biblatex);
3228         biblioModule->biblatexBbxLA->setEnabled(biblatex);
3229         biblioModule->biblatexCbxCO->setEnabled(biblatex);
3230         biblioModule->biblatexCbxLA->setEnabled(biblatex);
3231         biblioModule->resetBbxPB->setEnabled(biblatex);
3232         biblioModule->resetCbxPB->setEnabled(biblatex);
3233         biblioModule->matchBbxPB->setEnabled(biblatex);
3234
3235         // These are useful with biblatex, jurabib and natbib
3236         QString const engine =
3237                 biblioModule->citeEngineCO->itemData(
3238                                 biblioModule->citeEngineCO->currentIndex()).toString();
3239         LyXCiteEngine const * ce = theCiteEnginesList[fromqstr(engine)];
3240
3241         bool const citepack = ce->required("biblatex.sty") || ce->required("jurabib.sty")
3242                         || ce->required("natbib.sty");
3243         biblioModule->citePackageOptionsLE->setEnabled(citepack);
3244         biblioModule->citePackageOptionsL->setEnabled(citepack);
3245 }
3246
3247
3248 void GuiDocument::citeStyleChanged()
3249 {
3250         QString const engine =
3251                 biblioModule->citeEngineCO->itemData(
3252                                 biblioModule->citeEngineCO->currentIndex()).toString();
3253         QString const currentDef = isBiblatex() ?
3254                 biblioModule->biblatexBbxCO->currentText()
3255                 : biblioModule->defaultBiblioCO->currentText();
3256         if (theCiteEnginesList[fromqstr(engine)]->isDefaultBiblio(fromqstr(currentDef)))
3257                 resetDefaultBibfile();
3258
3259         biblioChanged();
3260 }
3261
3262
3263 void GuiDocument::bibtexChanged(int n)
3264 {
3265         biblioModule->bibtexOptionsLE->setEnabled(
3266                 biblioModule->bibtexCO->itemData(n).toString() != "default");
3267         biblioChanged();
3268 }
3269
3270
3271 void GuiDocument::updateCiteStyles(vector<string> const & engs, CiteEngineType const & sel)
3272 {
3273         biblioModule->citeStyleCO->clear();
3274
3275         vector<string>::const_iterator it  = engs.begin();
3276         vector<string>::const_iterator end = engs.end();
3277         for (; it != end; ++it) {
3278                 if (*it == "default")
3279                         biblioModule->citeStyleCO->addItem(qt_("Basic numerical"),
3280                                                            ENGINE_TYPE_DEFAULT);
3281                 else if (*it == "authoryear")
3282                         biblioModule->citeStyleCO->addItem(qt_("Author-year"),
3283                                                            ENGINE_TYPE_AUTHORYEAR);
3284                 else if (*it == "numerical")
3285                         biblioModule->citeStyleCO->addItem(qt_("Author-number"),
3286                                                            ENGINE_TYPE_NUMERICAL);
3287         }
3288         int i = biblioModule->citeStyleCO->findData(sel);
3289         if (biblioModule->citeStyleCO->findData(sel) == -1)
3290                 i = 0;
3291         biblioModule->citeStyleCO->setCurrentIndex(i);
3292
3293         biblioModule->citationStyleL->setEnabled(engs.size() > 1);
3294         biblioModule->citeStyleCO->setEnabled(engs.size() > 1);
3295 }
3296
3297
3298 void GuiDocument::updateEngineType(string const & items, CiteEngineType const & sel)
3299 {
3300         engine_types_.clear();
3301
3302         for (int n = 0; !token(items, '|', n).empty(); ++n) {
3303                 string style = token(items, '|', n);
3304                 engine_types_.push_back(style);
3305         }
3306
3307         updateCiteStyles(engine_types_, sel);
3308 }
3309
3310
3311 namespace {
3312         // FIXME unicode
3313         // both of these should take a vector<docstring>
3314
3315         // This is an insanely complicated attempt to make this sort of thing
3316         // work with RTL languages.
3317         docstring formatStrVec(vector<string> const & v, docstring const & s)
3318         {
3319                 //this mess formats the list as "v[0], v[1], ..., [s] v[n]"
3320                 if (v.empty())
3321                         return docstring();
3322                 if (v.size() == 1)
3323                         return translateIfPossible(from_utf8(v[0]));
3324                 if (v.size() == 2) {
3325                         docstring retval = _("%1$s and %2$s");
3326                         retval = subst(retval, _("and"), s);
3327                         return bformat(retval, translateIfPossible(from_utf8(v[0])),
3328                                        translateIfPossible(from_utf8(v[1])));
3329                 }
3330                 // The idea here is to format all but the last two items...
3331                 int const vSize = v.size();
3332                 docstring t2 = _("%1$s, %2$s");
3333                 docstring retval = translateIfPossible(from_utf8(v[0]));
3334                 for (int i = 1; i < vSize - 2; ++i)
3335                         retval = bformat(t2, retval, translateIfPossible(from_utf8(v[i])));
3336                 //...and then to  plug them, and the last two, into this schema
3337                 docstring t = _("%1$s, %2$s, and %3$s");
3338                 t = subst(t, _("and"), s);
3339                 return bformat(t, retval, translateIfPossible(from_utf8(v[vSize - 2])),
3340                                translateIfPossible(from_utf8(v[vSize - 1])));
3341         }
3342
3343         vector<string> idsToNames(vector<string> const & idList)
3344         {
3345                 vector<string> retval;
3346                 vector<string>::const_iterator it  = idList.begin();
3347                 vector<string>::const_iterator end = idList.end();
3348                 for (; it != end; ++it) {
3349                         LyXModule const * const mod = theModuleList[*it];
3350                         if (!mod)
3351                                 retval.push_back(to_utf8(bformat(_("%1$s (unavailable)"),
3352                                                 translateIfPossible(from_utf8(*it)))));
3353                         else
3354                                 retval.push_back(mod->getName());
3355                 }
3356                 return retval;
3357         }
3358 } // end anonymous namespace
3359
3360
3361 void GuiDocument::modulesToParams(BufferParams & bp)
3362 {
3363         // update list of loaded modules
3364         bp.clearLayoutModules();
3365         int const srows = modules_sel_model_.rowCount();
3366         for (int i = 0; i < srows; ++i)
3367                 bp.addLayoutModule(modules_sel_model_.getIDString(i));
3368         updateSelectedModules();
3369
3370         // update the list of removed modules
3371         bp.clearRemovedModules();
3372         LayoutModuleList const & reqmods = bp.baseClass()->defaultModules();
3373         list<string>::const_iterator rit = reqmods.begin();
3374         list<string>::const_iterator ren = reqmods.end();
3375
3376         // check each of the default modules
3377         for (; rit != ren; ++rit) {
3378                 list<string>::const_iterator mit = bp.getModules().begin();
3379                 list<string>::const_iterator men = bp.getModules().end();
3380                 bool found = false;
3381                 for (; mit != men; ++mit) {
3382                         if (*rit == *mit) {
3383                                 found = true;
3384                                 break;
3385                         }
3386                 }
3387                 if (!found) {
3388                         // the module isn't present so must have been removed by the user
3389                         bp.addRemovedModule(*rit);
3390                 }
3391         }
3392 }
3393
3394 void GuiDocument::modulesChanged()
3395 {
3396         modulesToParams(bp_);
3397
3398         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()
3399             && (nonModuleChanged_ || shellescapeChanged_)) {
3400                 int const ret = Alert::prompt(_("Unapplied changes"),
3401                                 _("Some changes in the dialog were not yet applied.\n"
3402                                 "If you do not apply now, they will be lost after this action."),
3403                                 1, 1, _("&Apply"), _("&Dismiss"));
3404                 if (ret == 0)
3405                         applyView();
3406         }
3407
3408         modulesChanged_ = true;
3409         bp_.makeDocumentClass();
3410         paramsToDialog();
3411         changed();
3412 }
3413
3414
3415 void GuiDocument::updateModuleInfo()
3416 {
3417         selectionManager->update();
3418
3419         //Module description
3420         bool const focus_on_selected = selectionManager->selectedFocused();
3421         QAbstractItemView * lv;
3422         bool category = false;
3423         if (focus_on_selected) {
3424                 lv = modulesModule->selectedLV;
3425                 category = true;
3426         } else
3427                 lv = modulesModule->availableLV;
3428         if (lv->selectionModel()->selectedIndexes().isEmpty()) {
3429                 modulesModule->infoML->document()->clear();
3430                 return;
3431         }
3432         QModelIndex const & idx = lv->selectionModel()->currentIndex();
3433
3434         if (!idx.isValid())
3435                 return;
3436
3437         if (!focus_on_selected
3438             && modules_av_model_.itemFromIndex(idx)->hasChildren()) {
3439                 // This is a category header
3440                 modulesModule->infoML->document()->clear();
3441                 return;
3442         }
3443
3444         string const modName = focus_on_selected ?
3445                                 modules_sel_model_.getIDString(idx.row())
3446                               : fromqstr(modules_av_model_.data(idx, Qt::UserRole).toString());
3447         docstring desc = getModuleDescription(modName);
3448
3449         LayoutModuleList const & provmods = bp_.baseClass()->providedModules();
3450         if (std::find(provmods.begin(), provmods.end(), modName) != provmods.end()) {
3451                 if (!desc.empty())
3452                         desc += "\n";
3453                 desc += _("Module provided by document class.");
3454         }
3455
3456         if (category) {
3457                 docstring cat = getModuleCategory(modName);
3458                 if (!cat.empty()) {
3459                         if (!desc.empty())
3460                                 desc += "\n";
3461                         desc += bformat(_("<p><b>Category:</b> %1$s.</p>"),
3462                                         translateIfPossible(cat));
3463                 }
3464         }
3465
3466         vector<string> pkglist = getPackageList(modName);
3467         docstring pkgdesc = formatStrVec(pkglist, _("and"));
3468         if (!pkgdesc.empty()) {
3469                 if (!desc.empty())
3470                         desc += "\n";
3471                 desc += bformat(_("<p><b>Package(s) required:</b> %1$s.</p>"), pkgdesc);
3472         }
3473
3474         pkglist = getRequiredList(modName);
3475         if (!pkglist.empty()) {
3476                 vector<string> const reqdescs = idsToNames(pkglist);
3477                 pkgdesc = formatStrVec(reqdescs, _("or"));
3478                 if (!desc.empty())
3479                         desc += "\n";
3480                 desc += bformat(_("<p><b>Modules required:</b> %1$s.</p>"), pkgdesc);
3481         }
3482
3483         pkglist = getExcludedList(modName);
3484         if (!pkglist.empty()) {
3485                 vector<string> const reqdescs = idsToNames(pkglist);
3486                 pkgdesc = formatStrVec(reqdescs, _( "and"));
3487                 if (!desc.empty())
3488                         desc += "\n";
3489                 desc += bformat(_("<p><b>Modules excluded:</b> %1$s.</p>"), pkgdesc);
3490         }
3491
3492         if (!desc.empty())
3493                 desc += "\n";
3494         desc += bformat(_("<p><b>Filename:</b> <tt>%1$s.module</tt>.</p>"), from_utf8(modName));
3495
3496         if (!isModuleAvailable(modName)) {
3497                 if (!desc.empty())
3498                         desc += "\n";
3499                 desc += _("<p><font color=red><b>WARNING: Some required packages are unavailable!</b></font></p>");
3500         }
3501
3502         modulesModule->infoML->document()->setHtml(toqstr(desc));
3503 }
3504
3505
3506 void GuiDocument::updateNumbering()
3507 {
3508         DocumentClass const & tclass = documentClass();
3509
3510         numberingModule->tocTW->setUpdatesEnabled(false);
3511         numberingModule->tocTW->clear();
3512
3513         int const depth = numberingModule->depthSL->value();
3514         int const toc = numberingModule->tocSL->value();
3515         QString const no = qt_("No");
3516         QString const yes = qt_("Yes");
3517         QTreeWidgetItem * item = nullptr;
3518
3519         DocumentClass::const_iterator lit = tclass.begin();
3520         DocumentClass::const_iterator len = tclass.end();
3521         for (; lit != len; ++lit) {
3522                 int const toclevel = lit->toclevel;
3523                 if (toclevel != Layout::NOT_IN_TOC && !lit->counter.empty()) {
3524                         item = new QTreeWidgetItem(numberingModule->tocTW);
3525                         item->setText(0, toqstr(translateIfPossible(lit->name())));
3526                         item->setText(1, (toclevel <= depth) ? yes : no);
3527                         item->setText(2, (toclevel <= toc) ? yes : no);
3528                 }
3529         }
3530
3531         numberingModule->tocTW->setUpdatesEnabled(true);
3532         numberingModule->tocTW->update();
3533 }
3534
3535
3536 void GuiDocument::getTableStyles()
3537 {
3538         // We look for lyx files in the subdirectory dir of
3539         //   1) user_lyxdir
3540         //   2) build_lyxdir (if not empty)
3541         //   3) system_lyxdir
3542         // in this order. Files with a given sub-hierarchy will
3543         // only be listed once.
3544         // We also consider i18n subdirectories and store them separately.
3545         QStringList dirs;
3546
3547         // The three locations to look at.
3548         string const user = addPath(package().user_support().absFileName(), "tabletemplates");
3549         string const build = addPath(package().build_support().absFileName(), "tabletemplates");
3550         string const system = addPath(package().system_support().absFileName(), "tabletemplates");
3551
3552         dirs << toqstr(user)
3553              << toqstr(build)
3554              << toqstr(system);
3555
3556         for (int i = 0; i < dirs.size(); ++i) {
3557                 QString const & dir = dirs.at(i);
3558                 QDirIterator it(dir, QDir::Files, QDirIterator::Subdirectories);
3559                 while (it.hasNext()) {
3560                         QString fn = QFileInfo(it.next()).fileName();
3561                         if (!fn.endsWith(".lyx") || fn.contains("_1x"))
3562                                 continue;
3563                         QString data = fn.left(fn.lastIndexOf(".lyx"));
3564                         QString guiname = data;
3565                         guiname = toqstr(translateIfPossible(qstring_to_ucs4(guiname.replace('_', ' '))));
3566                         QString relpath = toqstr(makeRelPath(qstring_to_ucs4(fn),
3567                                                              qstring_to_ucs4(dir)));
3568                         if (textLayoutModule->tableStyleCO->findData(data) == -1)
3569                                 textLayoutModule->tableStyleCO->addItem(guiname, data);
3570                 }
3571         }
3572 }
3573
3574
3575 void GuiDocument::updateDefaultFormat()
3576 {
3577         if (!bufferview())
3578                 return;
3579         // make a copy in order to consider unapplied changes
3580         BufferParams param_copy = buffer().params();
3581         param_copy.useNonTeXFonts = fontModule->osFontsCB->isChecked();
3582         int const idx = latexModule->classCO->currentIndex();
3583         if (idx >= 0) {
3584                 string const classname = fromqstr(latexModule->classCO->getData(idx));
3585                 param_copy.setBaseClass(classname, buffer().layoutPos());
3586                 param_copy.makeDocumentClass(true);
3587         }
3588         outputModule->defaultFormatCO->blockSignals(true);
3589         outputModule->defaultFormatCO->clear();
3590         outputModule->defaultFormatCO->addItem(qt_("Default"),
3591                                 QVariant(QString("default")));
3592         FormatList const & formats =
3593                                 param_copy.exportableFormats(true);
3594         for (Format const * f : formats)
3595                 outputModule->defaultFormatCO->addItem
3596                         (toqstr(translateIfPossible(f->prettyname())),
3597                          QVariant(toqstr(f->name())));
3598         outputModule->defaultFormatCO->blockSignals(false);
3599 }
3600
3601
3602 bool GuiDocument::isChildIncluded(string const & child)
3603 {
3604         if (includeonlys_.empty())
3605                 return false;
3606         return (std::find(includeonlys_.begin(),
3607                           includeonlys_.end(), child) != includeonlys_.end());
3608 }
3609
3610
3611 void GuiDocument::applyView()
3612 {
3613         // auto-validate local layout
3614         if (!localLayout->isValid()) {
3615                 localLayout->validate();
3616                 if (!localLayout->isValid()) {
3617                         setApplyStopped(true);
3618                         docPS->setCurrentPanel(N_("Local Layout"));
3619                         return;
3620                 }
3621         }
3622
3623         // preamble
3624         preambleModule->apply(bp_);
3625         localLayout->apply(bp_);
3626
3627         // date
3628         bp_.suppress_date = latexModule->suppressDateCB->isChecked();
3629         bp_.use_refstyle  = latexModule->refstyleCB->isChecked();
3630         bp_.use_formatted_ref  = latexModule->refFormattedCB->isChecked();
3631
3632         // biblio
3633         string const engine =
3634                 fromqstr(biblioModule->citeEngineCO->itemData(
3635                                 biblioModule->citeEngineCO->currentIndex()).toString());
3636         bp_.setCiteEngine(engine);
3637
3638         CiteEngineType const style = CiteEngineType(biblioModule->citeStyleCO->itemData(
3639                 biblioModule->citeStyleCO->currentIndex()).toInt());
3640         if (theCiteEnginesList[engine]->hasEngineType(style))
3641                 bp_.setCiteEngineType(style);
3642         else
3643                 bp_.setCiteEngineType(ENGINE_TYPE_DEFAULT);
3644
3645         bp_.splitbib(biblioModule->bibtopicCB->isChecked());
3646
3647         bp_.multibib = fromqstr(biblioModule->bibunitsCO->itemData(
3648                                 biblioModule->bibunitsCO->currentIndex()).toString());
3649
3650         bp_.setDefaultBiblioStyle(fromqstr(biblioModule->defaultBiblioCO->currentText()));
3651
3652         bp_.biblatex_bibstyle = fromqstr(biblioModule->biblatexBbxCO->currentText());
3653         bp_.biblatex_citestyle = fromqstr(biblioModule->biblatexCbxCO->currentText());
3654         bp_.biblio_opts = fromqstr(biblioModule->citePackageOptionsLE->text());
3655
3656         string const bibtex_command =
3657                 fromqstr(biblioModule->bibtexCO->itemData(
3658                         biblioModule->bibtexCO->currentIndex()).toString());
3659         string const bibtex_options =
3660                 fromqstr(biblioModule->bibtexOptionsLE->text());
3661         if (bibtex_command == "default" || bibtex_options.empty())
3662                 bp_.bibtex_command = bibtex_command;
3663         else
3664                 bp_.bibtex_command = bibtex_command + " " + bibtex_options;
3665
3666         if (biblioChanged_) {
3667                 buffer().invalidateBibinfoCache();
3668                 buffer().removeBiblioTempFiles();
3669         }
3670
3671         // Indices
3672         indicesModule->apply(bp_);
3673
3674         // language & quotes
3675         switch (langModule->encodingCO->currentIndex()) {
3676                 case EncodingSets::unicode: {
3677                         if (!fontModule->osFontsCB->isChecked())
3678                                 bp_.inputenc = fromqstr(langModule->unicodeEncodingCO->itemData(
3679                                         langModule->unicodeEncodingCO->currentIndex()).toString());
3680                         break;
3681                 }
3682                 case EncodingSets::legacy: {
3683                         bp_.inputenc = "auto-legacy";
3684                         bp_.inputenc = fromqstr(langModule->autoEncodingCO->itemData(
3685                                 langModule->autoEncodingCO->currentIndex()).toString());
3686                         break;
3687                 }
3688                 case EncodingSets::custom: {
3689                         bp_.inputenc = fromqstr(langModule->customEncodingCO->itemData(
3690                                 langModule->customEncodingCO->currentIndex()).toString());
3691                         break;
3692                 }
3693                 default:
3694                         // this should never happen
3695                         bp_.inputenc = "utf8";
3696         }
3697         bp_.quotes_style = QuoteStyle(langModule->quoteStyleCO->itemData(
3698                 langModule->quoteStyleCO->currentIndex()).toInt());
3699         bp_.dynamic_quotes = langModule->dynamicQuotesCB->isChecked();
3700
3701         QString const langname = langModule->languageCO->itemData(
3702                 langModule->languageCO->currentIndex()).toString();
3703         Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
3704         Cursor & cur = const_cast<BufferView *>(bufferview())->cursor();
3705         // If current cursor language was the document language, then update it too.
3706         if (cur.current_font.language() == bp_.language) {
3707                 cur.current_font.setLanguage(newlang);
3708                 cur.real_current_font.setLanguage(newlang);
3709         }
3710         bp_.language = newlang;
3711
3712         QString const pack = langModule->languagePackageCO->itemData(
3713                 langModule->languagePackageCO->currentIndex()).toString();
3714         if (pack == "custom")
3715                 bp_.lang_package =
3716                         fromqstr(langModule->languagePackageLE->text());
3717         else
3718                 bp_.lang_package = fromqstr(pack);
3719
3720         //color
3721         bp_.backgroundcolor = set_backgroundcolor;
3722         bp_.isbackgroundcolor = is_backgroundcolor;
3723         bp_.fontcolor = set_fontcolor;
3724         bp_.isfontcolor = is_fontcolor;
3725         bp_.notefontcolor = set_notefontcolor;
3726         bp_.isnotefontcolor = is_notefontcolor;
3727         if (is_notefontcolor) {
3728                 // Set information used in statusbar (#12130)
3729                 lcolor.setColor("notefontcolor", lyx::X11hexname(set_notefontcolor));
3730                 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
3731         }
3732         bp_.boxbgcolor = set_boxbgcolor;
3733         bp_.isboxbgcolor = is_boxbgcolor;
3734
3735         // numbering
3736         if (bp_.documentClass().hasTocLevels()) {
3737                 bp_.tocdepth = numberingModule->tocSL->value();
3738                 bp_.secnumdepth = numberingModule->depthSL->value();
3739         }
3740         bp_.use_lineno = numberingModule->linenoCB->isChecked();
3741         bp_.lineno_opts = fromqstr(numberingModule->linenoLE->text());
3742
3743         // bullets
3744         bp_.user_defined_bullet(0) = bulletsModule->bullet(0);
3745         bp_.user_defined_bullet(1) = bulletsModule->bullet(1);
3746         bp_.user_defined_bullet(2) = bulletsModule->bullet(2);
3747         bp_.user_defined_bullet(3) = bulletsModule->bullet(3);
3748
3749         // packages
3750         bp_.graphics_driver =
3751                 tex_graphics[latexModule->psdriverCO->currentIndex()];
3752
3753         // text layout
3754         int idx = latexModule->classCO->currentIndex();
3755         if (idx >= 0) {
3756                 string const classname = fromqstr(latexModule->classCO->getData(idx));
3757                 bp_.setBaseClass(classname, buffer().layoutPos());
3758         }
3759
3760         // Modules
3761         modulesToParams(bp_);
3762
3763         // Math
3764         map<string, string> const & packages = BufferParams::auto_packages();
3765         for (map<string, string>::const_iterator it = packages.begin();
3766              it != packages.end(); ++it) {
3767                 QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
3768                 if (!item)
3769                         continue;
3770                 int row = mathsModule->packagesTW->row(item);
3771
3772                 QRadioButton * rb =
3773                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
3774                 if (rb->isChecked()) {
3775                         bp_.use_package(it->first, BufferParams::package_auto);
3776                         continue;
3777                 }
3778                 rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
3779                 if (rb->isChecked()) {
3780                         bp_.use_package(it->first, BufferParams::package_on);
3781                         continue;
3782                 }
3783                 rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
3784                 if (rb->isChecked())
3785                         bp_.use_package(it->first, BufferParams::package_off);
3786         }
3787         // if math is indented
3788         bp_.is_math_indent = mathsModule->MathIndentCB->isChecked();
3789         if (bp_.is_math_indent) {
3790                 // if formulas are indented
3791                 if (mathsModule->MathIndentCO->itemData(mathsModule->MathIndentCO->currentIndex()) == "custom") {
3792                         Length mathindent(widgetsToLength(mathsModule->MathIndentLE,
3793                                                           mathsModule->MathIndentLengthCO));
3794                         bp_.setMathIndent(mathindent);
3795                 } else
3796                         // default
3797                         bp_.setMathIndent(Length());
3798         }
3799         switch (mathsModule->MathNumberingPosCO->currentIndex()) {
3800                 case 0:
3801                         bp_.math_numbering_side = BufferParams::LEFT;
3802                         break;
3803                 case 1:
3804                         bp_.math_numbering_side = BufferParams::DEFAULT;
3805                         break;
3806                 case 2:
3807                         bp_.math_numbering_side = BufferParams::RIGHT;
3808                         break;
3809                 default:
3810                         // this should never happen
3811                         bp_.math_numbering_side = BufferParams::DEFAULT;
3812                         break;
3813         }
3814
3815         // Page Layout
3816         if (pageLayoutModule->pagestyleCO->currentIndex() == 0)
3817                 bp_.pagestyle = "default";
3818         else {
3819                 QString style_gui = pageLayoutModule->pagestyleCO->currentText();
3820                 for (size_t i = 0; i != pagestyles.size(); ++i)
3821                         if (pagestyles[i].second == style_gui)
3822                                 bp_.pagestyle = pagestyles[i].first;
3823         }
3824
3825         // Text Layout
3826         switch (textLayoutModule->lspacingCO->currentIndex()) {
3827         case 0:
3828                 bp_.spacing().set(Spacing::Single);
3829                 break;
3830         case 1:
3831                 bp_.spacing().set(Spacing::Onehalf);
3832                 break;
3833         case 2:
3834                 bp_.spacing().set(Spacing::Double);
3835                 break;
3836         case 3: {
3837                 string s = widgetToDoubleStr(textLayoutModule->lspacingLE);
3838                 if (s.empty())
3839                         bp_.spacing().set(Spacing::Single);
3840                 else
3841                         bp_.spacing().set(Spacing::Other, s);
3842                 break;
3843                 }
3844         }
3845
3846         if (textLayoutModule->twoColumnCB->isChecked())
3847                 bp_.columns = 2;
3848         else
3849                 bp_.columns = 1;
3850
3851         bp_.justification = textLayoutModule->justCB->isChecked();
3852
3853         if (textLayoutModule->indentRB->isChecked()) {
3854                 // if paragraphs are separated by an indentation
3855                 bp_.paragraph_separation = BufferParams::ParagraphIndentSeparation;
3856                 if (textLayoutModule->indentCO->itemData(textLayoutModule->indentCO->currentIndex()) == "custom") {
3857                         Length parindent(widgetsToLength(textLayoutModule->indentLE,
3858                                                          textLayoutModule->indentLengthCO));
3859                         bp_.setParIndent(parindent);
3860                 } else
3861                         // default
3862                         bp_.setParIndent(Length());
3863         } else {
3864                 // if paragraphs are separated by a skip
3865                 bp_.paragraph_separation = BufferParams::ParagraphSkipSeparation;
3866                 VSpace::VSpaceKind spacekind =
3867                         VSpace::VSpaceKind(textLayoutModule->skipCO->itemData(textLayoutModule->skipCO->currentIndex()).toInt());
3868                 switch (spacekind) {
3869                 case VSpace::SMALLSKIP:
3870                 case VSpace::MEDSKIP:
3871                 case VSpace::BIGSKIP:
3872                 case VSpace::HALFLINE:
3873                 case VSpace::FULLLINE:
3874                         bp_.setDefSkip(VSpace(spacekind));
3875                         break;
3876                 case VSpace::LENGTH: {
3877                         VSpace vs = VSpace(
3878                                 widgetsToLength(textLayoutModule->skipLE,
3879                                 textLayoutModule->skipLengthCO)
3880                                 );
3881                         bp_.setDefSkip(vs);
3882                         break;
3883                 }
3884                 default:
3885                         // this should never happen
3886                         bp_.setDefSkip(VSpace(VSpace::MEDSKIP));
3887                         break;
3888                 }
3889         }
3890         bp_.tablestyle = fromqstr(textLayoutModule->tableStyleCO->itemData(
3891                                       textLayoutModule->tableStyleCO->currentIndex()).toString());
3892
3893         bp_.options =
3894                 fromqstr(latexModule->optionsLE->text());
3895
3896         bp_.use_default_options =
3897                 latexModule->defaultOptionsCB->isChecked();
3898
3899         if (latexModule->childDocGB->isChecked())
3900                 bp_.master =
3901                         fromqstr(latexModule->childDocLE->text());
3902         else
3903                 bp_.master = string();
3904
3905         // Master/Child
3906         bp_.clearIncludedChildren();
3907         updateIncludeonlys();
3908         if (masterChildModule->includeonlyRB->isChecked()) {
3909                 list<string>::const_iterator it = includeonlys_.begin();
3910                 for (; it != includeonlys_.end() ; ++it) {
3911                         bp_.addIncludedChildren(*it);
3912                 }
3913         }
3914         if (masterChildModule->maintainCRNoneRB->isChecked())
3915                 bp_.maintain_unincluded_children =
3916                         BufferParams::CM_None;
3917         else if (masterChildModule->maintainCRMostlyRB->isChecked())
3918                 bp_.maintain_unincluded_children =
3919                         BufferParams::CM_Mostly;
3920         else
3921                 bp_.maintain_unincluded_children =
3922                         BufferParams::CM_Strict;
3923         updateIncludeonlyDisplay();
3924
3925         // Float Settings
3926         bp_.float_placement = floatModule->getPlacement();
3927         bp_.float_alignment = floatModule->getAlignment();
3928
3929         // Listings
3930         // text should have passed validation
3931         idx = listingsModule->packageCO->currentIndex();
3932         bp_.use_minted = string(lst_packages[idx]) == "Minted";
3933         bp_.listings_params =
3934                 InsetListingsParams(fromqstr(listingsModule->listingsED->toPlainText())).params();
3935
3936         // Formats
3937         bp_.default_output_format = fromqstr(outputModule->defaultFormatCO->itemData(
3938                 outputModule->defaultFormatCO->currentIndex()).toString());
3939
3940         bool const nontexfonts = fontModule->osFontsCB->isChecked();
3941         bp_.useNonTeXFonts = nontexfonts;
3942
3943         bp_.shell_escape = outputModule->shellescapeCB->isChecked();
3944         if (!bp_.shell_escape)
3945             theSession().shellescapeFiles().remove(buffer().absFileName());
3946         else if (!theSession().shellescapeFiles().find(buffer().absFileName()))
3947             theSession().shellescapeFiles().insert(buffer().absFileName());
3948         Buffer & buf = const_cast<Buffer &>(buffer());
3949         buf.params().shell_escape = bp_.shell_escape;
3950
3951         bp_.output_sync = outputModule->outputsyncCB->isChecked();
3952
3953         bp_.output_sync_macro = fromqstr(outputModule->synccustomCB->currentText());
3954
3955         int mathfmt = outputModule->mathoutCB->currentIndex();
3956         if (mathfmt == -1)
3957                 mathfmt = 0;
3958         BufferParams::MathOutput const mo =
3959                 static_cast<BufferParams::MathOutput>(mathfmt);
3960         bp_.html_math_output = mo;
3961         bp_.html_be_strict = outputModule->strictCB->isChecked();
3962         bp_.html_css_as_file = outputModule->cssCB->isChecked();
3963         bp_.html_math_img_scale = outputModule->mathimgSB->value();
3964         bp_.display_pixel_ratio = theGuiApp()->pixelRatio();
3965
3966         int tablefmt = outputModule->tableoutCB->currentIndex();
3967         if (tablefmt == -1)
3968                 tablefmt = 0;
3969         auto const to = static_cast<BufferParams::TableOutput>(tablefmt);
3970         bp_.docbook_table_output = to;
3971
3972         int mathmlprefix = outputModule->mathmlprefixCB->currentIndex();
3973         if (mathmlprefix == -1)
3974                 mathmlprefix = 0;
3975         auto const mp = static_cast<BufferParams::MathMLNameSpacePrefix>(mathmlprefix);
3976         bp_.docbook_mathml_prefix = mp;
3977
3978         bp_.save_transient_properties =
3979                 outputModule->saveTransientPropertiesCB->isChecked();
3980         bp_.postpone_fragile_content =
3981                 outputModule->postponeFragileCB->isChecked();
3982
3983         // fonts
3984         bp_.fonts_roman[nontexfonts] =
3985                 fromqstr(fontModule->fontsRomanCO->
3986                         getData(fontModule->fontsRomanCO->currentIndex()));
3987         bp_.fonts_roman[!nontexfonts] = fromqstr(fontModule->font_roman);
3988         bp_.font_roman_opts = fromqstr(fontModule->fontspecRomanLE->text());
3989
3990         bp_.fonts_sans[nontexfonts] =
3991                 fromqstr(fontModule->fontsSansCO->
3992                         getData(fontModule->fontsSansCO->currentIndex()));
3993         bp_.fonts_sans[!nontexfonts] = fromqstr(fontModule->font_sans);
3994         bp_.font_sans_opts = fromqstr(fontModule->fontspecSansLE->text());
3995
3996         bp_.fonts_typewriter[nontexfonts] =
3997                 fromqstr(fontModule->fontsTypewriterCO->
3998                         getData(fontModule->fontsTypewriterCO->currentIndex()));
3999         bp_.fonts_typewriter[!nontexfonts] = fromqstr(fontModule->font_typewriter);
4000         bp_.font_typewriter_opts = fromqstr(fontModule->fontspecTypewriterLE->text());
4001
4002         bp_.fonts_math[nontexfonts] =
4003                 fromqstr(fontModule->fontsMathCO->
4004                         itemData(fontModule->fontsMathCO->currentIndex()).toString());
4005         bp_.fonts_math[!nontexfonts] = fromqstr(fontModule->font_math);
4006
4007         QString const fontenc =
4008                 fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString();
4009         if (fontenc == "custom")
4010                 bp_.fontenc = fromqstr(fontModule->fontencLE->text());
4011         else
4012                 bp_.fontenc = fromqstr(fontenc);
4013
4014         bp_.fonts_cjk =
4015                 fromqstr(fontModule->cjkFontLE->text());
4016
4017         bp_.use_microtype = fontModule->microtypeCB->isChecked();
4018         bp_.use_dash_ligatures = !fontModule->dashesCB->isChecked();
4019
4020         bp_.fonts_sans_scale[nontexfonts] = fontModule->scaleSansSB->value();
4021         bp_.fonts_sans_scale[!nontexfonts] = fontModule->font_sf_scale;
4022
4023         bp_.fonts_typewriter_scale[nontexfonts] = fontModule->scaleTypewriterSB->value();
4024         bp_.fonts_typewriter_scale[!nontexfonts] = fontModule->font_tt_scale;
4025
4026         bp_.fonts_expert_sc = fontModule->fontScCB->isChecked();
4027
4028         bp_.fonts_roman_osf = fontModule->fontOsfCB->isChecked();
4029         bp_.fonts_sans_osf = fontModule->fontSansOsfCB->isChecked();
4030         bp_.fonts_typewriter_osf = fontModule->fontTypewriterOsfCB->isChecked();
4031
4032         bp_.fonts_default_family = GuiDocument::fontfamilies[
4033                 fontModule->fontsDefaultCO->currentIndex()];
4034
4035         if (fontModule->fontsizeCO->currentIndex() == 0)
4036                 bp_.fontsize = "default";
4037         else
4038                 bp_.fontsize =
4039                         fromqstr(fontModule->fontsizeCO->currentText());
4040
4041         // paper
4042         bp_.papersize = PAPER_SIZE(
4043                 pageLayoutModule->papersizeCO->currentIndex());
4044
4045         bp_.paperwidth = widgetsToLength(pageLayoutModule->paperwidthLE,
4046                 pageLayoutModule->paperwidthUnitCO);
4047
4048         bp_.paperheight = widgetsToLength(pageLayoutModule->paperheightLE,
4049                 pageLayoutModule->paperheightUnitCO);
4050
4051         if (pageLayoutModule->facingPagesCB->isChecked())
4052                 bp_.sides = TwoSides;
4053         else
4054                 bp_.sides = OneSide;
4055
4056         if (pageLayoutModule->landscapeRB->isChecked())
4057                 bp_.orientation = ORIENTATION_LANDSCAPE;
4058         else
4059                 bp_.orientation = ORIENTATION_PORTRAIT;
4060
4061         // margins
4062         bp_.use_geometry = !marginsModule->marginCB->isChecked();
4063
4064         Ui::MarginsUi const * m = marginsModule;
4065
4066         if (bp_.use_geometry) {
4067                 bp_.leftmargin = widgetsToLength(m->innerLE, m->innerUnit);
4068                 bp_.topmargin = widgetsToLength(m->topLE, m->topUnit);
4069                 bp_.rightmargin = widgetsToLength(m->outerLE, m->outerUnit);
4070                 bp_.bottommargin = widgetsToLength(m->bottomLE, m->bottomUnit);
4071                 bp_.headheight = widgetsToLength(m->headheightLE, m->headheightUnit);
4072                 bp_.headsep = widgetsToLength(m->headsepLE, m->headsepUnit);
4073                 bp_.footskip = widgetsToLength(m->footskipLE, m->footskipUnit);
4074                 bp_.columnsep = widgetsToLength(m->columnsepLE, m->columnsepUnit);
4075         }
4076
4077         // branches
4078         branchesModule->apply(bp_);
4079
4080         // PDF support
4081         PDFOptions & pdf = bp_.pdfoptions();
4082         pdf.use_hyperref = pdfSupportModule->use_hyperrefGB->isChecked();
4083         pdf.title = fromqstr(pdfSupportModule->titleLE->text());
4084         pdf.author = fromqstr(pdfSupportModule->authorLE->text());
4085         pdf.subject = fromqstr(pdfSupportModule->subjectLE->text());
4086         pdf.keywords = fromqstr(pdfSupportModule->keywordsLE->text());
4087
4088         pdf.bookmarks = pdfSupportModule->bookmarksGB->isChecked();
4089         pdf.bookmarksnumbered = pdfSupportModule->bookmarksnumberedCB->isChecked();
4090         pdf.bookmarksopen = pdfSupportModule->bookmarksopenGB->isChecked();
4091         pdf.bookmarksopenlevel = pdfSupportModule->bookmarksopenlevelSB->value();
4092
4093         pdf.breaklinks = pdfSupportModule->breaklinksCB->isChecked();
4094         pdf.pdfborder = pdfSupportModule->pdfborderCB->isChecked();
4095         pdf.pdfusetitle = pdfSupportModule->pdfusetitleCB->isChecked();
4096         pdf.colorlinks = pdfSupportModule->colorlinksCB->isChecked();
4097         pdf.backref =
4098                 backref_opts[pdfSupportModule->backrefCO->currentIndex()];
4099         if (pdfSupportModule->fullscreenCB->isChecked())
4100                 pdf.pagemode = pdf.pagemode_fullscreen;
4101         else
4102                 pdf.pagemode.clear();
4103         pdf.quoted_options = pdf.quoted_options_check(
4104                                 fromqstr(pdfSupportModule->optionsTE->toPlainText()));
4105         bp_.document_metadata = qstring_to_ucs4(pdfSupportModule->metadataTE->toPlainText()
4106                                                 .trimmed().replace(QRegularExpression("\n+"), "\n"));
4107
4108         // change tracking
4109         bp_.track_changes = changesModule->trackChangesCB->isChecked();
4110         bp_.output_changes = changesModule->outputChangesCB->isChecked();
4111         bool const cb_switched_off = (bp_.change_bars
4112                                       && !changesModule->changeBarsCB->isChecked());
4113         bp_.change_bars = changesModule->changeBarsCB->isChecked();
4114         if (cb_switched_off)
4115                 // if change bars have been switched off,
4116                 // we need to ditch the aux file
4117                 buffer().requireFreshStart(true);
4118
4119         // reset trackers
4120         nonModuleChanged_ = false;
4121         shellescapeChanged_ = false;
4122 }
4123
4124
4125 void GuiDocument::paramsToDialog()
4126 {
4127         // set the default unit
4128         Length::UNIT const default_unit = Length::defaultUnit();
4129
4130         // preamble
4131         preambleModule->update(bp_, id());
4132         localLayout->update(bp_, id());
4133
4134         // date
4135         latexModule->suppressDateCB->setChecked(bp_.suppress_date);
4136         latexModule->refstyleCB->setChecked(bp_.use_refstyle);
4137         latexModule->refFormattedCB->setChecked(bp_.use_formatted_ref);
4138
4139         // biblio
4140         string const cite_engine = bp_.citeEngine();
4141
4142         biblioModule->citeEngineCO->setCurrentIndex(
4143                 biblioModule->citeEngineCO->findData(toqstr(cite_engine)));
4144
4145         updateEngineType(documentClass().opt_enginetype(),
4146                 bp_.citeEngineType());
4147
4148         checkPossibleCiteEngines();
4149
4150         biblioModule->citeStyleCO->setCurrentIndex(
4151                 biblioModule->citeStyleCO->findData(bp_.citeEngineType()));
4152
4153         biblioModule->bibtopicCB->setChecked(bp_.splitbib());
4154
4155         biblioModule->bibunitsCO->clear();
4156         biblioModule->bibunitsCO->addItem(qt_("No"), QString());
4157         if (documentClass().hasLaTeXLayout("part"))
4158                 biblioModule->bibunitsCO->addItem(qt_("per part"), toqstr("part"));
4159         if (documentClass().hasLaTeXLayout("chapter"))
4160                 biblioModule->bibunitsCO->addItem(qt_("per chapter"), toqstr("chapter"));
4161         if (documentClass().hasLaTeXLayout("section"))
4162                 biblioModule->bibunitsCO->addItem(qt_("per section"), toqstr("section"));
4163         if (documentClass().hasLaTeXLayout("subsection"))
4164                 biblioModule->bibunitsCO->addItem(qt_("per subsection"), toqstr("subsection"));
4165         biblioModule->bibunitsCO->addItem(qt_("per child document"), toqstr("child"));
4166
4167         int const mbpos = biblioModule->bibunitsCO->findData(toqstr(bp_.multibib));
4168         if (mbpos != -1)
4169                 biblioModule->bibunitsCO->setCurrentIndex(mbpos);
4170         else
4171                 biblioModule->bibunitsCO->setCurrentIndex(0);
4172
4173         updateEngineDependends();
4174
4175         if (isBiblatex()) {
4176                 updateDefaultBiblio(bp_.biblatex_bibstyle, "bbx");
4177                 updateDefaultBiblio(bp_.biblatex_citestyle, "cbx");
4178         } else
4179                 updateDefaultBiblio(bp_.defaultBiblioStyle());
4180
4181         biblioModule->citePackageOptionsLE->setText(toqstr(bp_.biblio_opts));
4182
4183         string command;
4184         string options =
4185                 split(bp_.bibtex_command, command, ' ');
4186
4187         int bpos = biblioModule->bibtexCO->findData(toqstr(command));
4188         if (bpos == -1) {
4189                 // We add and set the unknown compiler, indicating that it is unavailable
4190                 // to assure document compilation and for security reasons, a fallback
4191                 // will be used on document processing stage
4192                 biblioModule->bibtexCO->addItem(toqstr(bformat(_("%1$s (not available)"),
4193                                                         from_utf8(command))), toqstr(command));
4194                 bpos = biblioModule->bibtexCO->findData(toqstr(command));
4195         }
4196         biblioModule->bibtexCO->setCurrentIndex(bpos);
4197         biblioModule->bibtexOptionsLE->setText(toqstr(options).trimmed());
4198         biblioModule->bibtexOptionsLE->setEnabled(
4199                 biblioModule->bibtexCO->currentIndex() != 0);
4200
4201         biblioChanged_ = false;
4202
4203         // indices
4204         // We may be called when there is no Buffer, e.g., when
4205         // the last view has just been closed.
4206         bool const isReadOnly = isBufferAvailable() ? buffer().isReadonly() : false;
4207         indicesModule->update(bp_, isReadOnly);
4208
4209         // language & quotes
4210         int const pos = langModule->languageCO->findData(toqstr(
4211                 bp_.language->lang()));
4212         langModule->languageCO->setCurrentIndex(pos);
4213
4214         updateQuoteStyles();
4215
4216         langModule->quoteStyleCO->setCurrentIndex(
4217                 langModule->quoteStyleCO->findData(static_cast<int>(bp_.quotes_style)));
4218         langModule->dynamicQuotesCB->setChecked(bp_.dynamic_quotes);
4219
4220         // LaTeX input encoding: set after the fonts (see below)
4221
4222         int p = langModule->languagePackageCO->findData(toqstr(bp_.lang_package));
4223         if (p == -1) {
4224                 langModule->languagePackageCO->setCurrentIndex(
4225                           langModule->languagePackageCO->findData("custom"));
4226                 langModule->languagePackageLE->setText(toqstr(bp_.lang_package));
4227         } else {
4228                 langModule->languagePackageCO->setCurrentIndex(p);
4229                 langModule->languagePackageLE->clear();
4230         }
4231
4232         //color
4233         if (bp_.isfontcolor) {
4234                 colorModule->mainTextCF->setStyleSheet(
4235                         colorFrameStyleSheet(rgb2qcolor(bp_.fontcolor)));
4236                 colorModule->mainTextCF->setVisible(true);
4237         } else
4238                 colorModule->mainTextCF->setVisible(false);
4239         set_fontcolor = bp_.fontcolor;
4240         is_fontcolor = bp_.isfontcolor;
4241
4242         colorModule->noteFontCF->setStyleSheet(
4243                 colorFrameStyleSheet(rgb2qcolor(bp_.notefontcolor)));
4244         set_notefontcolor = bp_.notefontcolor;
4245         is_notefontcolor = bp_.isnotefontcolor;
4246
4247         if (bp_.isbackgroundcolor) {
4248                 colorModule->pageBackgroundCF->setStyleSheet(
4249                         colorFrameStyleSheet(rgb2qcolor(bp_.backgroundcolor)));
4250                 colorModule->pageBackgroundCF->setVisible(true);
4251         } else
4252                 colorModule->pageBackgroundCF->setVisible(false);
4253         set_backgroundcolor = bp_.backgroundcolor;
4254         is_backgroundcolor = bp_.isbackgroundcolor;
4255
4256         colorModule->boxBackgroundCF->setStyleSheet(
4257                 colorFrameStyleSheet(rgb2qcolor(bp_.boxbgcolor)));
4258         set_boxbgcolor = bp_.boxbgcolor;
4259         is_boxbgcolor = bp_.isboxbgcolor;
4260
4261         // numbering
4262         int const min_toclevel = documentClass().min_toclevel();
4263         int const max_toclevel = documentClass().max_toclevel();
4264         if (documentClass().hasTocLevels()) {
4265                 numberingModule->setEnabled(true);
4266                 numberingModule->depthSL->setMinimum(min_toclevel - 1);
4267                 numberingModule->depthSL->setMaximum(max_toclevel);
4268                 numberingModule->depthSL->setValue(bp_.secnumdepth);
4269                 numberingModule->tocSL->setMaximum(min_toclevel - 1);
4270                 numberingModule->tocSL->setMaximum(max_toclevel);
4271                 numberingModule->tocSL->setValue(bp_.tocdepth);
4272                 updateNumbering();
4273         } else {
4274                 numberingModule->setEnabled(false);
4275                 numberingModule->tocTW->clear();
4276         }
4277
4278         numberingModule->linenoCB->setChecked(bp_.use_lineno);
4279         numberingModule->linenoLE->setEnabled(bp_.use_lineno);
4280         numberingModule->linenoLA->setEnabled(bp_.use_lineno);
4281         numberingModule->linenoLE->setText(toqstr(bp_.lineno_opts));
4282
4283         // bullets
4284         bulletsModule->setBullet(0, bp_.user_defined_bullet(0));
4285         bulletsModule->setBullet(1, bp_.user_defined_bullet(1));
4286         bulletsModule->setBullet(2, bp_.user_defined_bullet(2));
4287         bulletsModule->setBullet(3, bp_.user_defined_bullet(3));
4288         bulletsModule->init();
4289
4290         // packages
4291         int nitem = findToken(tex_graphics, bp_.graphics_driver);
4292         if (nitem >= 0)
4293                 latexModule->psdriverCO->setCurrentIndex(nitem);
4294         updateModuleInfo();
4295
4296         // math
4297         mathsModule->MathIndentCB->setChecked(bp_.is_math_indent);
4298         if (bp_.is_math_indent) {
4299                 Length const mathindent = bp_.getMathIndent();
4300                 int indent = 0;
4301                 if (!mathindent.empty()) {
4302                         lengthToWidgets(mathsModule->MathIndentLE,
4303                                         mathsModule->MathIndentLengthCO,
4304                                         mathindent, default_unit);
4305                         indent = 1;
4306                 }
4307                 mathsModule->MathIndentCO->setCurrentIndex(indent);
4308                 enableMathIndent(indent);
4309         }
4310         switch(bp_.math_numbering_side) {
4311         case BufferParams::LEFT:
4312                 mathsModule->MathNumberingPosCO->setCurrentIndex(0);
4313                 break;
4314         case BufferParams::DEFAULT:
4315                 mathsModule->MathNumberingPosCO->setCurrentIndex(1);
4316                 break;
4317         case BufferParams::RIGHT:
4318                 mathsModule->MathNumberingPosCO->setCurrentIndex(2);
4319         }
4320
4321         map<string, string> const & packages = BufferParams::auto_packages();
4322         for (map<string, string>::const_iterator it = packages.begin();
4323              it != packages.end(); ++it) {
4324                 QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
4325                 if (!item)
4326                         continue;
4327                 int row = mathsModule->packagesTW->row(item);
4328                 switch (bp_.use_package(it->first)) {
4329                         case BufferParams::package_off: {
4330                                 QRadioButton * rb =
4331                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
4332                                 rb->setChecked(true);
4333                                 break;
4334                         }
4335                         case BufferParams::package_on: {
4336                                 QRadioButton * rb =
4337                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
4338                                 rb->setChecked(true);
4339                                 break;
4340                         }
4341                         case BufferParams::package_auto: {
4342                                 QRadioButton * rb =
4343                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
4344                                 rb->setChecked(true);
4345                                 break;
4346                         }
4347                 }
4348         }
4349
4350         switch (bp_.spacing().getSpace()) {
4351                 case Spacing::Other: nitem = 3; break;
4352                 case Spacing::Double: nitem = 2; break;
4353                 case Spacing::Onehalf: nitem = 1; break;
4354                 case Spacing::Default: case Spacing::Single: nitem = 0; break;
4355         }
4356
4357         // text layout
4358         string const & layoutID = bp_.baseClassID();
4359         setLayoutComboByIDString(layoutID);
4360
4361         updatePagestyle(documentClass().opt_pagestyle(),
4362                                  bp_.pagestyle);
4363
4364         textLayoutModule->lspacingCO->setCurrentIndex(nitem);
4365         if (bp_.spacing().getSpace() == Spacing::Other) {
4366                 doubleToWidget(textLayoutModule->lspacingLE,
4367                         bp_.spacing().getValueAsString());
4368         }
4369         setLSpacing(nitem);
4370         int ts = textLayoutModule->tableStyleCO->findData(toqstr(bp_.tablestyle));
4371         if (ts != -1)
4372                 textLayoutModule->tableStyleCO->setCurrentIndex(ts);
4373
4374         if (bp_.paragraph_separation == BufferParams::ParagraphIndentSeparation) {
4375                 textLayoutModule->indentRB->setChecked(true);
4376                 string parindent = bp_.getParIndent().asString();
4377                 QString indent = toqstr("default");
4378                 if (!parindent.empty()) {
4379                         lengthToWidgets(textLayoutModule->indentLE,
4380                                         textLayoutModule->indentLengthCO,
4381                                         parindent, default_unit);
4382                         indent = toqstr("custom");
4383                 }
4384                 textLayoutModule->indentCO->setCurrentIndex(textLayoutModule->indentCO->findData(indent));
4385                 setIndent(textLayoutModule->indentCO->currentIndex());
4386         } else {
4387                 textLayoutModule->skipRB->setChecked(true);
4388                 VSpace::VSpaceKind skip = bp_.getDefSkip().kind();
4389                 textLayoutModule->skipCO->setCurrentIndex(textLayoutModule->skipCO->findData(skip));
4390                 if (skip == VSpace::LENGTH) {
4391                         string const length = bp_.getDefSkip().asLyXCommand();
4392                         lengthToWidgets(textLayoutModule->skipLE,
4393                                 textLayoutModule->skipLengthCO,
4394                                 length, default_unit);
4395                 }
4396                 setSkip(textLayoutModule->skipCO->currentIndex());
4397         }
4398
4399         textLayoutModule->twoColumnCB->setChecked(
4400                 bp_.columns == 2);
4401         textLayoutModule->justCB->setChecked(bp_.justification);
4402
4403         if (!bp_.options.empty()) {
4404                 latexModule->optionsLE->setText(
4405                         toqstr(bp_.options));
4406         } else {
4407                 latexModule->optionsLE->setText(QString());
4408         }
4409
4410         // latex
4411         latexModule->defaultOptionsCB->setChecked(
4412                         bp_.use_default_options);
4413         updateSelectedModules();
4414         selectionManager->updateProvidedModules(
4415                         bp_.baseClass()->providedModules());
4416         selectionManager->updateExcludedModules(
4417                         bp_.baseClass()->excludedModules());
4418
4419         if (!documentClass().options().empty()) {
4420                 latexModule->defaultOptionsLE->setText(
4421                         toqstr(documentClass().options()));
4422         } else {
4423                 latexModule->defaultOptionsLE->setText(
4424                         toqstr(_("[No options predefined]")));
4425         }
4426
4427         latexModule->defaultOptionsLE->setEnabled(
4428                 bp_.use_default_options
4429                 && !documentClass().options().empty());
4430
4431         latexModule->defaultOptionsCB->setEnabled(
4432                 !documentClass().options().empty());
4433
4434         if (!bp_.master.empty()) {
4435                 latexModule->childDocGB->setChecked(true);
4436                 latexModule->childDocLE->setText(
4437                         toqstr(bp_.master));
4438         } else {
4439                 latexModule->childDocLE->setText(QString());
4440                 latexModule->childDocGB->setChecked(false);
4441         }
4442
4443         // Master/Child
4444         if (!bufferview() || !buffer().hasChildren()) {
4445                 masterChildModule->childrenTW->clear();
4446                 includeonlys_.clear();
4447                 docPS->showPanel("Child Documents", false);
4448                 if (docPS->isCurrentPanel("Child Documents"))
4449                         docPS->setCurrentPanel("Document Class");
4450         } else {
4451                 docPS->showPanel("Child Documents", true);
4452                 masterChildModule->setEnabled(true);
4453                 includeonlys_ = bp_.getIncludedChildren();
4454                 updateIncludeonlys();
4455                 updateIncludeonlyDisplay();
4456         }
4457         switch (bp_.maintain_unincluded_children) {
4458         case BufferParams::CM_None:
4459                 masterChildModule->maintainCRNoneRB->setChecked(true);
4460                 break;
4461         case BufferParams::CM_Mostly:
4462                 masterChildModule->maintainCRMostlyRB->setChecked(true);
4463                 break;
4464         case BufferParams::CM_Strict:
4465         default:
4466                 masterChildModule->maintainCRStrictRB->setChecked(true);
4467                 break;
4468         }
4469
4470         // Float Settings
4471         floatModule->setPlacement(bp_.float_placement);
4472         floatModule->setAlignment(bp_.float_alignment);
4473
4474         // ListingsSettings
4475         // break listings_params to multiple lines
4476         string lstparams =
4477                 InsetListingsParams(bp_.listings_params).separatedParams();
4478         listingsModule->listingsED->setPlainText(toqstr(lstparams));
4479         int nn = findToken(lst_packages, bp_.use_minted ? "Minted" : "Listings");
4480         if (nn >= 0)
4481                 listingsModule->packageCO->setCurrentIndex(nn);
4482
4483         // Fonts
4484         // some languages only work with Polyglossia (which requires non-TeX fonts)
4485         Language const * lang = lyx::languages.getLanguage(
4486                 fromqstr(langModule->languageCO->itemData(
4487                         langModule->languageCO->currentIndex()).toString()));
4488         bool const need_fontspec =
4489                 lang->babel().empty() && !lang->polyglossia().empty()
4490                 && lang->required() != "CJK" && lang->required() != "japanese";
4491         bool const os_fonts_available =
4492                 bp_.baseClass()->outputType() == lyx::LATEX
4493                 && LaTeXFeatures::isAvailable("fontspec");
4494         fontModule->osFontsCB->setEnabled(os_fonts_available && !need_fontspec);
4495         fontModule->osFontsCB->setChecked(
4496                 (os_fonts_available && bp_.useNonTeXFonts) || need_fontspec);
4497         updateFontsize(documentClass().opt_fontsize(),
4498                         bp_.fontsize);
4499
4500         QString font = toqstr(bp_.fontsRoman());
4501         bool foundfont = fontModule->fontsRomanCO->set(font, false);
4502         if (!foundfont) {
4503                 fontModule->fontsRomanCO->addItemSort(font, font + qt_(" (not installed)"),
4504                                                       qt_("Uninstalled used fonts"),
4505                                                       qt_("This font is not installed and won't be used in output"),
4506                                                       false, false, false, true);
4507                 fontModule->fontsRomanCO->set(font);
4508         }
4509         fontModule->font_roman = toqstr(bp_.fonts_roman[!bp_.useNonTeXFonts]);
4510
4511         font = toqstr(bp_.fontsSans());
4512         foundfont = fontModule->fontsSansCO->set(font, false);
4513         if (!foundfont) {
4514                 fontModule->fontsSansCO->addItemSort(font, font + qt_(" (not installed)"),
4515                                                      qt_("Uninstalled used fonts"),
4516                                                      qt_("This font is not installed and won't be used in output"),
4517                                                      false, false, false, true);
4518                 fontModule->fontsSansCO->set(font);
4519         }
4520         fontModule->font_sans = toqstr(bp_.fonts_sans[!bp_.useNonTeXFonts]);
4521
4522         font = toqstr(bp_.fontsTypewriter());
4523         foundfont = fontModule->fontsTypewriterCO->set(font, false);
4524         if (!foundfont) {
4525                 fontModule->fontsTypewriterCO->addItemSort(font, font + qt_(" (not installed)"),
4526                                                            qt_("Uninstalled used fonts"),
4527                                                            qt_("This font is not installed and won't be used in output"),
4528                                                            false, false, false, true);
4529                 fontModule->fontsTypewriterCO->set(font);
4530         }
4531         fontModule->font_typewriter = toqstr(bp_.fonts_typewriter[!bp_.useNonTeXFonts]);
4532
4533         font = toqstr(bp_.fontsMath());
4534         int mpos = fontModule->fontsMathCO->findData(font);
4535         if (mpos == -1) {
4536                 mpos = fontModule->fontsMathCO->count();
4537                 fontModule->fontsMathCO->addItem(font + qt_(" (not installed)"), font);
4538         }
4539         fontModule->fontsMathCO->setCurrentIndex(mpos);
4540         fontModule->font_math = toqstr(bp_.fonts_math[!bp_.useNonTeXFonts]);
4541
4542         if (bp_.useNonTeXFonts && os_fonts_available) {
4543                 fontModule->fontencLA->setEnabled(false);
4544                 fontModule->fontencCO->setEnabled(false);
4545                 fontModule->fontencLE->setEnabled(false);
4546         } else {
4547                 fontModule->fontencLA->setEnabled(true);
4548                 fontModule->fontencCO->setEnabled(true);
4549                 fontModule->fontencLE->setEnabled(true);
4550                 romanChanged(fontModule->fontsRomanCO->currentIndex());
4551                 sansChanged(fontModule->fontsSansCO->currentIndex());
4552                 ttChanged(fontModule->fontsTypewriterCO->currentIndex());
4553         }
4554         // Handle options enabling
4555         updateFontOptions();
4556
4557         if (!bp_.fonts_cjk.empty())
4558                 fontModule->cjkFontLE->setText(
4559                         toqstr(bp_.fonts_cjk));
4560         else
4561                 fontModule->cjkFontLE->setText(QString());
4562
4563         fontModule->microtypeCB->setChecked(bp_.use_microtype);
4564         fontModule->dashesCB->setChecked(!bp_.use_dash_ligatures);
4565
4566         fontModule->fontScCB->setChecked(bp_.fonts_expert_sc);
4567         fontModule->fontOsfCB->setChecked(bp_.fonts_roman_osf);
4568         fontModule->fontSansOsfCB->setChecked(bp_.fonts_sans_osf);
4569         fontModule->fontTypewriterOsfCB->setChecked(bp_.fonts_typewriter_osf);
4570         fontModule->scaleSansSB->setValue(bp_.fontsSansScale());
4571         fontModule->font_sf_scale = bp_.fonts_sans_scale[!bp_.useNonTeXFonts];
4572         fontModule->scaleTypewriterSB->setValue(bp_.fontsTypewriterScale());
4573         fontModule->font_tt_scale = bp_.fonts_typewriter_scale[!bp_.useNonTeXFonts];
4574         if (!bp_.font_roman_opts.empty())
4575                 fontModule->fontspecRomanLE->setText(
4576                         toqstr(bp_.font_roman_opts));
4577         else
4578                 fontModule->fontspecRomanLE->setText(QString());
4579         if (!bp_.font_sans_opts.empty())
4580                 fontModule->fontspecSansLE->setText(
4581                         toqstr(bp_.font_sans_opts));
4582         else
4583                 fontModule->fontspecSansLE->setText(QString());
4584         if (!bp_.font_typewriter_opts.empty())
4585                 fontModule->fontspecTypewriterLE->setText(
4586                         toqstr(bp_.font_typewriter_opts));
4587         else
4588                 fontModule->fontspecTypewriterLE->setText(QString());
4589
4590         nn = findToken(GuiDocument::fontfamilies, bp_.fonts_default_family);
4591         if (nn >= 0)
4592                 fontModule->fontsDefaultCO->setCurrentIndex(nn);
4593
4594         if (bp_.fontenc == "auto" || bp_.fontenc == "default") {
4595                 fontModule->fontencCO->setCurrentIndex(
4596                         fontModule->fontencCO->findData(toqstr(bp_.fontenc)));
4597                 fontModule->fontencLE->setEnabled(false);
4598         } else {
4599                 fontModule->fontencCO->setCurrentIndex(
4600                                         fontModule->fontencCO->findData("custom"));
4601                 fontModule->fontencLE->setText(toqstr(bp_.fontenc));
4602         }
4603
4604         // LaTeX input encoding
4605         // Set after fonts because non-tex fonts override "\inputencoding".
4606         inputencodingToDialog();
4607
4608         // Formats
4609         // This must be set _after_ fonts since updateDefaultFormat()
4610         // checks osFontsCB settings.
4611         // update combobox with formats
4612         updateDefaultFormat();
4613         int index = outputModule->defaultFormatCO->findData(toqstr(
4614                 bp_.default_output_format));
4615         // set to default if format is not found
4616         if (index == -1)
4617                 index = 0;
4618         outputModule->defaultFormatCO->setCurrentIndex(index);
4619
4620         outputModule->shellescapeCB->setChecked(bp_.shell_escape);
4621         outputModule->outputsyncCB->setChecked(bp_.output_sync);
4622         outputModule->synccustomCB->setEditText(toqstr(bp_.output_sync_macro));
4623         outputModule->synccustomCB->setEnabled(bp_.output_sync);
4624         outputModule->synccustomLA->setEnabled(bp_.output_sync);
4625
4626         outputModule->mathimgSB->setValue(bp_.html_math_img_scale);
4627         outputModule->mathoutCB->setCurrentIndex(bp_.html_math_output);
4628         outputModule->strictCB->setChecked(bp_.html_be_strict);
4629         outputModule->cssCB->setChecked(bp_.html_css_as_file);
4630
4631         outputModule->tableoutCB->setCurrentIndex(bp_.docbook_table_output);
4632         outputModule->mathmlprefixCB->setCurrentIndex(bp_.docbook_mathml_prefix);
4633
4634         outputModule->saveTransientPropertiesCB
4635                 ->setChecked(bp_.save_transient_properties);
4636         outputModule->postponeFragileCB
4637                 ->setChecked(bp_.postpone_fragile_content);
4638
4639         // paper
4640         bool const extern_geometry =
4641                 documentClass().provides("geometry");
4642         int const psize = bp_.papersize;
4643         pageLayoutModule->papersizeCO->setCurrentIndex(psize);
4644         setCustomPapersize(!extern_geometry && psize == 1);
4645         pageLayoutModule->papersizeCO->setEnabled(!extern_geometry);
4646
4647         bool const landscape =
4648                 bp_.orientation == ORIENTATION_LANDSCAPE;
4649         pageLayoutModule->landscapeRB->setChecked(landscape);
4650         pageLayoutModule->portraitRB->setChecked(!landscape);
4651         pageLayoutModule->landscapeRB->setEnabled(!extern_geometry);
4652         pageLayoutModule->portraitRB->setEnabled(!extern_geometry);
4653
4654         pageLayoutModule->facingPagesCB->setChecked(
4655                 bp_.sides == TwoSides);
4656
4657         lengthToWidgets(pageLayoutModule->paperwidthLE,
4658                 pageLayoutModule->paperwidthUnitCO, bp_.paperwidth, default_unit);
4659         lengthToWidgets(pageLayoutModule->paperheightLE,
4660                 pageLayoutModule->paperheightUnitCO, bp_.paperheight, default_unit);
4661
4662         // margins
4663         Ui::MarginsUi * m = marginsModule;
4664
4665         tmp_leftmargin_ = bp_.leftmargin;
4666         tmp_topmargin_ = bp_.topmargin;
4667         tmp_rightmargin_ = bp_.rightmargin;
4668         tmp_bottommargin_ = bp_.bottommargin;
4669         tmp_headheight_ = bp_.headheight;
4670         tmp_headsep_ = bp_.headsep;
4671         tmp_footskip_ = bp_.footskip;
4672         tmp_columnsep_ = bp_.columnsep;
4673
4674         lengthToWidgets(m->topLE, m->topUnit,
4675                 bp_.topmargin, default_unit);
4676         lengthToWidgets(m->bottomLE, m->bottomUnit,
4677                 bp_.bottommargin, default_unit);
4678         lengthToWidgets(m->innerLE, m->innerUnit,
4679                 bp_.leftmargin, default_unit);
4680         lengthToWidgets(m->outerLE, m->outerUnit,
4681                 bp_.rightmargin, default_unit);
4682         lengthToWidgets(m->headheightLE, m->headheightUnit,
4683                 bp_.headheight, default_unit);
4684         lengthToWidgets(m->headsepLE, m->headsepUnit,
4685                 bp_.headsep, default_unit);
4686         lengthToWidgets(m->footskipLE, m->footskipUnit,
4687                 bp_.footskip, default_unit);
4688         lengthToWidgets(m->columnsepLE, m->columnsepUnit,
4689                 bp_.columnsep, default_unit);
4690
4691         setMargins();
4692
4693         // branches
4694         updateUnknownBranches();
4695         branchesModule->update(bp_);
4696
4697         // PDF support
4698         PDFOptions const & pdf = bp_.pdfoptions();
4699         pdfSupportModule->use_hyperrefGB->setChecked(pdf.use_hyperref);
4700         if (bp_.documentClass().provides("hyperref"))
4701                 pdfSupportModule->use_hyperrefGB->setTitle(qt_("C&ustomize Hyperref Options"));
4702         else
4703                 pdfSupportModule->use_hyperrefGB->setTitle(qt_("&Use Hyperref Support"));
4704         pdfSupportModule->titleLE->setText(toqstr(pdf.title));
4705         pdfSupportModule->authorLE->setText(toqstr(pdf.author));
4706         pdfSupportModule->subjectLE->setText(toqstr(pdf.subject));
4707         pdfSupportModule->keywordsLE->setText(toqstr(pdf.keywords));
4708
4709         pdfSupportModule->bookmarksGB->setChecked(pdf.bookmarks);
4710         pdfSupportModule->bookmarksnumberedCB->setChecked(pdf.bookmarksnumbered);
4711         pdfSupportModule->bookmarksopenGB->setChecked(pdf.bookmarksopen);
4712
4713         pdfSupportModule->bookmarksopenlevelSB->setValue(pdf.bookmarksopenlevel);
4714         pdfSupportModule->bookmarksopenlevelSB->setEnabled(pdf.bookmarksopen);
4715         pdfSupportModule->bookmarksopenlevelLA->setEnabled(pdf.bookmarksopen);
4716
4717         pdfSupportModule->breaklinksCB->setChecked(pdf.breaklinks);
4718         pdfSupportModule->pdfborderCB->setChecked(pdf.pdfborder);
4719         pdfSupportModule->pdfusetitleCB->setChecked(pdf.pdfusetitle);
4720         pdfSupportModule->colorlinksCB->setChecked(pdf.colorlinks);
4721
4722         nn = findToken(backref_opts, pdf.backref);
4723         if (nn >= 0)
4724                 pdfSupportModule->backrefCO->setCurrentIndex(nn);
4725
4726         pdfSupportModule->fullscreenCB->setChecked
4727                 (pdf.pagemode == pdf.pagemode_fullscreen);
4728
4729         pdfSupportModule->optionsTE->setPlainText(
4730                 toqstr(pdf.quoted_options));
4731
4732         pdfSupportModule->metadataTE->setPlainText(
4733                 toqstr(rtrim(bp_.document_metadata, "\n")));
4734
4735         // change tracking
4736         changesModule->trackChangesCB->setChecked(bp_.track_changes);
4737         changesModule->outputChangesCB->setChecked(bp_.output_changes);
4738         changesModule->changeBarsCB->setChecked(bp_.change_bars);
4739         changesModule->changeBarsCB->setEnabled(bp_.output_changes);
4740
4741         // Make sure that the bc is in the INITIAL state
4742         if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
4743                 bc().restore();
4744
4745         // clear changed branches cache
4746         changedBranches_.clear();
4747
4748         // re-initiate module filter
4749         if (!filter_->text().isEmpty())
4750                 moduleFilterPressed();
4751
4752         // reset trackers
4753         nonModuleChanged_ = false;
4754         shellescapeChanged_ = false;
4755 }
4756
4757
4758 void GuiDocument::saveDocDefault()
4759 {
4760         // we have to apply the params first
4761         applyView();
4762         saveAsDefault();
4763 }
4764
4765
4766 void GuiDocument::updateAvailableModules()
4767 {
4768         modules_av_model_.clear();
4769         list<modInfoStruct> modInfoList = getModuleInfo();
4770         // Sort names according to the locale
4771         modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
4772                         return 0 < b.name.localeAwareCompare(a.name);
4773                 });
4774         QIcon user_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-user")
4775                                : getPixmap("images/", "lyxfiles-user", "svgz,png"));
4776         QIcon system_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-system")
4777                                  : getPixmap("images/", "lyxfiles-system", "svgz,png"));
4778         int i = 0;
4779         QFont catfont;
4780         catfont.setBold(true);
4781         QBrush unavbrush;
4782         unavbrush.setColor(Qt::gray);
4783         for (modInfoStruct const & m : modInfoList) {
4784                 QStandardItem * item = new QStandardItem();
4785                 QStandardItem * catItem;
4786                 QString const catname = m.category;
4787                 QList<QStandardItem *> fcats = modules_av_model_.findItems(catname, Qt::MatchExactly);
4788                 if (!fcats.empty())
4789                         catItem = fcats.first();
4790                 else {
4791                         catItem = new QStandardItem();
4792                         catItem->setText(catname);
4793                         catItem->setFont(catfont);
4794                         modules_av_model_.insertRow(i, catItem);
4795                         ++i;
4796                 }
4797                 item->setEditable(false);
4798                 catItem->setEditable(false);
4799                 item->setData(m.name, Qt::DisplayRole);
4800                 if (m.missingreqs)
4801                         item->setForeground(unavbrush);
4802                 item->setData(toqstr(m.id), Qt::UserRole);
4803                 item->setData(m.description, Qt::ToolTipRole);
4804                 if (m.local)
4805                         item->setIcon(user_icon);
4806                 else
4807                         item->setIcon(system_icon);
4808                 catItem->appendRow(item);
4809         }
4810         modules_av_model_.sort(0);
4811 }
4812
4813
4814 void GuiDocument::updateSelectedModules()
4815 {
4816         modules_sel_model_.clear();
4817         list<modInfoStruct> const selModList = getSelectedModules();
4818         int i = 0;
4819         for (modInfoStruct const & m : selModList) {
4820                 modules_sel_model_.insertRow(i, m.name, m.id, m.description);
4821                 ++i;
4822         }
4823 }
4824
4825
4826 void GuiDocument::updateIncludeonlyDisplay()
4827 {
4828         if (includeonlys_.empty()) {
4829                 masterChildModule->includeallRB->setChecked(true);
4830                 masterChildModule->childrenTW->setEnabled(false);
4831                 masterChildModule->maintainGB->setEnabled(false);
4832         } else {
4833                 masterChildModule->includeonlyRB->setChecked(true);
4834                 masterChildModule->childrenTW->setEnabled(true);
4835                 masterChildModule->maintainGB->setEnabled(true);
4836         }
4837 }
4838
4839
4840 void GuiDocument::updateIncludeonlys(bool const cleanup)
4841 {
4842         masterChildModule->childrenTW->clear();
4843         QString const no = qt_("No");
4844         QString const yes = qt_("Yes");
4845
4846         ListOfBuffers children = buffer().getChildren();
4847         ListOfBuffers::const_iterator it  = children.begin();
4848         ListOfBuffers::const_iterator end = children.end();
4849         bool has_unincluded = false;
4850         bool all_unincluded = true;
4851         for (; it != end; ++it) {
4852                 QTreeWidgetItem * item = new QTreeWidgetItem(masterChildModule->childrenTW);
4853                 // FIXME Unicode
4854                 string const name =
4855                         to_utf8(makeRelPath(from_utf8((*it)->fileName().absFileName()),
4856                                                         from_utf8(buffer().filePath())));
4857                 item->setText(0, toqstr(name));
4858                 item->setText(1, isChildIncluded(name) ? yes : no);
4859                 if (!isChildIncluded(name))
4860                         has_unincluded = true;
4861                 else
4862                         all_unincluded = false;
4863         }
4864         // Both if all children are included and if none is included
4865         // is equal to "include all" (i.e., omit \includeonly).
4866         if (cleanup && (!has_unincluded || all_unincluded))
4867                 includeonlys_.clear();
4868 }
4869
4870
4871 bool GuiDocument::isBiblatex() const
4872 {
4873         QString const engine =
4874                 biblioModule->citeEngineCO->itemData(
4875                                 biblioModule->citeEngineCO->currentIndex()).toString();
4876
4877         // this can happen if the cite engine is unknown, which can happen
4878         // if one is using a file that came from someone else, etc. in that
4879         // case, we crash if we proceed.
4880         if (engine.isEmpty())
4881             return false;
4882
4883         return theCiteEnginesList[fromqstr(engine)]->getCiteFramework() == "biblatex";
4884 }
4885
4886
4887 void GuiDocument::updateDefaultBiblio(string const & style,
4888                                       string const & which)
4889 {
4890         QString const bibstyle = toqstr(style);
4891         biblioModule->defaultBiblioCO->clear();
4892
4893         int item_nr = -1;
4894
4895         if (isBiblatex()) {
4896                 if (which != "cbx") {
4897                         // First the bbx styles
4898                         biblioModule->biblatexBbxCO->clear();
4899                         QStringList str = texFileList("bbxFiles.lst");
4900                         // test whether we have a valid list, otherwise run rescan
4901                         if (str.isEmpty()) {
4902                                 rescanTexStyles("bbx");
4903                                 str = texFileList("bbxFiles.lst");
4904                         }
4905                         for (int i = 0; i != str.size(); ++i)
4906                                 str[i] = onlyFileName(str[i]);
4907                         // sort on filename only (no path)
4908                         str.sort();
4909
4910                         for (int i = 0; i != str.count(); ++i) {
4911                                 QString item = changeExtension(str[i], "");
4912                                 if (item == bibstyle)
4913                                         item_nr = i;
4914                                 biblioModule->biblatexBbxCO->addItem(item);
4915                         }
4916
4917                         if (item_nr == -1 && !bibstyle.isEmpty()) {
4918                                 biblioModule->biblatexBbxCO->addItem(bibstyle);
4919                                 item_nr = biblioModule->biblatexBbxCO->count() - 1;
4920                         }
4921
4922                         if (item_nr != -1)
4923                                 biblioModule->biblatexBbxCO->setCurrentIndex(item_nr);
4924                         else
4925                                 biblioModule->biblatexBbxCO->clearEditText();
4926                 }
4927
4928                 if (which != "bbx") {
4929                         // now the cbx styles
4930                         biblioModule->biblatexCbxCO->clear();
4931                         QStringList str = texFileList("cbxFiles.lst");
4932                         // test whether we have a valid list, otherwise run rescan
4933                         if (str.isEmpty()) {
4934                                 rescanTexStyles("cbx");
4935                                 str = texFileList("cbxFiles.lst");
4936                         }
4937                         for (int i = 0; i != str.size(); ++i)
4938                                 str[i] = onlyFileName(str[i]);
4939                         // sort on filename only (no path)
4940                         str.sort();
4941
4942                         for (int i = 0; i != str.count(); ++i) {
4943                                 QString item = changeExtension(str[i], "");
4944                                 if (item == bibstyle)
4945                                         item_nr = i;
4946                                 biblioModule->biblatexCbxCO->addItem(item);
4947                         }
4948
4949                         if (item_nr == -1 && !bibstyle.isEmpty()) {
4950                                 biblioModule->biblatexCbxCO->addItem(bibstyle);
4951                                 item_nr = biblioModule->biblatexCbxCO->count() - 1;
4952                         }
4953
4954                         if (item_nr != -1)
4955                                 biblioModule->biblatexCbxCO->setCurrentIndex(item_nr);
4956                         else
4957                                 biblioModule->biblatexCbxCO->clearEditText();
4958                 }
4959         } else {// BibTeX
4960                 biblioModule->biblatexBbxCO->clear();
4961                 biblioModule->biblatexCbxCO->clear();
4962                 QStringList str = texFileList("bstFiles.lst");
4963                 // test whether we have a valid list, otherwise run rescan
4964                 if (str.isEmpty()) {
4965                         rescanTexStyles("bst");
4966                         str = texFileList("bstFiles.lst");
4967                 }
4968                 for (int i = 0; i != str.size(); ++i)
4969                         str[i] = onlyFileName(str[i]);
4970                 // sort on filename only (no path)
4971                 str.sort();
4972
4973                 for (int i = 0; i != str.count(); ++i) {
4974                         QString item = changeExtension(str[i], "");
4975                         if (item == bibstyle)
4976                                 item_nr = i;
4977                         biblioModule->defaultBiblioCO->addItem(item);
4978                 }
4979
4980                 if (item_nr == -1 && !bibstyle.isEmpty()) {
4981                         biblioModule->defaultBiblioCO->addItem(bibstyle);
4982                         item_nr = biblioModule->defaultBiblioCO->count() - 1;
4983                 }
4984
4985                 if (item_nr != -1)
4986                         biblioModule->defaultBiblioCO->setCurrentIndex(item_nr);
4987                 else
4988                         biblioModule->defaultBiblioCO->clearEditText();
4989         }
4990
4991         updateResetDefaultBiblio();
4992 }
4993
4994
4995 void GuiDocument::updateResetDefaultBiblio()
4996 {
4997         QString const engine =
4998                 biblioModule->citeEngineCO->itemData(
4999                                 biblioModule->citeEngineCO->currentIndex()).toString();
5000         CiteEngineType const cet =
5001                 CiteEngineType(biblioModule->citeStyleCO->itemData(
5002                                                           biblioModule->citeStyleCO->currentIndex()).toInt());
5003
5004         string const defbib = theCiteEnginesList[fromqstr(engine)]->getDefaultBiblio(cet);
5005         if (isBiblatex()) {
5006                 QString const bbx = biblioModule->biblatexBbxCO->currentText();
5007                 QString const cbx = biblioModule->biblatexCbxCO->currentText();
5008                 biblioModule->resetCbxPB->setEnabled(defbib != fromqstr(cbx));
5009                 biblioModule->resetBbxPB->setEnabled(defbib != fromqstr(bbx));
5010                 biblioModule->matchBbxPB->setEnabled(bbx != cbx && !cbx.isEmpty()
5011                         && biblioModule->biblatexBbxCO->findText(cbx) != -1);
5012         } else
5013                 biblioModule->resetDefaultBiblioPB->setEnabled(
5014                         defbib != fromqstr(biblioModule->defaultBiblioCO->currentText()));
5015 }
5016
5017
5018 void GuiDocument::matchBiblatexStyles()
5019 {
5020         updateDefaultBiblio(fromqstr(biblioModule->biblatexCbxCO->currentText()), "bbx");
5021         biblioChanged();
5022 }
5023
5024
5025 void GuiDocument::updateContents()
5026 {
5027         // Nothing to do here as the document settings is not cursor dependent.
5028         return;
5029 }
5030
5031
5032 void GuiDocument::useClassDefaults()
5033 {
5034         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
5035                 int const ret = Alert::prompt(_("Unapplied changes"),
5036                                 _("Some changes in the dialog were not yet applied.\n"
5037                                   "If you do not apply now, they will be lost after this action."),
5038                                 1, 1, _("&Apply"), _("&Dismiss"));
5039                 if (ret == 0)
5040                         applyView();
5041         }
5042
5043         int idx = latexModule->classCO->currentIndex();
5044         string const classname = fromqstr(latexModule->classCO->getData(idx));
5045         if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
5046                 Alert::error(_("Error"), _("Unable to set document class."));
5047                 return;
5048         }
5049         bp_.useClassDefaults();
5050         paramsToDialog();
5051         changed();
5052 }
5053
5054
5055 void GuiDocument::setLayoutComboByIDString(string const & idString)
5056 {
5057         if (!latexModule->classCO->set(toqstr(idString)))
5058                 Alert::warning(_("Can't set layout!"),
5059                         bformat(_("Unable to set layout for ID: %1$s"), from_utf8(idString)));
5060 }
5061
5062
5063 bool GuiDocument::isValid()
5064 {
5065         bool const listings_valid = validateListingsParameters().isEmpty();
5066         bool const local_layout_valid = !localLayout->editing();
5067         bool const preamble_valid = !preambleModule->editing();
5068
5069         docPS->markPanelValid(N_("Listings[[inset]]"), listings_valid);
5070         docPS->markPanelValid(N_("Local Layout"), local_layout_valid && localLayout->isValid());
5071         docPS->markPanelValid(N_("LaTeX Preamble"), preamble_valid);
5072         
5073         return listings_valid && local_layout_valid && preamble_valid;
5074 }
5075
5076
5077 char const * const GuiDocument::fontfamilies[5] = {
5078         "default", "rmdefault", "sfdefault", "ttdefault", ""
5079 };
5080
5081
5082 char const * GuiDocument::fontfamilies_gui[5] = {
5083         N_("Default"), N_("Roman"), N_("Sans Serif"), N_("Typewriter"), ""
5084 };
5085
5086
5087 bool GuiDocument::initialiseParams(string const &)
5088 {
5089         BufferView const * view = bufferview();
5090         if (!view) {
5091                 bp_ = BufferParams();
5092                 paramsToDialog();
5093                 return true;
5094         }
5095         prev_buffer_filename_ = view->buffer().absFileName();
5096         bp_ = view->buffer().params();
5097         loadModuleInfo();
5098         updateAvailableModules();
5099         //FIXME It'd be nice to make sure here that the selected
5100         //modules are consistent: That required modules are actually
5101         //selected, and that we don't have conflicts. If so, we could
5102         //at least pop up a warning.
5103         paramsToDialog();
5104         return true;
5105 }
5106
5107
5108 void GuiDocument::clearParams()
5109 {
5110         bp_ = BufferParams();
5111 }
5112
5113
5114 BufferId GuiDocument::id() const
5115 {
5116         BufferView const * const view = bufferview();
5117         return view? &view->buffer() : nullptr;
5118 }
5119
5120
5121 list<GuiDocument::modInfoStruct> const & GuiDocument::getModuleInfo()
5122 {
5123         return moduleNames_;
5124 }
5125
5126
5127 list<GuiDocument::modInfoStruct> const
5128 GuiDocument::makeModuleInfo(LayoutModuleList const & mods)
5129 {
5130         list<modInfoStruct> mInfo;
5131         for (string const & name : mods) {
5132                 modInfoStruct m;
5133                 LyXModule const * const mod = theModuleList[name];
5134                 if (mod)
5135                         m = modInfo(*mod);
5136                 else {
5137                         m.id = name;
5138                         m.name = toqstr(name + " (") + qt_("Not Found") + toqstr(")");
5139                         m.local = false;
5140                         m.missingreqs = true;
5141                 }
5142                 mInfo.push_back(m);
5143         }
5144         return mInfo;
5145 }
5146
5147
5148 list<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
5149 {
5150         return makeModuleInfo(params().getModules());
5151 }
5152
5153
5154 list<GuiDocument::modInfoStruct> const GuiDocument::getProvidedModules()
5155 {
5156         return makeModuleInfo(params().baseClass()->providedModules());
5157 }
5158
5159
5160 DocumentClass const & GuiDocument::documentClass() const
5161 {
5162         return bp_.documentClass();
5163 }
5164
5165
5166 static void dispatch_bufferparams(Dialog const & dialog,
5167         BufferParams const & bp, FuncCode lfun, Buffer const * buf)
5168 {
5169         ostringstream ss;
5170         ss << "\\begin_header\n";
5171         bp.writeFile(ss, buf);
5172         ss << "\\end_header\n";
5173         dialog.dispatch(FuncRequest(lfun, ss.str()));
5174 }
5175
5176
5177 void GuiDocument::dispatchParams()
5178 {
5179         // We need a non-const buffer object.
5180         Buffer & buf = const_cast<BufferView *>(bufferview())->buffer();
5181         // There may be several undo records; group them (bug #8998)
5182         // This handles undo groups automagically
5183         UndoGroupHelper ugh(&buf);
5184
5185         // This must come first so that a language change is correctly noticed
5186         setLanguage();
5187
5188         // We need to load the master before we formally update the params,
5189         // since otherwise we run updateBuffer, etc, before the child's master
5190         // has been set.
5191         if (!params().master.empty()) {
5192                 FileName const master_file = support::makeAbsPath(params().master,
5193                            support::onlyPath(buffer().absFileName()));
5194                 if (isLyXFileName(master_file.absFileName())) {
5195                         Buffer * master = checkAndLoadLyXFile(master_file, true);
5196                         if (master) {
5197                                 if (master->isChild(const_cast<Buffer *>(&buffer())))
5198                                         const_cast<Buffer &>(buffer()).setParent(master);
5199                                 else
5200                                         Alert::warning(_("Assigned master does not include this file"),
5201                                                 bformat(_("You must include this file in the document\n"
5202                                                           "'%1$s' in order to use the master document\n"
5203                                                           "feature."), from_utf8(params().master)));
5204                         } else
5205                                 Alert::warning(_("Could not load master"),
5206                                                 bformat(_("The master document '%1$s'\n"
5207                                                            "could not be loaded."),
5208                                                            from_utf8(params().master)));
5209                 }
5210         }
5211
5212         // Apply the BufferParams. Note that this will set the base class
5213         // and then update the buffer's layout.
5214         dispatch_bufferparams(*this, params(), LFUN_BUFFER_PARAMS_APPLY, &buffer());
5215
5216         // Generate the colours requested by each new branch.
5217         BranchList & branchlist = params().branchlist();
5218         if (!branchlist.empty()) {
5219                 BranchList::const_iterator it = branchlist.begin();
5220                 BranchList::const_iterator const end = branchlist.end();
5221                 for (; it != end; ++it) {
5222                         docstring const & current_branch = it->branch();
5223                         Branch const * branch = branchlist.find(current_branch);
5224                         string const bcolor = branch->color();
5225                         RGBColor rgbcol;
5226                         if (bcolor.size() == 7 && bcolor[0] == '#')
5227                                 rgbcol = lyx::rgbFromHexName(bcolor);
5228                         else
5229                                 guiApp->getRgbColor(lcolor.getFromLyXName(bcolor), rgbcol);
5230                         string const x11hexname = X11hexname(rgbcol);
5231                         // display the new color
5232                         docstring const str = current_branch + ' ' + from_ascii(x11hexname);
5233                         dispatch(FuncRequest(LFUN_SET_COLOR, str));
5234                 }
5235         }
5236         // rename branches in the document
5237         executeBranchRenaming();
5238         // and clear changed branches cache
5239         changedBranches_.clear();
5240
5241         // Generate the colours requested by indices.
5242         IndicesList & indiceslist = params().indiceslist();
5243         if (!indiceslist.empty()) {
5244                 IndicesList::const_iterator it = indiceslist.begin();
5245                 IndicesList::const_iterator const end = indiceslist.end();
5246                 for (; it != end; ++it) {
5247                         docstring const & current_index = it->shortcut();
5248                         Index const * index = indiceslist.findShortcut(current_index);
5249                         string const x11hexname = X11hexname(index->color());
5250                         // display the new color
5251                         docstring const str = current_index + ' ' + from_ascii(x11hexname);
5252                         dispatch(FuncRequest(LFUN_SET_COLOR, str));
5253                 }
5254         }
5255         // FIXME LFUN
5256         // If we used an LFUN, we would not need these two lines:
5257         BufferView * bv = const_cast<BufferView *>(bufferview());
5258         bv->processUpdateFlags(Update::Force | Update::FitCursor);
5259 }
5260
5261
5262 void GuiDocument::setLanguage() const
5263 {
5264         Language const * const newL = bp_.language;
5265         if (buffer().params().language == newL)
5266                 return;
5267
5268         string const & lang_name = newL->lang();
5269         dispatch(FuncRequest(LFUN_BUFFER_LANGUAGE, lang_name));
5270 }
5271
5272
5273 void GuiDocument::saveAsDefault() const
5274 {
5275         dispatch_bufferparams(*this, params(), LFUN_BUFFER_SAVE_AS_DEFAULT, &buffer());
5276 }
5277
5278
5279 bool GuiDocument::providesOSF(QString const & font) const
5280 {
5281         if (fontModule->osFontsCB->isChecked())
5282                 // FIXME: we should check if the fonts really
5283                 // have OSF support. But how?
5284                 return font != "default";
5285         return theLaTeXFonts().getLaTeXFont(
5286                                 qstring_to_ucs4(font)).providesOSF(ot1(),
5287                                                                    completeFontset(),
5288                                                                    noMathFont());
5289 }
5290
5291
5292 bool GuiDocument::providesSC(QString const & font) const
5293 {
5294         if (fontModule->osFontsCB->isChecked())
5295                 return false;
5296         return theLaTeXFonts().getLaTeXFont(
5297                                 qstring_to_ucs4(font)).providesSC(ot1(),
5298                                                                   completeFontset(),
5299                                                                   noMathFont());
5300 }
5301
5302
5303 bool GuiDocument::providesScale(QString const & font) const
5304 {
5305         if (fontModule->osFontsCB->isChecked())
5306                 return font != "default";
5307         return theLaTeXFonts().getLaTeXFont(
5308                                 qstring_to_ucs4(font)).providesScale(ot1(),
5309                                                                      completeFontset(),
5310                                                                      noMathFont());
5311 }
5312
5313
5314 bool GuiDocument::providesExtraOpts(QString const & font) const
5315 {
5316         if (fontModule->osFontsCB->isChecked())
5317                 return font != "default";
5318         return theLaTeXFonts().getLaTeXFont(
5319                                 qstring_to_ucs4(font)).providesMoreOptions(ot1(),
5320                                                                      completeFontset(),
5321                                                                      noMathFont());
5322 }
5323
5324
5325 bool GuiDocument::providesNoMath(QString const & font) const
5326 {
5327         if (fontModule->osFontsCB->isChecked())
5328                 return false;
5329         return theLaTeXFonts().getLaTeXFont(
5330                                 qstring_to_ucs4(font)).providesNoMath(ot1(),
5331                                                                       completeFontset());
5332 }
5333
5334
5335 bool GuiDocument::hasMonolithicExpertSet(QString const & font) const
5336 {
5337         if (fontModule->osFontsCB->isChecked())
5338                 return false;
5339         return theLaTeXFonts().getLaTeXFont(
5340                                 qstring_to_ucs4(font)).hasMonolithicExpertSet(ot1(),
5341                                                                               completeFontset(),
5342                                                                               noMathFont());
5343 }
5344
5345
5346 //static
5347 GuiDocument::modInfoStruct GuiDocument::modInfo(LyXModule const & mod)
5348 {
5349         // FIXME Unicode: docstrings would be better for these parameters but this
5350         // change requires a lot of others
5351         modInfoStruct m;
5352         m.id = mod.getID();
5353         QString const guiname = toqstr(translateIfPossible(from_utf8(mod.getName())));
5354         m.missingreqs = !isModuleAvailable(mod.getID());
5355         if (m.missingreqs) {
5356                 m.name = qt_("%1 (missing req.)").arg(guiname);
5357         } else
5358                 m.name = guiname;
5359         m.category = mod.category().empty() ? qt_("Miscellaneous")
5360                                             : toqstr(translateIfPossible(from_utf8(mod.category())));
5361         QString desc = toqstr(translateIfPossible(from_utf8(mod.getDescription())));
5362         // Find the first sentence of the description
5363         QTextBoundaryFinder bf(QTextBoundaryFinder::Sentence, desc);
5364         int pos = bf.toNextBoundary();
5365         if (pos > 0)
5366                 desc.truncate(pos);
5367         m.local = mod.isLocal();
5368         QString const mtype = m.local ? qt_("personal module") : qt_("distributed module");
5369         QString modulename = qt_("<b>Module name:</b> <i>%1</i> (%2)").arg(toqstr(m.id)).arg(mtype);
5370         // Tooltip is the desc followed by the module name and the type
5371         m.description = QString("%1%2")
5372                 .arg(desc.isEmpty() ? QString() : QString("<p>%1</p>").arg(desc),
5373                      modulename);
5374         if (m.missingreqs)
5375                 m.description += QString("<p>%1</p>").arg(qt_("<b>Note:</b> Some requirements for this module are missing!"));
5376         return m;
5377 }
5378
5379
5380 void GuiDocument::loadModuleInfo()
5381 {
5382         moduleNames_.clear();
5383         for (LyXModule const & mod : theModuleList)
5384                 moduleNames_.push_back(modInfo(mod));
5385 }
5386
5387
5388 void GuiDocument::updateUnknownBranches()
5389 {
5390         if (!bufferview())
5391                 return;
5392         list<docstring> used_branches;
5393         buffer().getUsedBranches(used_branches);
5394         list<docstring>::const_iterator it = used_branches.begin();
5395         QStringList unknown_branches;
5396         for (; it != used_branches.end() ; ++it) {
5397                 if (!buffer().params().branchlist().find(*it))
5398                         unknown_branches.append(toqstr(*it));
5399         }
5400         branchesModule->setUnknownBranches(unknown_branches);
5401 }
5402
5403
5404 void GuiDocument::branchesRename(docstring const & oldname, docstring const & newname)
5405 {
5406         map<docstring, docstring>::iterator it = changedBranches_.begin();
5407         for (; it != changedBranches_.end() ; ++it) {
5408                 if (it->second == oldname) {
5409                         // branch has already been renamed
5410                         it->second = newname;
5411                         return;
5412                 }
5413         }
5414         // store new name
5415         changedBranches_[oldname] = newname;
5416 }
5417
5418
5419 void GuiDocument::executeBranchRenaming() const
5420 {
5421         map<docstring, docstring>::const_iterator it = changedBranches_.begin();
5422         for (; it != changedBranches_.end() ; ++it) {
5423                 docstring const arg = '"' + it->first + '"' + " " + '"' + it->second + '"';
5424                 dispatch(FuncRequest(LFUN_BRANCHES_RENAME, arg));
5425         }
5426 }
5427
5428
5429 void GuiDocument::allPackagesAuto()
5430 {
5431         allPackages(1);
5432 }
5433
5434
5435 void GuiDocument::allPackagesAlways()
5436 {
5437         allPackages(2);
5438 }
5439
5440
5441 void GuiDocument::allPackagesNot()
5442 {
5443         allPackages(3);
5444 }
5445
5446
5447 void GuiDocument::allPackages(int col)
5448 {
5449         for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) {
5450                 QRadioButton * rb =
5451                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col)->layout()->itemAt(0)->widget();
5452                 rb->setChecked(true);
5453         }
5454 }
5455
5456
5457 void GuiDocument::linenoToggled(bool on)
5458 {
5459         numberingModule->linenoLE->setEnabled(on);
5460         numberingModule->linenoLA->setEnabled(on);
5461 }
5462
5463
5464 void GuiDocument::outputChangesToggled(bool on)
5465 {
5466         changesModule->changeBarsCB->setEnabled(on);
5467         change_adaptor();
5468 }
5469
5470 void GuiDocument::setOutputSync(bool on)
5471 {
5472         outputModule->synccustomCB->setEnabled(on);
5473         outputModule->synccustomLA->setEnabled(on);
5474         change_adaptor();
5475 }
5476
5477
5478 bool GuiDocument::eventFilter(QObject * sender, QEvent * event)
5479 {
5480         if (event->type() == QEvent::ApplicationPaletteChange) {
5481                 // mode switch: colors need to be updated
5482                 // and the highlighting redone
5483                 if (pdf_options_highlighter_) {
5484                         pdf_options_highlighter_->setupColors();
5485                         pdf_options_highlighter_->rehighlight();
5486                 }
5487                 if (pdf_metadata_highlighter_) {
5488                         pdf_metadata_highlighter_->setupColors();
5489                         pdf_metadata_highlighter_->rehighlight();
5490                 }
5491         }
5492         return QWidget::eventFilter(sender, event);
5493 }
5494
5495
5496 } // namespace frontend
5497 } // namespace lyx
5498
5499 #include "moc_GuiDocument.cpp"