]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiDocument.cpp
Fix readability
[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::onBufferViewChanged()
1853 {
1854         if (switchback_) {
1855                 // We are just switching back. Nothing to do.
1856                 switchback_ = false;
1857                 return;
1858         }
1859         BufferView const * view = bufferview();
1860         string const new_filename = view ? view->buffer().absFileName() : string();
1861         // If we switched buffer really and the previous file name is different to
1862         // the current one, we ask on unapplied changes (#9369)
1863         // FIXME: This is more complicated than it should be. Why do we need these to cycles?
1864         // And ideally, we should propose to apply without having to switch back
1865         // (e.g., via a LFUN_BUFFER_PARAMS_APPLY_OTHER)
1866         if (!prev_buffer_filename_.empty() && prev_buffer_filename_ != new_filename
1867             && buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
1868                 // Only ask if we haven't yet in this cycle
1869                 int const ret = prompted_ ? 3 : Alert::prompt(_("Unapplied changes"),
1870                                 _("Some changes in the previous document were not yet applied.\n"
1871                                 "Do you want to switch back and apply them?"),
1872                                 1, 1, _("Yes, &Switch Back"), _("No, &Dismiss Changes"));
1873                 if (ret == 0) {
1874                         // Switch to previous buffer view and apply
1875                         switchback_ = true;
1876                         // Record that we have asked.
1877                         prompted_ = true;
1878                         lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH, prev_buffer_filename_));
1879                         return;
1880                 } else if (ret == 3) {
1881                         // We are in the second cycle. Set back.
1882                         prompted_ = false;
1883                         return;
1884                 }
1885         }
1886
1887         if (isVisibleView())
1888                 initialiseParams("");
1889 }
1890
1891
1892 void GuiDocument::saveDefaultClicked()
1893 {
1894         saveDocDefault();
1895 }
1896
1897
1898 void GuiDocument::useDefaultsClicked()
1899 {
1900         useClassDefaults();
1901 }
1902
1903
1904 void GuiDocument::change_adaptor()
1905 {
1906         nonModuleChanged_ = true;
1907         changed();
1908 }
1909
1910
1911 void GuiDocument::shellescapeChanged()
1912 {
1913         shellescapeChanged_ = true;
1914         changed();
1915 }
1916
1917 void GuiDocument::bookmarksopenChanged(bool state)
1918 {
1919         pdfSupportModule->bookmarksopenlevelSB->setEnabled(state);
1920         pdfSupportModule->bookmarksopenlevelLA->setEnabled(state);
1921 }
1922
1923
1924 void GuiDocument::changeTrackingChanged(bool state)
1925 {
1926         // This is triggered if the CT state is toggled outside
1927         // the document dialog (e.g., menu).
1928         changesModule->trackChangesCB->setChecked(state);
1929 }
1930
1931
1932 void GuiDocument::slotApply()
1933 {
1934         bool only_shellescape_changed = !nonModuleChanged_ && !modulesChanged_;
1935         bool wasclean = buffer().isClean();
1936         GuiDialog::slotApply();
1937         if (wasclean && only_shellescape_changed)
1938                 buffer().markClean();
1939         modulesChanged_ = false;
1940         isValid();
1941 }
1942
1943
1944 void GuiDocument::slotOK()
1945 {
1946         bool only_shellescape_changed = !nonModuleChanged_ && !modulesChanged_;
1947         bool wasclean = buffer().isClean();
1948         GuiDialog::slotOK();
1949         if (wasclean && only_shellescape_changed)
1950                 buffer().markClean();
1951         modulesChanged_ = false;
1952 }
1953
1954
1955 void GuiDocument::slotButtonBox(QAbstractButton * button)
1956 {
1957         switch (buttonBox->standardButton(button)) {
1958         case QDialogButtonBox::Ok:
1959                 slotOK();
1960                 break;
1961         case QDialogButtonBox::Apply:
1962                 slotApply();
1963                 break;
1964         case QDialogButtonBox::Cancel:
1965                 slotClose();
1966                 break;
1967         case QDialogButtonBox::Reset:
1968         case QDialogButtonBox::RestoreDefaults:
1969                 slotRestore();
1970                 break;
1971         default:
1972                 break;
1973         }
1974 }
1975
1976
1977 void GuiDocument::filterModules(QString const & str)
1978 {
1979         updateAvailableModules();
1980         if (str.isEmpty())
1981                 return;
1982
1983         modules_av_model_.clear();
1984         list<modInfoStruct> modInfoList = getModuleInfo();
1985         // Sort names according to the locale
1986         modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
1987                         return 0 < b.name.localeAwareCompare(a.name);
1988                 });
1989
1990         QIcon user_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-user")
1991                                : getPixmap("images/", "lyxfiles-user", "svgz,png"));
1992         QIcon system_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-system")
1993                                  : getPixmap("images/", "lyxfiles-system", "svgz,png"));
1994
1995         int i = 0;
1996         for (modInfoStruct const & m : modInfoList) {
1997                 if (m.name.contains(str, Qt::CaseInsensitive) || contains(m.id, fromqstr(str))) {
1998                         QStandardItem * item = new QStandardItem();
1999                         item->setData(m.name, Qt::DisplayRole);
2000                         item->setData(toqstr(m.id), Qt::UserRole);
2001                         item->setData(m.description, Qt::ToolTipRole);
2002                         item->setEditable(false);
2003                         if (m.local)
2004                                 item->setIcon(user_icon);
2005                         else
2006                                 item->setIcon(system_icon);
2007                         modules_av_model_.insertRow(i, item);
2008                         ++i;
2009                 }
2010         }
2011 }
2012
2013
2014 void GuiDocument::moduleFilterChanged(const QString & text)
2015 {
2016         if (!text.isEmpty()) {
2017                 filterModules(filter_->text());
2018                 return;
2019         }
2020         filterModules(filter_->text());
2021         filter_->setFocus();
2022 }
2023
2024
2025 void GuiDocument::moduleFilterPressed()
2026 {
2027         filterModules(filter_->text());
2028 }
2029
2030
2031 void GuiDocument::resetModuleFilter()
2032 {
2033         filter_->setText(QString());
2034         filterModules(filter_->text());
2035 }
2036
2037
2038 void GuiDocument::includeonlyClicked(QTreeWidgetItem * item, int)
2039 {
2040         if (item == nullptr)
2041                 return;
2042
2043         string child = fromqstr(item->text(0));
2044
2045         if (child.empty())
2046                 return;
2047
2048         if (isChildIncluded(child))
2049                 includeonlys_.remove(child);
2050         else
2051                 includeonlys_.push_back(child);
2052
2053         updateIncludeonlys(false);
2054         change_adaptor();
2055 }
2056
2057
2058 QString GuiDocument::validateListingsParameters()
2059 {
2060         if (listingsModule->bypassCB->isChecked())
2061                 return QString();
2062         string const package =
2063             lst_packages[listingsModule->packageCO->currentIndex()];
2064         string params = fromqstr(listingsModule->listingsED->toPlainText());
2065         InsetListingsParams lstparams(params);
2066         lstparams.setMinted(package == "Minted");
2067         return toqstr(lstparams.validate());
2068 }
2069
2070
2071 void GuiDocument::setListingsMessage()
2072 {
2073         // FIXME THREAD
2074         static bool isOK = true;
2075         QString msg = validateListingsParameters();
2076         if (msg.isEmpty()) {
2077                 listingsModule->listingsTB->setTextColor(QColor());
2078                 if (isOK)
2079                         return;
2080                 isOK = true;
2081                 listingsModule->listingsTB->setPlainText(
2082                         qt_("Input listings parameters below. "
2083                             "Enter ? for a list of parameters."));
2084         } else {
2085                 isOK = false;
2086                 listingsModule->listingsTB->setTextColor(QColor(255, 0, 0));
2087                 listingsModule->listingsTB->setPlainText(msg);
2088         }
2089 }
2090
2091
2092 void GuiDocument::listingsPackageChanged(int index)
2093 {
2094         string const package = lst_packages[index];
2095         if (package == "Minted" && lyxrc.pygmentize_command.empty()) {
2096                 Alert::warning(_("Pygments driver command not found!"),
2097                     _("The driver command necessary to use the minted package\n"
2098                       "(pygmentize) has not been found. Make sure you have\n"
2099                       "the python-pygments module installed or, if the driver\n"
2100                       "is named differently, to add the following line to the\n"
2101                       "document preamble:\n\n"
2102                       "\\AtBeginDocument{\\renewcommand{\\MintedPygmentize}{driver}}\n\n"
2103                       "where 'driver' is name of the driver command."));
2104         }
2105 }
2106
2107
2108 void GuiDocument::setLSpacing(int item)
2109 {
2110         textLayoutModule->lspacingLE->setEnabled(item == 3);
2111 }
2112
2113
2114 void GuiDocument::setIndent(int item)
2115 {
2116         bool const enable = (textLayoutModule->indentCO->itemData(item) == "custom");
2117         textLayoutModule->indentLE->setEnabled(enable);
2118         textLayoutModule->indentLengthCO->setEnabled(enable);
2119         textLayoutModule->skipLE->setEnabled(false);
2120         textLayoutModule->skipLengthCO->setEnabled(false);
2121         // needed to catch empty custom case
2122         bc().refresh();
2123         isValid();
2124 }
2125
2126
2127 void GuiDocument::enableIndent(bool indent)
2128 {
2129         textLayoutModule->skipLE->setEnabled(!indent);
2130         textLayoutModule->skipLengthCO->setEnabled(!indent);
2131         if (indent)
2132                 setIndent(textLayoutModule->indentCO->currentIndex());
2133 }
2134
2135
2136 void GuiDocument::setSkip(int item)
2137 {
2138         VSpace::VSpaceKind kind =
2139                 VSpace::VSpaceKind(textLayoutModule->skipCO->itemData(item).toInt());
2140         bool const enable = (kind == VSpace::LENGTH);
2141         textLayoutModule->skipLE->setEnabled(enable);
2142         textLayoutModule->skipLengthCO->setEnabled(enable);
2143         // needed to catch empty custom case
2144         bc().refresh();
2145         isValid();
2146 }
2147
2148
2149 void GuiDocument::enableSkip(bool skip)
2150 {
2151         textLayoutModule->indentLE->setEnabled(!skip);
2152         textLayoutModule->indentLengthCO->setEnabled(!skip);
2153         if (skip)
2154                 setSkip(textLayoutModule->skipCO->currentIndex());
2155 }
2156
2157 void GuiDocument::allowMathIndent() {
2158         // only disable when not checked, checked does not always allow enabling
2159         if (!mathsModule->MathIndentCB->isChecked()) {
2160                 mathsModule->MathIndentLE->setEnabled(false);
2161                 mathsModule->MathIndentLengthCO->setEnabled(false);
2162         }
2163         if (mathsModule->MathIndentCB->isChecked()
2164             && mathsModule->MathIndentCO->itemData(mathsModule->MathIndentCO->currentIndex()) == "custom") {
2165                         mathsModule->MathIndentLE->setEnabled(true);
2166                         mathsModule->MathIndentLengthCO->setEnabled(true);
2167         }
2168         isValid();
2169 }
2170
2171 void GuiDocument::enableMathIndent(int item)
2172 {
2173         bool const enable = (item == 1);
2174         mathsModule->MathIndentLE->setEnabled(enable);
2175         mathsModule->MathIndentLengthCO->setEnabled(enable);
2176         // needed to catch empty custom case
2177         bc().refresh();
2178         isValid();
2179 }
2180
2181
2182 void GuiDocument::setMargins()
2183 {
2184         bool const extern_geometry =
2185                 documentClass().provides("geometry");
2186         marginsModule->marginCB->setEnabled(!extern_geometry);
2187         if (extern_geometry) {
2188                 marginsModule->marginCB->setChecked(false);
2189                 setCustomMargins(true);
2190         } else {
2191                 marginsModule->marginCB->setChecked(!bp_.use_geometry);
2192                 setCustomMargins(!bp_.use_geometry);
2193         }
2194 }
2195
2196
2197 void GuiDocument::papersizeChanged(int paper_size)
2198 {
2199         setCustomPapersize(paper_size == 1);
2200 }
2201
2202
2203 void GuiDocument::setCustomPapersize(bool custom)
2204 {
2205         pageLayoutModule->paperwidthL->setEnabled(custom);
2206         pageLayoutModule->paperwidthLE->setEnabled(custom);
2207         pageLayoutModule->paperwidthUnitCO->setEnabled(custom);
2208         pageLayoutModule->paperheightL->setEnabled(custom);
2209         pageLayoutModule->paperheightLE->setEnabled(custom);
2210         pageLayoutModule->paperheightLE->setFocus();
2211         pageLayoutModule->paperheightUnitCO->setEnabled(custom);
2212 }
2213
2214
2215 void GuiDocument::setColSep()
2216 {
2217         setCustomMargins(marginsModule->marginCB->checkState() == Qt::Checked);
2218 }
2219
2220
2221 void GuiDocument::setCustomMargins(bool cb_checked)
2222 {
2223         bool const custom_margins = !cb_checked;
2224         if (custom_margins) {
2225                 Length::UNIT const default_unit = Length::defaultUnit();
2226                 // fill with chached values
2227                 lengthToWidgets(marginsModule->topLE,
2228                                 marginsModule->topUnit,
2229                                 tmp_topmargin_, default_unit);
2230                 lengthToWidgets(marginsModule->bottomLE,
2231                                 marginsModule->bottomUnit,
2232                                 tmp_bottommargin_, default_unit);
2233                 lengthToWidgets(marginsModule->innerLE,
2234                                 marginsModule->innerUnit,
2235                                 tmp_leftmargin_, default_unit);
2236                 lengthToWidgets(marginsModule->outerLE,
2237                                 marginsModule->outerUnit,
2238                                 tmp_rightmargin_, default_unit);
2239                 lengthToWidgets(marginsModule->headheightLE,
2240                                 marginsModule->headheightUnit,
2241                                 tmp_headheight_, default_unit);
2242                 lengthToWidgets(marginsModule->headsepLE,
2243                                 marginsModule->headsepUnit,
2244                                 tmp_headsep_, default_unit);
2245                 lengthToWidgets(marginsModule->footskipLE,
2246                                 marginsModule->footskipUnit,
2247                                 tmp_footskip_, default_unit);
2248                 lengthToWidgets(marginsModule->columnsepLE,
2249                                 marginsModule->columnsepUnit,
2250                                 tmp_columnsep_, default_unit);
2251         } else { // default margins
2252                 // Cache current values
2253                 tmp_leftmargin_ = widgetsToLength(marginsModule->innerLE,
2254                                                   marginsModule->innerUnit);
2255                 tmp_topmargin_ = widgetsToLength(marginsModule->topLE,
2256                                                  marginsModule->topUnit);
2257                 tmp_rightmargin_ = widgetsToLength(marginsModule->outerLE,
2258                                                    marginsModule->outerUnit);
2259                 tmp_bottommargin_ = widgetsToLength(marginsModule->bottomLE,
2260                                                     marginsModule->bottomUnit);
2261                 tmp_headheight_ = widgetsToLength(marginsModule->headheightLE,
2262                                                   marginsModule->headheightUnit);
2263                 tmp_headsep_ = widgetsToLength(marginsModule->headsepLE,
2264                                                marginsModule->headsepUnit);
2265                 tmp_footskip_ = widgetsToLength(marginsModule->footskipLE,
2266                                                 marginsModule->footskipUnit);
2267                 tmp_columnsep_ = widgetsToLength(marginsModule->columnsepLE,
2268                                                  marginsModule->columnsepUnit);
2269                 // clear widgets
2270                 marginsModule->topLE->clear();
2271                 marginsModule->bottomLE->clear();
2272                 marginsModule->innerLE->clear();
2273                 marginsModule->outerLE->clear();
2274                 marginsModule->headheightLE->clear();
2275                 marginsModule->headsepLE->clear();
2276                 marginsModule->footskipLE->clear();
2277                 marginsModule->columnsepLE->clear();
2278         }
2279
2280         marginsModule->topL->setEnabled(custom_margins);
2281         marginsModule->topLE->setEnabled(custom_margins);
2282         marginsModule->topUnit->setEnabled(custom_margins);
2283
2284         marginsModule->bottomL->setEnabled(custom_margins);
2285         marginsModule->bottomLE->setEnabled(custom_margins);
2286         marginsModule->bottomUnit->setEnabled(custom_margins);
2287
2288         marginsModule->innerL->setEnabled(custom_margins);
2289         marginsModule->innerLE->setEnabled(custom_margins);
2290         marginsModule->innerUnit->setEnabled(custom_margins);
2291
2292         marginsModule->outerL->setEnabled(custom_margins);
2293         marginsModule->outerLE->setEnabled(custom_margins);
2294         marginsModule->outerUnit->setEnabled(custom_margins);
2295
2296         marginsModule->headheightL->setEnabled(custom_margins);
2297         marginsModule->headheightLE->setEnabled(custom_margins);
2298         marginsModule->headheightUnit->setEnabled(custom_margins);
2299
2300         marginsModule->headsepL->setEnabled(custom_margins);
2301         marginsModule->headsepLE->setEnabled(custom_margins);
2302         marginsModule->headsepUnit->setEnabled(custom_margins);
2303
2304         marginsModule->footskipL->setEnabled(custom_margins);
2305         marginsModule->footskipLE->setEnabled(custom_margins);
2306         marginsModule->footskipUnit->setEnabled(custom_margins);
2307
2308         bool const enableColSep = custom_margins &&
2309                         textLayoutModule->twoColumnCB->isChecked();
2310         marginsModule->columnsepL->setEnabled(enableColSep);
2311         marginsModule->columnsepLE->setEnabled(enableColSep);
2312         marginsModule->columnsepUnit->setEnabled(enableColSep);
2313
2314         // set some placeholder text that hint on defaults
2315         QString const placeholder = marginsModule->marginCB->isChecked() ?
2316                 qt_("Default margins") : qt_("Package defaults");
2317         // set tooltip depending on gemoetry state
2318         QString const tooltip = marginsModule->marginCB->isChecked() ?
2319                 qt_("If no value is given, the defaults as set by the class, a package or the preamble are used.")
2320                 : qt_("If no value is given, the defaults as set by the geometry package or a package/class overriding geometry's defaults are used.");
2321         marginsModule->topLE->setPlaceholderText(placeholder);
2322         marginsModule->bottomLE->setPlaceholderText(placeholder);
2323         marginsModule->innerLE->setPlaceholderText(placeholder);
2324         marginsModule->outerLE->setPlaceholderText(placeholder);
2325         marginsModule->headheightLE->setPlaceholderText(placeholder);
2326         marginsModule->headsepLE->setPlaceholderText(placeholder);
2327         marginsModule->footskipLE->setPlaceholderText(placeholder);
2328         marginsModule->columnsepLE->setPlaceholderText(placeholder);
2329         marginsModule->topLE->setToolTip(tooltip);
2330         marginsModule->bottomLE->setToolTip(tooltip);
2331         marginsModule->innerLE->setToolTip(tooltip);
2332         marginsModule->outerLE->setToolTip(tooltip);
2333         marginsModule->headheightLE->setToolTip(tooltip);
2334         marginsModule->headsepLE->setToolTip(tooltip);
2335         marginsModule->footskipLE->setToolTip(tooltip);
2336         marginsModule->columnsepLE->setToolTip(tooltip);
2337 }
2338
2339
2340 void GuiDocument::changeBackgroundColor()
2341 {
2342         QColor const & newColor = getColor(rgb2qcolor(set_backgroundcolor));
2343         if (!newColor.isValid())
2344                 return;
2345         // set the color
2346         colorModule->pageBackgroundCF->setVisible(true);
2347         colorModule->pageBackgroundCF->setStyleSheet(
2348                 colorFrameStyleSheet(newColor));
2349         // save color
2350         set_backgroundcolor = rgbFromHexName(fromqstr(newColor.name()));
2351         is_backgroundcolor = true;
2352         change_adaptor();
2353 }
2354
2355
2356 void GuiDocument::deleteBackgroundColor()
2357 {
2358         // set the color back to default by setting an empty StyleSheet
2359         colorModule->pageBackgroundCF->setStyleSheet(QLatin1String(""));
2360         colorModule->pageBackgroundCF->setVisible(false);
2361         // save default color (white)
2362         set_backgroundcolor = rgbFromHexName("#ffffff");
2363         is_backgroundcolor = false;
2364         change_adaptor();
2365 }
2366
2367
2368 void GuiDocument::changeFontColor()
2369 {
2370         QColor const & newColor = getColor(rgb2qcolor(set_fontcolor));
2371         if (!newColor.isValid())
2372                 return;
2373         //  set the color
2374         colorModule->mainTextCF->setVisible(true);
2375         colorModule->mainTextCF->setStyleSheet(
2376                 colorFrameStyleSheet(newColor));
2377         // save color
2378         set_fontcolor = rgbFromHexName(fromqstr(newColor.name()));
2379         is_fontcolor = true;
2380         change_adaptor();
2381 }
2382
2383
2384 void GuiDocument::deleteFontColor()
2385 {
2386         // set the button color back to default by setting an empty StyleSheet
2387         colorModule->mainTextCF->setStyleSheet(QLatin1String(""));
2388         colorModule->mainTextCF->setVisible(false);
2389         // save default color (black)
2390         set_fontcolor = rgbFromHexName("#000000");
2391         is_fontcolor = false;
2392         change_adaptor();
2393 }
2394
2395
2396 void GuiDocument::changeNoteFontColor()
2397 {
2398         QColor const & newColor = getColor(rgb2qcolor(set_notefontcolor));
2399         if (!newColor.isValid())
2400                 return;
2401         // set the color
2402         colorModule->noteFontCF->setStyleSheet(
2403                 colorFrameStyleSheet(newColor));
2404         // save color
2405         set_notefontcolor = rgbFromHexName(fromqstr(newColor.name()));
2406         is_notefontcolor = true;
2407         change_adaptor();
2408 }
2409
2410
2411 void GuiDocument::deleteNoteFontColor()
2412 {
2413         // set the color back to pref
2414         theApp()->getRgbColor(Color_greyedouttext, set_notefontcolor);
2415         colorModule->noteFontCF->setStyleSheet(
2416                 colorFrameStyleSheet(rgb2qcolor(set_notefontcolor)));
2417         is_notefontcolor = false;
2418         change_adaptor();
2419 }
2420
2421
2422 void GuiDocument::changeBoxBackgroundColor()
2423 {
2424         QColor const & newColor = getColor(rgb2qcolor(set_boxbgcolor));
2425         if (!newColor.isValid())
2426                 return;
2427         // set the color
2428         colorModule->boxBackgroundCF->setStyleSheet(
2429                 colorFrameStyleSheet(newColor));
2430         // save color
2431         set_boxbgcolor = rgbFromHexName(fromqstr(newColor.name()));
2432         is_boxbgcolor = true;
2433         change_adaptor();
2434 }
2435
2436
2437 void GuiDocument::deleteBoxBackgroundColor()
2438 {
2439         // set the color back to pref
2440         theApp()->getRgbColor(Color_shadedbg, set_boxbgcolor);
2441         colorModule->boxBackgroundCF->setStyleSheet(
2442                 colorFrameStyleSheet(rgb2qcolor(set_boxbgcolor)));
2443         is_boxbgcolor = false;
2444         change_adaptor();
2445 }
2446
2447
2448 void GuiDocument::updateQuoteStyles(bool const set)
2449 {
2450         Language const * lang = lyx::languages.getLanguage(
2451                 fromqstr(langModule->languageCO->itemData(
2452                         langModule->languageCO->currentIndex()).toString()));
2453
2454         QuoteStyle def = bp_.getQuoteStyle(lang->quoteStyle());
2455
2456         langModule->quoteStyleCO->clear();
2457
2458         bool has_default = false;
2459         for (int i = 0; i < quoteparams.stylescount(); ++i) {
2460                 QuoteStyle qs = QuoteStyle(i);
2461                 if (qs == QuoteStyle::Dynamic)
2462                         continue;
2463                 bool const langdef = (qs == def);
2464                 if (langdef) {
2465                         // add the default style on top
2466                         langModule->quoteStyleCO->insertItem(0,
2467                                 toqstr(quoteparams.getGuiLabel(qs, langdef)), static_cast<int>(qs));
2468                         has_default = true;
2469                 }
2470                 else
2471                         langModule->quoteStyleCO->addItem(
2472                                 toqstr(quoteparams.getGuiLabel(qs, langdef)), static_cast<int>(qs));
2473         }
2474         // Use document serif font to assure quotation marks are distinguishable
2475         QFont comboFont(toqstr(lyxrc.roman_font_name),
2476                         langModule->quoteStyleCO->fontInfo().pointSize() * 1.4, -1, false);
2477         QFontMetrics fm(comboFont);
2478         // calculate width of the widest item in the set font
2479         int qswidth = 0;
2480         for (int i = 0; i < langModule->quoteStyleCO->count(); ++i) {
2481                 langModule->quoteStyleCO->setItemData(i, QVariant(comboFont), Qt::FontRole);
2482                 QString str = langModule->quoteStyleCO->itemText(i);
2483 #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
2484                 qswidth = max(qswidth, fm.horizontalAdvance(str));
2485 #else
2486                 qswidth = max(qswidth, fm.width(str));
2487 #endif
2488         }
2489         // add scrollbar width and margin to width
2490         qswidth += langModule->quoteStyleCO->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
2491         qswidth += langModule->quoteStyleCO->view()->autoScrollMargin();
2492         langModule->quoteStyleCO->view()->setMinimumWidth(qswidth);
2493         if (set && has_default)
2494                 // (re)set to the default style
2495                 langModule->quoteStyleCO->setCurrentIndex(0);
2496 }
2497
2498
2499 void GuiDocument::languageChanged(int i)
2500 {
2501         // some languages only work with Polyglossia
2502         Language const * lang = lyx::languages.getLanguage(
2503                 fromqstr(langModule->languageCO->itemData(i).toString()));
2504         if (lang->babel().empty() && !lang->polyglossia().empty()
2505                 && lang->required() != "CJK" && lang->required() != "japanese") {
2506                         // If we force to switch fontspec on, store
2507                         // current state (#8717)
2508                         if (fontModule->osFontsCB->isEnabled())
2509                                 forced_fontspec_activation =
2510                                         !fontModule->osFontsCB->isChecked();
2511                         fontModule->osFontsCB->setChecked(true);
2512                         fontModule->osFontsCB->setEnabled(false);
2513         }
2514         else {
2515                 fontModule->osFontsCB->setEnabled(true);
2516                 // If we have forced to switch fontspec on,
2517                 // restore previous state (#8717)
2518                 if (forced_fontspec_activation)
2519                         fontModule->osFontsCB->setChecked(false);
2520                 forced_fontspec_activation = false;
2521         }
2522
2523         // set appropriate quotation mark style
2524         updateQuoteStyles(true);
2525 }
2526
2527
2528 void GuiDocument::osFontsChanged(bool nontexfonts)
2529 {
2530         bool const tex_fonts = !nontexfonts;
2531         // store current fonts
2532         QString const font_roman = fontModule->fontsRomanCO->getData(
2533                         fontModule->fontsRomanCO->currentIndex());
2534         QString const font_sans = fontModule->fontsSansCO->getData(
2535                         fontModule->fontsSansCO->currentIndex());
2536         QString const font_typewriter = fontModule->fontsTypewriterCO->getData(
2537                         fontModule->fontsTypewriterCO->currentIndex());
2538         QString const font_math = fontModule->fontsMathCO->itemData(
2539                         fontModule->fontsMathCO->currentIndex()).toString();
2540         int const font_sf_scale = fontModule->scaleSansSB->value();
2541         int const font_tt_scale = fontModule->scaleTypewriterSB->value();
2542
2543         updateFontlist();
2544         // store default format
2545         QString const dformat = outputModule->defaultFormatCO->itemData(
2546                 outputModule->defaultFormatCO->currentIndex()).toString();
2547         updateDefaultFormat();
2548         // try to restore default format
2549         int index = outputModule->defaultFormatCO->findData(dformat);
2550         // set to default if format is not found
2551         if (index == -1)
2552                 index = 0;
2553         outputModule->defaultFormatCO->setCurrentIndex(index);
2554
2555         // try to restore fonts which were selected two toggles ago
2556         if (!fontModule->font_roman.isEmpty())
2557                 fontModule->fontsRomanCO->set(fontModule->font_roman);
2558         if (!fontModule->font_sans.isEmpty())
2559                 fontModule->fontsSansCO->set(fontModule->font_sans);
2560         if (!fontModule->font_typewriter.isEmpty())
2561                 fontModule->fontsTypewriterCO->set(fontModule->font_typewriter);
2562         index = fontModule->fontsMathCO->findData(fontModule->font_math);
2563         if (index != -1)
2564                 fontModule->fontsMathCO->setCurrentIndex(index);
2565         // save fonts for next next toggle
2566         fontModule->font_roman = font_roman;
2567         fontModule->font_sans = font_sans;
2568         fontModule->font_typewriter = font_typewriter;
2569         fontModule->font_math = font_math;
2570         fontModule->font_sf_scale = font_sf_scale;
2571         fontModule->font_tt_scale = font_tt_scale;
2572
2573         // non-tex fonts override the "\inputencoding" option with "utf8-plain"
2574         langModule->encodingCO->setEnabled(tex_fonts);
2575         inputencodingToDialog();
2576
2577         fontModule->cjkFontLE->setEnabled(tex_fonts);
2578         fontModule->cjkFontLA->setEnabled(tex_fonts);
2579
2580         updateFontOptions();
2581
2582         fontModule->fontencLA->setEnabled(tex_fonts);
2583         fontModule->fontencCO->setEnabled(tex_fonts);
2584         if (!tex_fonts)
2585                 fontModule->fontencLE->setEnabled(false);
2586         else
2587                 fontencChanged(fontModule->fontencCO->currentIndex());
2588 }
2589
2590
2591 void GuiDocument::encodingSwitched(int i)
2592 {
2593         bool const tex_fonts = !fontModule->osFontsCB->isChecked();
2594         langModule->unicodeEncodingCO->setEnabled(tex_fonts);
2595         langModule->customEncodingCO->setEnabled(tex_fonts);
2596         langModule->autoEncodingCO->setEnabled(tex_fonts);
2597         langModule->unicodeEncodingCO->setVisible(i == EncodingSets::unicode);
2598         langModule->autoEncodingCO->setVisible(i == EncodingSets::legacy);
2599         langModule->customEncodingCO->setVisible(i == EncodingSets::custom);
2600         switch (i) {
2601         case EncodingSets::unicode:
2602                 langModule->encodingVariantLA->setBuddy(langModule->unicodeEncodingCO);
2603                 break;
2604         case EncodingSets::legacy:
2605                 langModule->encodingVariantLA->setBuddy(langModule->autoEncodingCO);
2606                 break;
2607         case EncodingSets::custom:
2608                 langModule->encodingVariantLA->setBuddy(langModule->customEncodingCO);
2609                 break;
2610         }
2611  
2612         if (tex_fonts)
2613                 langModule->unicodeEncodingCO->setItemText(1, qt_("Direct (No inputenc)"));
2614         else
2615                 langModule->unicodeEncodingCO->setItemText(1, qt_("Direct (XeTeX/LuaTeX)"));
2616 }
2617
2618 void GuiDocument::inputencodingToDialog()
2619 {
2620         QString inputenc = toqstr(bp_.inputenc);
2621         int p;
2622         if (fontModule->osFontsCB->isChecked()) { // non-tex fonts require utf8-plain
2623                 langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2624                 langModule->unicodeEncodingCO->setCurrentIndex(
2625                         langModule->unicodeEncodingCO->findData("utf8-plain"));
2626         } else if (inputenc.startsWith("utf8")) {
2627                 langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2628                 p = langModule->unicodeEncodingCO->findData(inputenc);
2629                 if (p == -1)
2630                         p = 0;
2631                 langModule->unicodeEncodingCO->setCurrentIndex(p);
2632                 langModule->autoEncodingCO->setCurrentIndex(0);
2633                 langModule->customEncodingCO->setCurrentIndex(0);
2634         } else if (inputenc.startsWith("auto")) {
2635                 langModule->encodingCO->setCurrentIndex(EncodingSets::legacy);
2636                 p = langModule->autoEncodingCO->findData(inputenc);
2637                 if (p == -1)
2638                         p = 0;
2639                 langModule->unicodeEncodingCO->setCurrentIndex(0);
2640                 langModule->autoEncodingCO->setCurrentIndex(p);
2641                 langModule->customEncodingCO->setCurrentIndex(0);
2642         } else {
2643                 langModule->encodingCO->setCurrentIndex(EncodingSets::custom);
2644                 p = langModule->customEncodingCO->findData(inputenc);
2645                 if (p == -1) {
2646                         p = 0;
2647                         langModule->encodingCO->setCurrentIndex(EncodingSets::unicode);
2648                 }
2649                 langModule->unicodeEncodingCO->setCurrentIndex(0);
2650                 langModule->autoEncodingCO->setCurrentIndex(0);
2651                 langModule->customEncodingCO->setCurrentIndex(p);
2652         }
2653         encodingSwitched(langModule->encodingCO->currentIndex());
2654 }
2655
2656
2657 void GuiDocument::mathFontChanged(int)
2658 {
2659         updateFontOptions();
2660 }
2661
2662 void GuiDocument::fontOsfToggled(bool state)
2663 {
2664         if (fontModule->osFontsCB->isChecked())
2665                 return;
2666         QString font = fontModule->fontsRomanCO->getData(
2667                         fontModule->fontsRomanCO->currentIndex());
2668         if (hasMonolithicExpertSet(font))
2669                 fontModule->fontScCB->setChecked(state);
2670 }
2671
2672
2673 void GuiDocument::fontScToggled(bool state)
2674 {
2675         if (fontModule->osFontsCB->isChecked())
2676                 return;
2677         QString font = fontModule->fontsRomanCO->getData(
2678                         fontModule->fontsRomanCO->currentIndex());
2679         if (hasMonolithicExpertSet(font))
2680                 fontModule->fontOsfCB->setChecked(state);
2681 }
2682
2683
2684 void GuiDocument::updateExtraOpts()
2685 {
2686         QString font = fontModule->fontsRomanCO->getData(
2687                         fontModule->fontsRomanCO->currentIndex());
2688         bool const rm_opts = providesExtraOpts(font);
2689         font = fontModule->fontsSansCO->getData(
2690                         fontModule->fontsSansCO->currentIndex());
2691         bool const sf_opts = providesExtraOpts(font);
2692         font = fontModule->fontsTypewriterCO->getData(
2693                         fontModule->fontsTypewriterCO->currentIndex());
2694         bool const tt_opts = providesExtraOpts(font);
2695         fontModule->fontspecRomanLA->setEnabled(rm_opts);
2696         fontModule->fontspecRomanLE->setEnabled(rm_opts);
2697         fontModule->fontspecSansLA->setEnabled(sf_opts);
2698         fontModule->fontspecSansLE->setEnabled(sf_opts);
2699         fontModule->fontspecTypewriterLA->setEnabled(tt_opts);
2700         fontModule->fontspecTypewriterLE->setEnabled(tt_opts);
2701 }
2702
2703
2704 void GuiDocument::updateFontOptions()
2705 {
2706         QString font = fontModule->fontsSansCO->getData(
2707                         fontModule->fontsSansCO->currentIndex());
2708         bool scalable = providesScale(font);
2709         fontModule->scaleSansSB->setEnabled(scalable);
2710         fontModule->scaleSansLA->setEnabled(scalable);
2711         fontModule->fontSansOsfCB->setEnabled(providesOSF(font));
2712         font = fontModule->fontsTypewriterCO->getData(
2713                         fontModule->fontsTypewriterCO->currentIndex());
2714         scalable = providesScale(font);
2715         fontModule->scaleTypewriterSB->setEnabled(scalable);
2716         fontModule->scaleTypewriterLA->setEnabled(scalable);
2717         fontModule->fontTypewriterOsfCB->setEnabled(providesOSF(font));
2718         font = fontModule->fontsRomanCO->getData(
2719                         fontModule->fontsRomanCO->currentIndex());
2720         fontModule->fontScCB->setEnabled(providesSC(font));
2721         fontModule->fontOsfCB->setEnabled(providesOSF(font));
2722         updateExtraOpts();
2723         updateMathFonts(font);
2724 }
2725
2726
2727 void GuiDocument::updateFontsize(string const & items, string const & sel)
2728 {
2729         fontModule->fontsizeCO->clear();
2730         fontModule->fontsizeCO->addItem(qt_("Default"));
2731
2732         for (int n = 0; !token(items,'|',n).empty(); ++n)
2733                 fontModule->fontsizeCO->
2734                         addItem(toqstr(token(items,'|',n)));
2735
2736         for (int n = 0; n < fontModule->fontsizeCO->count(); ++n) {
2737                 if (fromqstr(fontModule->fontsizeCO->itemText(n)) == sel) {
2738                         fontModule->fontsizeCO->setCurrentIndex(n);
2739                         break;
2740                 }
2741         }
2742 }
2743
2744
2745 bool GuiDocument::ot1() const
2746 {
2747         QString const fontenc =
2748                 fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString();
2749         int const i = langModule->languageCO->currentIndex();
2750         if (i == -1)
2751                 return false;
2752         QString const langname = langModule->languageCO->itemData(i).toString();
2753         Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
2754         return (fontenc == "default"
2755                 || (fontenc == "auto" && newlang->fontenc(buffer().params()) == "OT1")
2756                 || (fontenc == "custom" && fontModule->fontencLE->text() == "OT1"));
2757 }
2758
2759
2760 bool GuiDocument::completeFontset() const
2761 {
2762         return (fontModule->fontsSansCO->getData(
2763                         fontModule->fontsSansCO->currentIndex()) == "default"
2764                 && fontModule->fontsSansCO->getData(
2765                         fontModule->fontsTypewriterCO->currentIndex()) == "default");
2766 }
2767
2768
2769 bool GuiDocument::noMathFont() const
2770 {
2771         return (fontModule->fontsMathCO->itemData(
2772                 fontModule->fontsMathCO->currentIndex()).toString() == "default");
2773 }
2774
2775
2776 void GuiDocument::updateTexFonts()
2777 {
2778         LaTeXFonts::TexFontMap texfontmap = theLaTeXFonts().getLaTeXFonts();
2779
2780         LaTeXFonts::TexFontMap::const_iterator it = texfontmap.begin();
2781         LaTeXFonts::TexFontMap::const_iterator end = texfontmap.end();
2782         for (; it != end; ++it) {
2783                 LaTeXFont lf = it->second;
2784                 if (lf.name().empty()) {
2785                         LYXERR0("Error: Unnamed font: " << it->first);
2786                         continue;
2787                 }
2788                 docstring const family = lf.family();
2789                 docstring guiname = translateIfPossible(lf.guiname());
2790                 if (!lf.available(ot1(), noMathFont()))
2791                         guiname += _(" (not installed)");
2792                 if (family == "rm")
2793                         rmfonts_.insert(toqstr(guiname), toqstr(it->first));
2794                 else if (family == "sf")
2795                         sffonts_.insert(toqstr(guiname), toqstr(it->first));
2796                 else if (family == "tt")
2797                         ttfonts_.insert(toqstr(guiname), toqstr(it->first));
2798                 else if (family == "math")
2799                         mathfonts_.insert(toqstr(guiname), toqstr(it->first));
2800         }
2801 }
2802
2803
2804 void GuiDocument::updateFontlist()
2805 {
2806         // reset the filters of the CategorizedCombos
2807         fontModule->fontsRomanCO->resetFilter();
2808         fontModule->fontsSansCO->resetFilter();
2809         fontModule->fontsTypewriterCO->resetFilter();
2810         fontModule->fontsRomanCO->clear();
2811         fontModule->fontsSansCO->clear();
2812         fontModule->fontsTypewriterCO->clear();
2813         fontModule->fontsMathCO->clear();
2814
2815         // With fontspec (XeTeX, LuaTeX), we have access to all system fonts, but not the LaTeX fonts
2816         if (fontModule->osFontsCB->isChecked()) {
2817                 fontModule->fontsRomanCO->addItemSort(QString("default"), qt_("Default"),
2818                                                       QString(), qt_("Default font (as set by class)"),
2819                                                       false, false, false, true, true);
2820                 fontModule->fontsSansCO->addItemSort(QString("default"), qt_("Default"),
2821                                                      QString(), qt_("Default font (as set by class)"),
2822                                                      false, false, false, true, true);
2823                 fontModule->fontsTypewriterCO->addItemSort(QString("default"), qt_("Default"),
2824                                                            QString(), qt_("Default font (as set by class)"),
2825                                                            false, false, false, true, true);
2826                 QString unimath = qt_("Non-TeX Fonts Default");
2827                 if (!LaTeXFeatures::isAvailable("unicode-math"))
2828                         unimath += qt_(" (not available)");
2829                 fontModule->fontsMathCO->addItem(qt_("Class Default (TeX Fonts)"), QString("auto"));
2830                 fontModule->fontsMathCO->addItem(unimath, QString("default"));
2831
2832 #if QT_VERSION >= 0x060000
2833                 const QStringList families(QFontDatabase::families());
2834 #else
2835                 QFontDatabase fontdb;
2836                 const QStringList families(fontdb.families());
2837 #endif
2838                 for (auto const & family : families) {
2839                         fontModule->fontsRomanCO->addItemSort(family, family,
2840                                                               QString(), QString(),
2841                                                               false, false, false, true, true);
2842                         fontModule->fontsSansCO->addItemSort(family, family,
2843                                                              QString(), QString(),
2844                                                              false, false, false, true, true);
2845                         fontModule->fontsTypewriterCO->addItemSort(family, family,
2846                                                                    QString(), QString(),
2847                                                                    false, false, false, true, true);
2848                 }
2849                 return;
2850         }
2851
2852         if (rmfonts_.empty())
2853                 updateTexFonts();
2854
2855         fontModule->fontsRomanCO->addItemSort(QString("default"), qt_("Default"),
2856                                               QString(), qt_("Default font (as set by class)"),
2857                                               false, false, false, true, true);
2858         QMap<QString, QString>::const_iterator rmi = rmfonts_.constBegin();
2859         while (rmi != rmfonts_.constEnd()) {
2860                 fontModule->fontsRomanCO->addItemSort(rmi.value(), rmi.key(),
2861                                                       QString(), QString(),
2862                                                       false, false, false, true, true);
2863                 ++rmi;
2864         }
2865
2866         fontModule->fontsSansCO->addItemSort(QString("default"), qt_("Default"),
2867                                              QString(), qt_("Default font (as set by class)"),
2868                                              false, false, false, true, true);
2869         QMap<QString, QString>::const_iterator sfi = sffonts_.constBegin();
2870         while (sfi != sffonts_.constEnd()) {
2871                 fontModule->fontsSansCO->addItemSort(sfi.value(), sfi.key(),
2872                                                      QString(), QString(),
2873                                                      false, false, false, true, true);
2874                 ++sfi;
2875         }
2876
2877         fontModule->fontsTypewriterCO->addItemSort(QString("default"), qt_("Default"),
2878                                                    QString(), qt_("Default font (as set by class)"),
2879                                                    false, false, false, true, true);
2880         QMap<QString, QString>::const_iterator tti = ttfonts_.constBegin();
2881         while (tti != ttfonts_.constEnd()) {
2882                 fontModule->fontsTypewriterCO->addItemSort(tti.value(), tti.key(),
2883                                                            QString(), QString(),
2884                                                            false, false, false, true, true);
2885                 ++tti;
2886         }
2887
2888         fontModule->fontsMathCO->addItem(qt_("Automatic"), QString("auto"));
2889         fontModule->fontsMathCO->addItem(qt_("Class Default"), QString("default"));
2890         QMap<QString, QString>::const_iterator mmi = mathfonts_.constBegin();
2891         while (mmi != mathfonts_.constEnd()) {
2892                 fontModule->fontsMathCO->addItem(mmi.key(), mmi.value());
2893                 ++mmi;
2894         }
2895 }
2896
2897
2898 void GuiDocument::fontencChanged(int item)
2899 {
2900         fontModule->fontencLE->setEnabled(
2901                 fontModule->fontencCO->itemData(item).toString() == "custom");
2902         // The availability of TeX fonts depends on the font encoding
2903         updateTexFonts();
2904         updateFontOptions();
2905 }
2906
2907
2908 void GuiDocument::updateMathFonts(QString const & rm)
2909 {
2910         if (fontModule->osFontsCB->isChecked())
2911                 return;
2912         QString const math =
2913                 fontModule->fontsMathCO->itemData(fontModule->fontsMathCO->currentIndex()).toString();
2914         int const i = fontModule->fontsMathCO->findData("default");
2915         if (providesNoMath(rm) && i == -1)
2916                 fontModule->fontsMathCO->insertItem(1, qt_("Class Default"), QString("default"));
2917         else if (!providesNoMath(rm) && i != -1) {
2918                 int const c = fontModule->fontsMathCO->currentIndex();
2919                 fontModule->fontsMathCO->removeItem(i);
2920                 if (c == i)
2921                         fontModule->fontsMathCO->setCurrentIndex(0);
2922         }
2923 }
2924
2925
2926 void GuiDocument::romanChanged(int item)
2927 {
2928         QString const font = fontModule->fontsRomanCO->getData(item);
2929         fontModule->fontOsfCB->setEnabled(providesOSF(font));
2930         updateExtraOpts();
2931         if (fontModule->osFontsCB->isChecked())
2932                 return;
2933         fontModule->fontScCB->setEnabled(providesSC(font));
2934         updateMathFonts(font);
2935 }
2936
2937
2938 void GuiDocument::sansChanged(int item)
2939 {
2940         QString const font = fontModule->fontsSansCO->getData(item);
2941         bool const scalable = providesScale(font);
2942         fontModule->scaleSansSB->setEnabled(scalable);
2943         fontModule->scaleSansLA->setEnabled(scalable);
2944         fontModule->fontSansOsfCB->setEnabled(providesOSF(font));
2945         updateExtraOpts();
2946 }
2947
2948
2949 void GuiDocument::ttChanged(int item)
2950 {
2951         QString const font = fontModule->fontsTypewriterCO->getData(item);
2952         bool scalable = providesScale(font);
2953         fontModule->scaleTypewriterSB->setEnabled(scalable);
2954         fontModule->scaleTypewriterLA->setEnabled(scalable);
2955         fontModule->fontTypewriterOsfCB->setEnabled(providesOSF(font));
2956         updateExtraOpts();
2957 }
2958
2959
2960 void GuiDocument::updatePagestyle(string const & items, string const & sel)
2961 {
2962         pagestyles.clear();
2963         pageLayoutModule->pagestyleCO->clear();
2964         pageLayoutModule->pagestyleCO->addItem(qt_("Default"));
2965
2966         for (int n = 0; !token(items, '|', n).empty(); ++n) {
2967                 string style = token(items, '|', n);
2968                 QString style_gui = qt_(style);
2969                 pagestyles.push_back(pair<string, QString>(style, style_gui));
2970                 pageLayoutModule->pagestyleCO->addItem(style_gui);
2971         }
2972
2973         if (sel == "default") {
2974                 pageLayoutModule->pagestyleCO->setCurrentIndex(0);
2975                 return;
2976         }
2977
2978         int nn = 0;
2979
2980         for (auto const & pagestyle : pagestyles)
2981                 if (pagestyle.first == sel)
2982                         nn = pageLayoutModule->pagestyleCO->findText(pagestyle.second);
2983
2984         if (nn > 0)
2985                 pageLayoutModule->pagestyleCO->setCurrentIndex(nn);
2986 }
2987
2988
2989 void GuiDocument::browseLayout()
2990 {
2991         QString const label1 = qt_("Lay&outs");
2992         QString const dir1 = toqstr(lyxrc.document_path);
2993         QStringList const filter(qt_("LyX Layout (*.layout)"));
2994         QString file = browseRelToParent(QString(), bufferFilePath(),
2995                 qt_("Local layout file"), filter, false,
2996                 label1, dir1);
2997
2998         if (!file.endsWith(".layout"))
2999                 return;
3000
3001         FileName layoutFile = support::makeAbsPath(fromqstr(file),
3002                 fromqstr(bufferFilePath()));
3003
3004         int const ret = Alert::prompt(_("Local layout file"),
3005                 _("The layout file you have selected is a local layout\n"
3006                   "file, not one in the system or user directory.\n"
3007                   "Your document will not work with this layout if you\n"
3008                   "move the layout file to a different directory."),
3009                   1, 1, _("&Set Layout"), _("&Cancel"));
3010         if (ret == 1)
3011                 return;
3012
3013         // load the layout file
3014         LayoutFileList & bcl = LayoutFileList::get();
3015         string classname = layoutFile.onlyFileName();
3016         // this will update an existing layout if that layout has been loaded before.
3017         LayoutFileIndex name = support::onlyFileName(bcl.addLocalLayout(
3018                 classname.substr(0, classname.size() - 7),
3019                 layoutFile.onlyPath().absFileName()));
3020
3021         if (name.empty()) {
3022                 Alert::error(_("Error"),
3023                         _("Unable to read local layout file."));
3024                 return;
3025         }
3026
3027         const_cast<Buffer &>(buffer()).setLayoutPos(layoutFile.onlyPath().absFileName());
3028
3029         // do not trigger classChanged if there is no change.
3030         if (latexModule->classCO->currentText() == toqstr(name))
3031                 return;
3032
3033         // add to combo box
3034         bool const avail = latexModule->classCO->set(toqstr(name));
3035         if (!avail) {
3036                 LayoutFile const & tc = bcl[name];
3037                 docstring const guiname = translateIfPossible(from_utf8(tc.description()));
3038                 // tooltip sensu "KOMA-Script Article [Class 'scrartcl']"
3039                 QString tooltip = toqstr(bformat(_("%1$s [Class '%2$s']"), guiname, from_utf8(tc.latexname())));
3040                 tooltip += '\n' + qt_("This is a local layout file.");
3041                 latexModule->classCO->addItemSort(toqstr(tc.name()), toqstr(guiname),
3042                                                   toqstr(translateIfPossible(from_utf8(tc.category()))),
3043                                                   tooltip,
3044                                                   true, true, true, true);
3045                 latexModule->classCO->set(toqstr(name));
3046         }
3047
3048         classChanged();
3049 }
3050
3051
3052 void GuiDocument::browseMaster()
3053 {
3054         QString const title = qt_("Select master document");
3055         QString const dir1 = toqstr(lyxrc.document_path);
3056         QString const old = latexModule->childDocLE->text();
3057         QString const docpath = toqstr(support::onlyPath(buffer().absFileName()));
3058         QStringList const filter(qt_("LyX Files (*.lyx)"));
3059         QString file = browseRelToSub(old, docpath, title, filter, false,
3060                 qt_("D&ocuments"), toqstr(lyxrc.document_path));
3061
3062         if (!file.isEmpty())
3063                 latexModule->childDocLE->setText(file);
3064 }
3065
3066
3067 void GuiDocument::classChanged_adaptor()
3068 {
3069         const_cast<Buffer &>(buffer()).setLayoutPos(string());
3070         classChanged();
3071 }
3072
3073
3074 void GuiDocument::classChanged()
3075 {
3076         int idx = latexModule->classCO->currentIndex();
3077         if (idx < 0)
3078                 return;
3079         string const classname = fromqstr(latexModule->classCO->getData(idx));
3080
3081         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
3082                 int const ret = Alert::prompt(_("Unapplied changes"),
3083                                 _("Some changes in the dialog were not yet applied.\n"
3084                                 "If you do not apply now, they will be lost after this action."),
3085                                 1, 1, _("&Apply"), _("&Dismiss"));
3086                 if (ret == 0)
3087                         applyView();
3088         }
3089
3090         // We load the TextClass as soon as it is selected. This is
3091         // necessary so that other options in the dialog can be updated
3092         // according to the new class. Note, however, that, if you use
3093         // the scroll wheel when sitting on the combo box, we'll load a
3094         // lot of TextClass objects very quickly....
3095         if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
3096                 Alert::error(_("Error"), _("Unable to set document class."));
3097                 return;
3098         }
3099         if (lyxrc.auto_reset_options)
3100                 bp_.useClassDefaults();
3101
3102         // With the introduction of modules came a distinction between the base
3103         // class and the document class. The former corresponds to the main layout
3104         // file; the latter is that plus the modules (or the document-specific layout,
3105         // or  whatever else there could be). Our parameters come from the document
3106         // class. So when we set the base class, we also need to recreate the document
3107         // class. Otherwise, we still have the old one.
3108         bp_.makeDocumentClass();
3109         paramsToDialog();
3110 }
3111
3112
3113 void GuiDocument::languagePackageChanged(int i)
3114 {
3115          langModule->languagePackageLE->setEnabled(
3116                 langModule->languagePackageCO->itemData(i).toString() == "custom");
3117 }
3118
3119
3120 void GuiDocument::biblioChanged()
3121 {
3122         biblioChanged_ = true;
3123         change_adaptor();
3124 }
3125
3126
3127 void GuiDocument::checkPossibleCiteEngines()
3128 {
3129         // Check if the class provides a specific engine,
3130         // and if so, enforce this.
3131         string force_engine;
3132         if (documentClass().provides("natbib")
3133             || documentClass().provides("natbib-internal"))
3134                 force_engine = "natbib";
3135         else if (documentClass().provides("jurabib"))
3136                 force_engine = "jurabib";
3137         else if (documentClass().provides("biblatex"))
3138                 force_engine = "biblatex";
3139         else if (documentClass().provides("biblatex-natbib"))
3140                 force_engine = "biblatex-natbib";
3141
3142         if (!force_engine.empty())
3143                 biblioModule->citeEngineCO->setCurrentIndex(
3144                         biblioModule->citeEngineCO->findData(toqstr(force_engine)));
3145         biblioModule->citeEngineCO->setEnabled(force_engine.empty());
3146 }
3147
3148
3149 void GuiDocument::rescanBibFiles()
3150 {
3151         if (isBiblatex())
3152                 rescanTexStyles("bbx cbx");
3153         else
3154                 rescanTexStyles("bst");
3155 }
3156
3157
3158 void GuiDocument::resetDefaultBibfile(string const & which)
3159 {
3160         QString const engine =
3161                 biblioModule->citeEngineCO->itemData(
3162                                 biblioModule->citeEngineCO->currentIndex()).toString();
3163
3164         CiteEngineType const cet =
3165                 CiteEngineType(biblioModule->citeStyleCO->itemData(
3166                                                           biblioModule->citeStyleCO->currentIndex()).toInt());
3167
3168         updateDefaultBiblio(theCiteEnginesList[fromqstr(engine)]->getDefaultBiblio(cet), which);
3169 }
3170
3171
3172 void GuiDocument::resetDefaultBbxBibfile()
3173 {
3174         resetDefaultBibfile("bbx");
3175 }
3176
3177
3178 void GuiDocument::resetDefaultCbxBibfile()
3179 {
3180         resetDefaultBibfile("cbx");
3181 }
3182
3183
3184 void GuiDocument::citeEngineChanged(int n)
3185 {
3186         QString const engine =
3187                 biblioModule->citeEngineCO->itemData(n).toString();
3188
3189         vector<string> const engs =
3190                 theCiteEnginesList[fromqstr(engine)]->getEngineType();
3191
3192         updateCiteStyles(engs);
3193         updateEngineDependends();
3194         resetDefaultBibfile();
3195         biblioChanged();
3196 }
3197
3198
3199 void GuiDocument::updateEngineDependends()
3200 {
3201         bool const biblatex = isBiblatex();
3202
3203         // These are only useful with BibTeX
3204         biblioModule->defaultBiblioCO->setEnabled(!biblatex);
3205         biblioModule->bibtexStyleLA->setEnabled(!biblatex);
3206         biblioModule->resetDefaultBiblioPB->setEnabled(!biblatex);
3207         biblioModule->bibtopicCB->setEnabled(!biblatex);
3208
3209         // These are only useful with Biblatex
3210         biblioModule->biblatexBbxCO->setEnabled(biblatex);
3211         biblioModule->biblatexBbxLA->setEnabled(biblatex);
3212         biblioModule->biblatexCbxCO->setEnabled(biblatex);
3213         biblioModule->biblatexCbxLA->setEnabled(biblatex);
3214         biblioModule->resetBbxPB->setEnabled(biblatex);
3215         biblioModule->resetCbxPB->setEnabled(biblatex);
3216         biblioModule->matchBbxPB->setEnabled(biblatex);
3217
3218         // These are useful with biblatex, jurabib and natbib
3219         QString const engine =
3220                 biblioModule->citeEngineCO->itemData(
3221                                 biblioModule->citeEngineCO->currentIndex()).toString();
3222         LyXCiteEngine const * ce = theCiteEnginesList[fromqstr(engine)];
3223
3224         bool const citepack = ce->required("biblatex.sty") || ce->required("jurabib.sty")
3225                         || ce->required("natbib.sty");
3226         biblioModule->citePackageOptionsLE->setEnabled(citepack);
3227         biblioModule->citePackageOptionsL->setEnabled(citepack);
3228 }
3229
3230
3231 void GuiDocument::citeStyleChanged()
3232 {
3233         QString const engine =
3234                 biblioModule->citeEngineCO->itemData(
3235                                 biblioModule->citeEngineCO->currentIndex()).toString();
3236         QString const currentDef = isBiblatex() ?
3237                 biblioModule->biblatexBbxCO->currentText()
3238                 : biblioModule->defaultBiblioCO->currentText();
3239         if (theCiteEnginesList[fromqstr(engine)]->isDefaultBiblio(fromqstr(currentDef)))
3240                 resetDefaultBibfile();
3241
3242         biblioChanged();
3243 }
3244
3245
3246 void GuiDocument::bibtexChanged(int n)
3247 {
3248         biblioModule->bibtexOptionsLE->setEnabled(
3249                 biblioModule->bibtexCO->itemData(n).toString() != "default");
3250         biblioChanged();
3251 }
3252
3253
3254 void GuiDocument::updateCiteStyles(vector<string> const & engs, CiteEngineType const & sel)
3255 {
3256         biblioModule->citeStyleCO->clear();
3257
3258         vector<string>::const_iterator it  = engs.begin();
3259         vector<string>::const_iterator end = engs.end();
3260         for (; it != end; ++it) {
3261                 if (*it == "default")
3262                         biblioModule->citeStyleCO->addItem(qt_("Basic numerical"),
3263                                                            ENGINE_TYPE_DEFAULT);
3264                 else if (*it == "authoryear")
3265                         biblioModule->citeStyleCO->addItem(qt_("Author-year"),
3266                                                            ENGINE_TYPE_AUTHORYEAR);
3267                 else if (*it == "numerical")
3268                         biblioModule->citeStyleCO->addItem(qt_("Author-number"),
3269                                                            ENGINE_TYPE_NUMERICAL);
3270         }
3271         int i = biblioModule->citeStyleCO->findData(sel);
3272         if (biblioModule->citeStyleCO->findData(sel) == -1)
3273                 i = 0;
3274         biblioModule->citeStyleCO->setCurrentIndex(i);
3275
3276         biblioModule->citationStyleL->setEnabled(engs.size() > 1);
3277         biblioModule->citeStyleCO->setEnabled(engs.size() > 1);
3278 }
3279
3280
3281 void GuiDocument::updateEngineType(string const & items, CiteEngineType const & sel)
3282 {
3283         engine_types_.clear();
3284
3285         for (int n = 0; !token(items, '|', n).empty(); ++n) {
3286                 string style = token(items, '|', n);
3287                 engine_types_.push_back(style);
3288         }
3289
3290         updateCiteStyles(engine_types_, sel);
3291 }
3292
3293
3294 namespace {
3295         // FIXME unicode
3296         // both of these should take a vector<docstring>
3297
3298         // This is an insanely complicated attempt to make this sort of thing
3299         // work with RTL languages.
3300         docstring formatStrVec(vector<string> const & v, docstring const & s)
3301         {
3302                 //this mess formats the list as "v[0], v[1], ..., [s] v[n]"
3303                 if (v.empty())
3304                         return docstring();
3305                 if (v.size() == 1)
3306                         return translateIfPossible(from_utf8(v[0]));
3307                 if (v.size() == 2) {
3308                         docstring retval = _("%1$s and %2$s");
3309                         retval = subst(retval, _("and"), s);
3310                         return bformat(retval, translateIfPossible(from_utf8(v[0])),
3311                                        translateIfPossible(from_utf8(v[1])));
3312                 }
3313                 // The idea here is to format all but the last two items...
3314                 int const vSize = v.size();
3315                 docstring t2 = _("%1$s, %2$s");
3316                 docstring retval = translateIfPossible(from_utf8(v[0]));
3317                 for (int i = 1; i < vSize - 2; ++i)
3318                         retval = bformat(t2, retval, translateIfPossible(from_utf8(v[i])));
3319                 //...and then to  plug them, and the last two, into this schema
3320                 docstring t = _("%1$s, %2$s, and %3$s");
3321                 t = subst(t, _("and"), s);
3322                 return bformat(t, retval, translateIfPossible(from_utf8(v[vSize - 2])),
3323                                translateIfPossible(from_utf8(v[vSize - 1])));
3324         }
3325
3326         vector<string> idsToNames(vector<string> const & idList)
3327         {
3328                 vector<string> retval;
3329                 vector<string>::const_iterator it  = idList.begin();
3330                 vector<string>::const_iterator end = idList.end();
3331                 for (; it != end; ++it) {
3332                         LyXModule const * const mod = theModuleList[*it];
3333                         if (!mod)
3334                                 retval.push_back(to_utf8(bformat(_("%1$s (unavailable)"),
3335                                                 translateIfPossible(from_utf8(*it)))));
3336                         else
3337                                 retval.push_back(mod->getName());
3338                 }
3339                 return retval;
3340         }
3341 } // end anonymous namespace
3342
3343
3344 void GuiDocument::modulesToParams(BufferParams & bp)
3345 {
3346         // update list of loaded modules
3347         bp.clearLayoutModules();
3348         int const srows = modules_sel_model_.rowCount();
3349         for (int i = 0; i < srows; ++i)
3350                 bp.addLayoutModule(modules_sel_model_.getIDString(i));
3351         updateSelectedModules();
3352
3353         // update the list of removed modules
3354         bp.clearRemovedModules();
3355         LayoutModuleList const & reqmods = bp.baseClass()->defaultModules();
3356         list<string>::const_iterator rit = reqmods.begin();
3357         list<string>::const_iterator ren = reqmods.end();
3358
3359         // check each of the default modules
3360         for (; rit != ren; ++rit) {
3361                 list<string>::const_iterator mit = bp.getModules().begin();
3362                 list<string>::const_iterator men = bp.getModules().end();
3363                 bool found = false;
3364                 for (; mit != men; ++mit) {
3365                         if (*rit == *mit) {
3366                                 found = true;
3367                                 break;
3368                         }
3369                 }
3370                 if (!found) {
3371                         // the module isn't present so must have been removed by the user
3372                         bp.addRemovedModule(*rit);
3373                 }
3374         }
3375 }
3376
3377 void GuiDocument::modulesChanged()
3378 {
3379         modulesToParams(bp_);
3380
3381         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()
3382             && (nonModuleChanged_ || shellescapeChanged_)) {
3383                 int const ret = Alert::prompt(_("Unapplied changes"),
3384                                 _("Some changes in the dialog were not yet applied.\n"
3385                                 "If you do not apply now, they will be lost after this action."),
3386                                 1, 1, _("&Apply"), _("&Dismiss"));
3387                 if (ret == 0)
3388                         applyView();
3389         }
3390
3391         modulesChanged_ = true;
3392         bp_.makeDocumentClass();
3393         paramsToDialog();
3394         changed();
3395 }
3396
3397
3398 void GuiDocument::updateModuleInfo()
3399 {
3400         selectionManager->update();
3401
3402         //Module description
3403         bool const focus_on_selected = selectionManager->selectedFocused();
3404         QAbstractItemView * lv;
3405         bool category = false;
3406         if (focus_on_selected) {
3407                 lv = modulesModule->selectedLV;
3408                 category = true;
3409         } else
3410                 lv = modulesModule->availableLV;
3411         if (lv->selectionModel()->selectedIndexes().isEmpty()) {
3412                 modulesModule->infoML->document()->clear();
3413                 return;
3414         }
3415         QModelIndex const & idx = lv->selectionModel()->currentIndex();
3416
3417         if (!idx.isValid())
3418                 return;
3419
3420         if (!focus_on_selected
3421             && modules_av_model_.itemFromIndex(idx)->hasChildren()) {
3422                 // This is a category header
3423                 modulesModule->infoML->document()->clear();
3424                 return;
3425         }
3426
3427         string const modName = focus_on_selected ?
3428                                 modules_sel_model_.getIDString(idx.row())
3429                               : fromqstr(modules_av_model_.data(idx, Qt::UserRole).toString());
3430         docstring desc = getModuleDescription(modName);
3431
3432         LayoutModuleList const & provmods = bp_.baseClass()->providedModules();
3433         if (std::find(provmods.begin(), provmods.end(), modName) != provmods.end()) {
3434                 if (!desc.empty())
3435                         desc += "\n";
3436                 desc += _("Module provided by document class.");
3437         }
3438
3439         if (category) {
3440                 docstring cat = getModuleCategory(modName);
3441                 if (!cat.empty()) {
3442                         if (!desc.empty())
3443                                 desc += "\n";
3444                         desc += bformat(_("<p><b>Category:</b> %1$s.</p>"),
3445                                         translateIfPossible(cat));
3446                 }
3447         }
3448
3449         vector<string> pkglist = getPackageList(modName);
3450         docstring pkgdesc = formatStrVec(pkglist, _("and"));
3451         if (!pkgdesc.empty()) {
3452                 if (!desc.empty())
3453                         desc += "\n";
3454                 desc += bformat(_("<p><b>Package(s) required:</b> %1$s.</p>"), pkgdesc);
3455         }
3456
3457         pkglist = getRequiredList(modName);
3458         if (!pkglist.empty()) {
3459                 vector<string> const reqdescs = idsToNames(pkglist);
3460                 pkgdesc = formatStrVec(reqdescs, _("or"));
3461                 if (!desc.empty())
3462                         desc += "\n";
3463                 desc += bformat(_("<p><b>Modules required:</b> %1$s.</p>"), pkgdesc);
3464         }
3465
3466         pkglist = getExcludedList(modName);
3467         if (!pkglist.empty()) {
3468                 vector<string> const reqdescs = idsToNames(pkglist);
3469                 pkgdesc = formatStrVec(reqdescs, _( "and"));
3470                 if (!desc.empty())
3471                         desc += "\n";
3472                 desc += bformat(_("<p><b>Modules excluded:</b> %1$s.</p>"), pkgdesc);
3473         }
3474
3475         if (!desc.empty())
3476                 desc += "\n";
3477         desc += bformat(_("<p><b>Filename:</b> <tt>%1$s.module</tt>.</p>"), from_utf8(modName));
3478
3479         if (!isModuleAvailable(modName)) {
3480                 if (!desc.empty())
3481                         desc += "\n";
3482                 desc += _("<p><font color=red><b>WARNING: Some required packages are unavailable!</b></font></p>");
3483         }
3484
3485         modulesModule->infoML->document()->setHtml(toqstr(desc));
3486 }
3487
3488
3489 void GuiDocument::updateNumbering()
3490 {
3491         DocumentClass const & tclass = documentClass();
3492
3493         numberingModule->tocTW->setUpdatesEnabled(false);
3494         numberingModule->tocTW->clear();
3495
3496         int const depth = numberingModule->depthSL->value();
3497         int const toc = numberingModule->tocSL->value();
3498         QString const no = qt_("No");
3499         QString const yes = qt_("Yes");
3500         QTreeWidgetItem * item = nullptr;
3501
3502         DocumentClass::const_iterator lit = tclass.begin();
3503         DocumentClass::const_iterator len = tclass.end();
3504         for (; lit != len; ++lit) {
3505                 int const toclevel = lit->toclevel;
3506                 if (toclevel != Layout::NOT_IN_TOC && !lit->counter.empty()) {
3507                         item = new QTreeWidgetItem(numberingModule->tocTW);
3508                         item->setText(0, toqstr(translateIfPossible(lit->name())));
3509                         item->setText(1, (toclevel <= depth) ? yes : no);
3510                         item->setText(2, (toclevel <= toc) ? yes : no);
3511                 }
3512         }
3513
3514         numberingModule->tocTW->setUpdatesEnabled(true);
3515         numberingModule->tocTW->update();
3516 }
3517
3518
3519 void GuiDocument::getTableStyles()
3520 {
3521         // We look for lyx files in the subdirectory dir of
3522         //   1) user_lyxdir
3523         //   2) build_lyxdir (if not empty)
3524         //   3) system_lyxdir
3525         // in this order. Files with a given sub-hierarchy will
3526         // only be listed once.
3527         // We also consider i18n subdirectories and store them separately.
3528         QStringList dirs;
3529
3530         // The three locations to look at.
3531         string const user = addPath(package().user_support().absFileName(), "tabletemplates");
3532         string const build = addPath(package().build_support().absFileName(), "tabletemplates");
3533         string const system = addPath(package().system_support().absFileName(), "tabletemplates");
3534
3535         dirs << toqstr(user)
3536              << toqstr(build)
3537              << toqstr(system);
3538
3539         for (int i = 0; i < dirs.size(); ++i) {
3540                 QString const & dir = dirs.at(i);
3541                 QDirIterator it(dir, QDir::Files, QDirIterator::Subdirectories);
3542                 while (it.hasNext()) {
3543                         QString fn = QFileInfo(it.next()).fileName();
3544                         if (!fn.endsWith(".lyx") || fn.contains("_1x"))
3545                                 continue;
3546                         QString data = fn.left(fn.lastIndexOf(".lyx"));
3547                         QString guiname = data;
3548                         guiname = toqstr(translateIfPossible(qstring_to_ucs4(guiname.replace('_', ' '))));
3549                         QString relpath = toqstr(makeRelPath(qstring_to_ucs4(fn),
3550                                                              qstring_to_ucs4(dir)));
3551                         if (textLayoutModule->tableStyleCO->findData(data) == -1)
3552                                 textLayoutModule->tableStyleCO->addItem(guiname, data);
3553                 }
3554         }
3555 }
3556
3557
3558 void GuiDocument::updateDefaultFormat()
3559 {
3560         if (!bufferview())
3561                 return;
3562         // make a copy in order to consider unapplied changes
3563         BufferParams param_copy = buffer().params();
3564         param_copy.useNonTeXFonts = fontModule->osFontsCB->isChecked();
3565         int const idx = latexModule->classCO->currentIndex();
3566         if (idx >= 0) {
3567                 string const classname = fromqstr(latexModule->classCO->getData(idx));
3568                 param_copy.setBaseClass(classname, buffer().layoutPos());
3569                 param_copy.makeDocumentClass(true);
3570         }
3571         outputModule->defaultFormatCO->blockSignals(true);
3572         outputModule->defaultFormatCO->clear();
3573         outputModule->defaultFormatCO->addItem(qt_("Default"),
3574                                 QVariant(QString("default")));
3575         FormatList const & formats =
3576                                 param_copy.exportableFormats(true);
3577         for (Format const * f : formats)
3578                 outputModule->defaultFormatCO->addItem
3579                         (toqstr(translateIfPossible(f->prettyname())),
3580                          QVariant(toqstr(f->name())));
3581         outputModule->defaultFormatCO->blockSignals(false);
3582 }
3583
3584
3585 bool GuiDocument::isChildIncluded(string const & child)
3586 {
3587         if (includeonlys_.empty())
3588                 return false;
3589         return (std::find(includeonlys_.begin(),
3590                           includeonlys_.end(), child) != includeonlys_.end());
3591 }
3592
3593
3594 void GuiDocument::applyView()
3595 {
3596         // auto-validate local layout
3597         if (!localLayout->isValid()) {
3598                 localLayout->validate();
3599                 if (!localLayout->isValid()) {
3600                         setApplyStopped(true);
3601                         docPS->setCurrentPanel(N_("Local Layout"));
3602                         return;
3603                 }
3604         }
3605
3606         // preamble
3607         preambleModule->apply(bp_);
3608         localLayout->apply(bp_);
3609
3610         // date
3611         bp_.suppress_date = latexModule->suppressDateCB->isChecked();
3612         bp_.use_refstyle  = latexModule->refstyleCB->isChecked();
3613         bp_.use_formatted_ref  = latexModule->refFormattedCB->isChecked();
3614
3615         // biblio
3616         string const engine =
3617                 fromqstr(biblioModule->citeEngineCO->itemData(
3618                                 biblioModule->citeEngineCO->currentIndex()).toString());
3619         bp_.setCiteEngine(engine);
3620
3621         CiteEngineType const style = CiteEngineType(biblioModule->citeStyleCO->itemData(
3622                 biblioModule->citeStyleCO->currentIndex()).toInt());
3623         if (theCiteEnginesList[engine]->hasEngineType(style))
3624                 bp_.setCiteEngineType(style);
3625         else
3626                 bp_.setCiteEngineType(ENGINE_TYPE_DEFAULT);
3627
3628         bp_.splitbib(biblioModule->bibtopicCB->isChecked());
3629
3630         bp_.multibib = fromqstr(biblioModule->bibunitsCO->itemData(
3631                                 biblioModule->bibunitsCO->currentIndex()).toString());
3632
3633         bp_.setDefaultBiblioStyle(fromqstr(biblioModule->defaultBiblioCO->currentText()));
3634
3635         bp_.biblatex_bibstyle = fromqstr(biblioModule->biblatexBbxCO->currentText());
3636         bp_.biblatex_citestyle = fromqstr(biblioModule->biblatexCbxCO->currentText());
3637         bp_.biblio_opts = fromqstr(biblioModule->citePackageOptionsLE->text());
3638
3639         string const bibtex_command =
3640                 fromqstr(biblioModule->bibtexCO->itemData(
3641                         biblioModule->bibtexCO->currentIndex()).toString());
3642         string const bibtex_options =
3643                 fromqstr(biblioModule->bibtexOptionsLE->text());
3644         if (bibtex_command == "default" || bibtex_options.empty())
3645                 bp_.bibtex_command = bibtex_command;
3646         else
3647                 bp_.bibtex_command = bibtex_command + " " + bibtex_options;
3648
3649         if (biblioChanged_) {
3650                 buffer().invalidateBibinfoCache();
3651                 buffer().removeBiblioTempFiles();
3652         }
3653
3654         // Indices
3655         indicesModule->apply(bp_);
3656
3657         // language & quotes
3658         switch (langModule->encodingCO->currentIndex()) {
3659                 case EncodingSets::unicode: {
3660                         if (!fontModule->osFontsCB->isChecked())
3661                                 bp_.inputenc = fromqstr(langModule->unicodeEncodingCO->itemData(
3662                                         langModule->unicodeEncodingCO->currentIndex()).toString());
3663                         break;
3664                 }
3665                 case EncodingSets::legacy: {
3666                         bp_.inputenc = "auto-legacy";
3667                         bp_.inputenc = fromqstr(langModule->autoEncodingCO->itemData(
3668                                 langModule->autoEncodingCO->currentIndex()).toString());
3669                         break;
3670                 }
3671                 case EncodingSets::custom: {
3672                         bp_.inputenc = fromqstr(langModule->customEncodingCO->itemData(
3673                                 langModule->customEncodingCO->currentIndex()).toString());
3674                         break;
3675                 }
3676                 default:
3677                         // this should never happen
3678                         bp_.inputenc = "utf8";
3679         }
3680         bp_.quotes_style = QuoteStyle(langModule->quoteStyleCO->itemData(
3681                 langModule->quoteStyleCO->currentIndex()).toInt());
3682         bp_.dynamic_quotes = langModule->dynamicQuotesCB->isChecked();
3683
3684         QString const langname = langModule->languageCO->itemData(
3685                 langModule->languageCO->currentIndex()).toString();
3686         Language const * newlang = lyx::languages.getLanguage(fromqstr(langname));
3687         Cursor & cur = const_cast<BufferView *>(bufferview())->cursor();
3688         // If current cursor language was the document language, then update it too.
3689         if (cur.current_font.language() == bp_.language) {
3690                 cur.current_font.setLanguage(newlang);
3691                 cur.real_current_font.setLanguage(newlang);
3692         }
3693         bp_.language = newlang;
3694
3695         QString const pack = langModule->languagePackageCO->itemData(
3696                 langModule->languagePackageCO->currentIndex()).toString();
3697         if (pack == "custom")
3698                 bp_.lang_package =
3699                         fromqstr(langModule->languagePackageLE->text());
3700         else
3701                 bp_.lang_package = fromqstr(pack);
3702
3703         //color
3704         bp_.backgroundcolor = set_backgroundcolor;
3705         bp_.isbackgroundcolor = is_backgroundcolor;
3706         bp_.fontcolor = set_fontcolor;
3707         bp_.isfontcolor = is_fontcolor;
3708         bp_.notefontcolor = set_notefontcolor;
3709         bp_.isnotefontcolor = is_notefontcolor;
3710         if (is_notefontcolor) {
3711                 // Set information used in statusbar (#12130)
3712                 lcolor.setColor("notefontcolor", lyx::X11hexname(set_notefontcolor));
3713                 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
3714         }
3715         bp_.boxbgcolor = set_boxbgcolor;
3716         bp_.isboxbgcolor = is_boxbgcolor;
3717
3718         // numbering
3719         if (bp_.documentClass().hasTocLevels()) {
3720                 bp_.tocdepth = numberingModule->tocSL->value();
3721                 bp_.secnumdepth = numberingModule->depthSL->value();
3722         }
3723         bp_.use_lineno = numberingModule->linenoCB->isChecked();
3724         bp_.lineno_opts = fromqstr(numberingModule->linenoLE->text());
3725
3726         // bullets
3727         bp_.user_defined_bullet(0) = bulletsModule->bullet(0);
3728         bp_.user_defined_bullet(1) = bulletsModule->bullet(1);
3729         bp_.user_defined_bullet(2) = bulletsModule->bullet(2);
3730         bp_.user_defined_bullet(3) = bulletsModule->bullet(3);
3731
3732         // packages
3733         bp_.graphics_driver =
3734                 tex_graphics[latexModule->psdriverCO->currentIndex()];
3735
3736         // text layout
3737         int idx = latexModule->classCO->currentIndex();
3738         if (idx >= 0) {
3739                 string const classname = fromqstr(latexModule->classCO->getData(idx));
3740                 bp_.setBaseClass(classname, buffer().layoutPos());
3741         }
3742
3743         // Modules
3744         modulesToParams(bp_);
3745
3746         // Math
3747         map<string, string> const & packages = BufferParams::auto_packages();
3748         for (map<string, string>::const_iterator it = packages.begin();
3749              it != packages.end(); ++it) {
3750                 QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
3751                 if (!item)
3752                         continue;
3753                 int row = mathsModule->packagesTW->row(item);
3754
3755                 QRadioButton * rb =
3756                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
3757                 if (rb->isChecked()) {
3758                         bp_.use_package(it->first, BufferParams::package_auto);
3759                         continue;
3760                 }
3761                 rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
3762                 if (rb->isChecked()) {
3763                         bp_.use_package(it->first, BufferParams::package_on);
3764                         continue;
3765                 }
3766                 rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
3767                 if (rb->isChecked())
3768                         bp_.use_package(it->first, BufferParams::package_off);
3769         }
3770         // if math is indented
3771         bp_.is_math_indent = mathsModule->MathIndentCB->isChecked();
3772         if (bp_.is_math_indent) {
3773                 // if formulas are indented
3774                 if (mathsModule->MathIndentCO->itemData(mathsModule->MathIndentCO->currentIndex()) == "custom") {
3775                         Length mathindent(widgetsToLength(mathsModule->MathIndentLE,
3776                                                           mathsModule->MathIndentLengthCO));
3777                         bp_.setMathIndent(mathindent);
3778                 } else
3779                         // default
3780                         bp_.setMathIndent(Length());
3781         }
3782         switch (mathsModule->MathNumberingPosCO->currentIndex()) {
3783                 case 0:
3784                         bp_.math_numbering_side = BufferParams::LEFT;
3785                         break;
3786                 case 1:
3787                         bp_.math_numbering_side = BufferParams::DEFAULT;
3788                         break;
3789                 case 2:
3790                         bp_.math_numbering_side = BufferParams::RIGHT;
3791                         break;
3792                 default:
3793                         // this should never happen
3794                         bp_.math_numbering_side = BufferParams::DEFAULT;
3795                         break;
3796         }
3797
3798         // Page Layout
3799         if (pageLayoutModule->pagestyleCO->currentIndex() == 0)
3800                 bp_.pagestyle = "default";
3801         else {
3802                 QString style_gui = pageLayoutModule->pagestyleCO->currentText();
3803                 for (size_t i = 0; i != pagestyles.size(); ++i)
3804                         if (pagestyles[i].second == style_gui)
3805                                 bp_.pagestyle = pagestyles[i].first;
3806         }
3807
3808         // Text Layout
3809         switch (textLayoutModule->lspacingCO->currentIndex()) {
3810         case 0:
3811                 bp_.spacing().set(Spacing::Single);
3812                 break;
3813         case 1:
3814                 bp_.spacing().set(Spacing::Onehalf);
3815                 break;
3816         case 2:
3817                 bp_.spacing().set(Spacing::Double);
3818                 break;
3819         case 3: {
3820                 string s = widgetToDoubleStr(textLayoutModule->lspacingLE);
3821                 if (s.empty())
3822                         bp_.spacing().set(Spacing::Single);
3823                 else
3824                         bp_.spacing().set(Spacing::Other, s);
3825                 break;
3826                 }
3827         }
3828
3829         if (textLayoutModule->twoColumnCB->isChecked())
3830                 bp_.columns = 2;
3831         else
3832                 bp_.columns = 1;
3833
3834         bp_.justification = textLayoutModule->justCB->isChecked();
3835
3836         if (textLayoutModule->indentRB->isChecked()) {
3837                 // if paragraphs are separated by an indentation
3838                 bp_.paragraph_separation = BufferParams::ParagraphIndentSeparation;
3839                 if (textLayoutModule->indentCO->itemData(textLayoutModule->indentCO->currentIndex()) == "custom") {
3840                         Length parindent(widgetsToLength(textLayoutModule->indentLE,
3841                                                          textLayoutModule->indentLengthCO));
3842                         bp_.setParIndent(parindent);
3843                 } else
3844                         // default
3845                         bp_.setParIndent(Length());
3846         } else {
3847                 // if paragraphs are separated by a skip
3848                 bp_.paragraph_separation = BufferParams::ParagraphSkipSeparation;
3849                 VSpace::VSpaceKind spacekind =
3850                         VSpace::VSpaceKind(textLayoutModule->skipCO->itemData(textLayoutModule->skipCO->currentIndex()).toInt());
3851                 switch (spacekind) {
3852                 case VSpace::SMALLSKIP:
3853                 case VSpace::MEDSKIP:
3854                 case VSpace::BIGSKIP:
3855                 case VSpace::HALFLINE:
3856                 case VSpace::FULLLINE:
3857                         bp_.setDefSkip(VSpace(spacekind));
3858                         break;
3859                 case VSpace::LENGTH: {
3860                         VSpace vs = VSpace(
3861                                 widgetsToLength(textLayoutModule->skipLE,
3862                                 textLayoutModule->skipLengthCO)
3863                                 );
3864                         bp_.setDefSkip(vs);
3865                         break;
3866                 }
3867                 default:
3868                         // this should never happen
3869                         bp_.setDefSkip(VSpace(VSpace::MEDSKIP));
3870                         break;
3871                 }
3872         }
3873         bp_.tablestyle = fromqstr(textLayoutModule->tableStyleCO->itemData(
3874                                       textLayoutModule->tableStyleCO->currentIndex()).toString());
3875
3876         bp_.options =
3877                 fromqstr(latexModule->optionsLE->text());
3878
3879         bp_.use_default_options =
3880                 latexModule->defaultOptionsCB->isChecked();
3881
3882         if (latexModule->childDocGB->isChecked())
3883                 bp_.master =
3884                         fromqstr(latexModule->childDocLE->text());
3885         else
3886                 bp_.master = string();
3887
3888         // Master/Child
3889         bp_.clearIncludedChildren();
3890         updateIncludeonlys();
3891         if (masterChildModule->includeonlyRB->isChecked()) {
3892                 list<string>::const_iterator it = includeonlys_.begin();
3893                 for (; it != includeonlys_.end() ; ++it) {
3894                         bp_.addIncludedChildren(*it);
3895                 }
3896         }
3897         if (masterChildModule->maintainCRNoneRB->isChecked())
3898                 bp_.maintain_unincluded_children =
3899                         BufferParams::CM_None;
3900         else if (masterChildModule->maintainCRMostlyRB->isChecked())
3901                 bp_.maintain_unincluded_children =
3902                         BufferParams::CM_Mostly;
3903         else
3904                 bp_.maintain_unincluded_children =
3905                         BufferParams::CM_Strict;
3906         updateIncludeonlyDisplay();
3907
3908         // Float Settings
3909         bp_.float_placement = floatModule->getPlacement();
3910         bp_.float_alignment = floatModule->getAlignment();
3911
3912         // Listings
3913         // text should have passed validation
3914         idx = listingsModule->packageCO->currentIndex();
3915         bp_.use_minted = string(lst_packages[idx]) == "Minted";
3916         bp_.listings_params =
3917                 InsetListingsParams(fromqstr(listingsModule->listingsED->toPlainText())).params();
3918
3919         // Formats
3920         bp_.default_output_format = fromqstr(outputModule->defaultFormatCO->itemData(
3921                 outputModule->defaultFormatCO->currentIndex()).toString());
3922
3923         bool const nontexfonts = fontModule->osFontsCB->isChecked();
3924         bp_.useNonTeXFonts = nontexfonts;
3925
3926         bp_.shell_escape = outputModule->shellescapeCB->isChecked();
3927         if (!bp_.shell_escape)
3928             theSession().shellescapeFiles().remove(buffer().absFileName());
3929         else if (!theSession().shellescapeFiles().find(buffer().absFileName()))
3930             theSession().shellescapeFiles().insert(buffer().absFileName());
3931         Buffer & buf = const_cast<Buffer &>(buffer());
3932         buf.params().shell_escape = bp_.shell_escape;
3933
3934         bp_.output_sync = outputModule->outputsyncCB->isChecked();
3935
3936         bp_.output_sync_macro = fromqstr(outputModule->synccustomCB->currentText());
3937
3938         int mathfmt = outputModule->mathoutCB->currentIndex();
3939         if (mathfmt == -1)
3940                 mathfmt = 0;
3941         BufferParams::MathOutput const mo =
3942                 static_cast<BufferParams::MathOutput>(mathfmt);
3943         bp_.html_math_output = mo;
3944         bp_.html_be_strict = outputModule->strictCB->isChecked();
3945         bp_.html_css_as_file = outputModule->cssCB->isChecked();
3946         bp_.html_math_img_scale = outputModule->mathimgSB->value();
3947         bp_.display_pixel_ratio = theGuiApp()->pixelRatio();
3948
3949         int tablefmt = outputModule->tableoutCB->currentIndex();
3950         if (tablefmt == -1)
3951                 tablefmt = 0;
3952         auto const to = static_cast<BufferParams::TableOutput>(tablefmt);
3953         bp_.docbook_table_output = to;
3954
3955         int mathmlprefix = outputModule->mathmlprefixCB->currentIndex();
3956         if (mathmlprefix == -1)
3957                 mathmlprefix = 0;
3958         auto const mp = static_cast<BufferParams::MathMLNameSpacePrefix>(mathmlprefix);
3959         bp_.docbook_mathml_prefix = mp;
3960
3961         bp_.save_transient_properties =
3962                 outputModule->saveTransientPropertiesCB->isChecked();
3963         bp_.postpone_fragile_content =
3964                 outputModule->postponeFragileCB->isChecked();
3965
3966         // fonts
3967         bp_.fonts_roman[nontexfonts] =
3968                 fromqstr(fontModule->fontsRomanCO->
3969                         getData(fontModule->fontsRomanCO->currentIndex()));
3970         bp_.fonts_roman[!nontexfonts] = fromqstr(fontModule->font_roman);
3971         bp_.font_roman_opts = fromqstr(fontModule->fontspecRomanLE->text());
3972
3973         bp_.fonts_sans[nontexfonts] =
3974                 fromqstr(fontModule->fontsSansCO->
3975                         getData(fontModule->fontsSansCO->currentIndex()));
3976         bp_.fonts_sans[!nontexfonts] = fromqstr(fontModule->font_sans);
3977         bp_.font_sans_opts = fromqstr(fontModule->fontspecSansLE->text());
3978
3979         bp_.fonts_typewriter[nontexfonts] =
3980                 fromqstr(fontModule->fontsTypewriterCO->
3981                         getData(fontModule->fontsTypewriterCO->currentIndex()));
3982         bp_.fonts_typewriter[!nontexfonts] = fromqstr(fontModule->font_typewriter);
3983         bp_.font_typewriter_opts = fromqstr(fontModule->fontspecTypewriterLE->text());
3984
3985         bp_.fonts_math[nontexfonts] =
3986                 fromqstr(fontModule->fontsMathCO->
3987                         itemData(fontModule->fontsMathCO->currentIndex()).toString());
3988         bp_.fonts_math[!nontexfonts] = fromqstr(fontModule->font_math);
3989
3990         QString const fontenc =
3991                 fontModule->fontencCO->itemData(fontModule->fontencCO->currentIndex()).toString();
3992         if (fontenc == "custom")
3993                 bp_.fontenc = fromqstr(fontModule->fontencLE->text());
3994         else
3995                 bp_.fontenc = fromqstr(fontenc);
3996
3997         bp_.fonts_cjk =
3998                 fromqstr(fontModule->cjkFontLE->text());
3999
4000         bp_.use_microtype = fontModule->microtypeCB->isChecked();
4001         bp_.use_dash_ligatures = !fontModule->dashesCB->isChecked();
4002
4003         bp_.fonts_sans_scale[nontexfonts] = fontModule->scaleSansSB->value();
4004         bp_.fonts_sans_scale[!nontexfonts] = fontModule->font_sf_scale;
4005
4006         bp_.fonts_typewriter_scale[nontexfonts] = fontModule->scaleTypewriterSB->value();
4007         bp_.fonts_typewriter_scale[!nontexfonts] = fontModule->font_tt_scale;
4008
4009         bp_.fonts_expert_sc = fontModule->fontScCB->isChecked();
4010
4011         bp_.fonts_roman_osf = fontModule->fontOsfCB->isChecked();
4012         bp_.fonts_sans_osf = fontModule->fontSansOsfCB->isChecked();
4013         bp_.fonts_typewriter_osf = fontModule->fontTypewriterOsfCB->isChecked();
4014
4015         bp_.fonts_default_family = GuiDocument::fontfamilies[
4016                 fontModule->fontsDefaultCO->currentIndex()];
4017
4018         if (fontModule->fontsizeCO->currentIndex() == 0)
4019                 bp_.fontsize = "default";
4020         else
4021                 bp_.fontsize =
4022                         fromqstr(fontModule->fontsizeCO->currentText());
4023
4024         // paper
4025         bp_.papersize = PAPER_SIZE(
4026                 pageLayoutModule->papersizeCO->currentIndex());
4027
4028         bp_.paperwidth = widgetsToLength(pageLayoutModule->paperwidthLE,
4029                 pageLayoutModule->paperwidthUnitCO);
4030
4031         bp_.paperheight = widgetsToLength(pageLayoutModule->paperheightLE,
4032                 pageLayoutModule->paperheightUnitCO);
4033
4034         if (pageLayoutModule->facingPagesCB->isChecked())
4035                 bp_.sides = TwoSides;
4036         else
4037                 bp_.sides = OneSide;
4038
4039         if (pageLayoutModule->landscapeRB->isChecked())
4040                 bp_.orientation = ORIENTATION_LANDSCAPE;
4041         else
4042                 bp_.orientation = ORIENTATION_PORTRAIT;
4043
4044         // margins
4045         bp_.use_geometry = !marginsModule->marginCB->isChecked();
4046
4047         Ui::MarginsUi const * m = marginsModule;
4048
4049         if (bp_.use_geometry) {
4050                 bp_.leftmargin = widgetsToLength(m->innerLE, m->innerUnit);
4051                 bp_.topmargin = widgetsToLength(m->topLE, m->topUnit);
4052                 bp_.rightmargin = widgetsToLength(m->outerLE, m->outerUnit);
4053                 bp_.bottommargin = widgetsToLength(m->bottomLE, m->bottomUnit);
4054                 bp_.headheight = widgetsToLength(m->headheightLE, m->headheightUnit);
4055                 bp_.headsep = widgetsToLength(m->headsepLE, m->headsepUnit);
4056                 bp_.footskip = widgetsToLength(m->footskipLE, m->footskipUnit);
4057                 bp_.columnsep = widgetsToLength(m->columnsepLE, m->columnsepUnit);
4058         }
4059
4060         // branches
4061         branchesModule->apply(bp_);
4062
4063         // PDF support
4064         PDFOptions & pdf = bp_.pdfoptions();
4065         pdf.use_hyperref = pdfSupportModule->use_hyperrefGB->isChecked();
4066         pdf.title = fromqstr(pdfSupportModule->titleLE->text());
4067         pdf.author = fromqstr(pdfSupportModule->authorLE->text());
4068         pdf.subject = fromqstr(pdfSupportModule->subjectLE->text());
4069         pdf.keywords = fromqstr(pdfSupportModule->keywordsLE->text());
4070
4071         pdf.bookmarks = pdfSupportModule->bookmarksGB->isChecked();
4072         pdf.bookmarksnumbered = pdfSupportModule->bookmarksnumberedCB->isChecked();
4073         pdf.bookmarksopen = pdfSupportModule->bookmarksopenGB->isChecked();
4074         pdf.bookmarksopenlevel = pdfSupportModule->bookmarksopenlevelSB->value();
4075
4076         pdf.breaklinks = pdfSupportModule->breaklinksCB->isChecked();
4077         pdf.pdfborder = pdfSupportModule->pdfborderCB->isChecked();
4078         pdf.pdfusetitle = pdfSupportModule->pdfusetitleCB->isChecked();
4079         pdf.colorlinks = pdfSupportModule->colorlinksCB->isChecked();
4080         pdf.backref =
4081                 backref_opts[pdfSupportModule->backrefCO->currentIndex()];
4082         if (pdfSupportModule->fullscreenCB->isChecked())
4083                 pdf.pagemode = pdf.pagemode_fullscreen;
4084         else
4085                 pdf.pagemode.clear();
4086         pdf.quoted_options = pdf.quoted_options_check(
4087                                 fromqstr(pdfSupportModule->optionsTE->toPlainText()));
4088         bp_.document_metadata = qstring_to_ucs4(pdfSupportModule->metadataTE->toPlainText()
4089                                                 .trimmed().replace(QRegularExpression("\n+"), "\n"));
4090
4091         // change tracking
4092         bp_.track_changes = changesModule->trackChangesCB->isChecked();
4093         bp_.output_changes = changesModule->outputChangesCB->isChecked();
4094         bool const cb_switched_off = (bp_.change_bars
4095                                       && !changesModule->changeBarsCB->isChecked());
4096         bp_.change_bars = changesModule->changeBarsCB->isChecked();
4097         if (cb_switched_off)
4098                 // if change bars have been switched off,
4099                 // we need to ditch the aux file
4100                 buffer().requireFreshStart(true);
4101
4102         // reset trackers
4103         nonModuleChanged_ = false;
4104         shellescapeChanged_ = false;
4105 }
4106
4107
4108 void GuiDocument::paramsToDialog()
4109 {
4110         // set the default unit
4111         Length::UNIT const default_unit = Length::defaultUnit();
4112
4113         // preamble
4114         preambleModule->update(bp_, id());
4115         localLayout->update(bp_, id());
4116
4117         // date
4118         latexModule->suppressDateCB->setChecked(bp_.suppress_date);
4119         latexModule->refstyleCB->setChecked(bp_.use_refstyle);
4120         latexModule->refFormattedCB->setChecked(bp_.use_formatted_ref);
4121
4122         // biblio
4123         string const cite_engine = bp_.citeEngine();
4124
4125         biblioModule->citeEngineCO->setCurrentIndex(
4126                 biblioModule->citeEngineCO->findData(toqstr(cite_engine)));
4127
4128         updateEngineType(documentClass().opt_enginetype(),
4129                 bp_.citeEngineType());
4130
4131         checkPossibleCiteEngines();
4132
4133         biblioModule->citeStyleCO->setCurrentIndex(
4134                 biblioModule->citeStyleCO->findData(bp_.citeEngineType()));
4135
4136         biblioModule->bibtopicCB->setChecked(bp_.splitbib());
4137
4138         biblioModule->bibunitsCO->clear();
4139         biblioModule->bibunitsCO->addItem(qt_("No"), QString());
4140         if (documentClass().hasLaTeXLayout("part"))
4141                 biblioModule->bibunitsCO->addItem(qt_("per part"), toqstr("part"));
4142         if (documentClass().hasLaTeXLayout("chapter"))
4143                 biblioModule->bibunitsCO->addItem(qt_("per chapter"), toqstr("chapter"));
4144         if (documentClass().hasLaTeXLayout("section"))
4145                 biblioModule->bibunitsCO->addItem(qt_("per section"), toqstr("section"));
4146         if (documentClass().hasLaTeXLayout("subsection"))
4147                 biblioModule->bibunitsCO->addItem(qt_("per subsection"), toqstr("subsection"));
4148         biblioModule->bibunitsCO->addItem(qt_("per child document"), toqstr("child"));
4149
4150         int const mbpos = biblioModule->bibunitsCO->findData(toqstr(bp_.multibib));
4151         if (mbpos != -1)
4152                 biblioModule->bibunitsCO->setCurrentIndex(mbpos);
4153         else
4154                 biblioModule->bibunitsCO->setCurrentIndex(0);
4155
4156         updateEngineDependends();
4157
4158         if (isBiblatex()) {
4159                 updateDefaultBiblio(bp_.biblatex_bibstyle, "bbx");
4160                 updateDefaultBiblio(bp_.biblatex_citestyle, "cbx");
4161         } else
4162                 updateDefaultBiblio(bp_.defaultBiblioStyle());
4163
4164         biblioModule->citePackageOptionsLE->setText(toqstr(bp_.biblio_opts));
4165
4166         string command;
4167         string options =
4168                 split(bp_.bibtex_command, command, ' ');
4169
4170         int bpos = biblioModule->bibtexCO->findData(toqstr(command));
4171         if (bpos == -1) {
4172                 // We add and set the unknown compiler, indicating that it is unavailable
4173                 // to assure document compilation and for security reasons, a fallback
4174                 // will be used on document processing stage
4175                 biblioModule->bibtexCO->addItem(toqstr(bformat(_("%1$s (not available)"),
4176                                                         from_utf8(command))), toqstr(command));
4177                 bpos = biblioModule->bibtexCO->findData(toqstr(command));
4178         }
4179         biblioModule->bibtexCO->setCurrentIndex(bpos);
4180         biblioModule->bibtexOptionsLE->setText(toqstr(options).trimmed());
4181         biblioModule->bibtexOptionsLE->setEnabled(
4182                 biblioModule->bibtexCO->currentIndex() != 0);
4183
4184         biblioChanged_ = false;
4185
4186         // indices
4187         // We may be called when there is no Buffer, e.g., when
4188         // the last view has just been closed.
4189         bool const isReadOnly = isBufferAvailable() ? buffer().isReadonly() : false;
4190         indicesModule->update(bp_, isReadOnly);
4191
4192         // language & quotes
4193         int const pos = langModule->languageCO->findData(toqstr(
4194                 bp_.language->lang()));
4195         langModule->languageCO->setCurrentIndex(pos);
4196
4197         updateQuoteStyles();
4198
4199         langModule->quoteStyleCO->setCurrentIndex(
4200                 langModule->quoteStyleCO->findData(static_cast<int>(bp_.quotes_style)));
4201         langModule->dynamicQuotesCB->setChecked(bp_.dynamic_quotes);
4202
4203         // LaTeX input encoding: set after the fonts (see below)
4204
4205         int p = langModule->languagePackageCO->findData(toqstr(bp_.lang_package));
4206         if (p == -1) {
4207                 langModule->languagePackageCO->setCurrentIndex(
4208                           langModule->languagePackageCO->findData("custom"));
4209                 langModule->languagePackageLE->setText(toqstr(bp_.lang_package));
4210         } else {
4211                 langModule->languagePackageCO->setCurrentIndex(p);
4212                 langModule->languagePackageLE->clear();
4213         }
4214
4215         //color
4216         if (bp_.isfontcolor) {
4217                 colorModule->mainTextCF->setStyleSheet(
4218                         colorFrameStyleSheet(rgb2qcolor(bp_.fontcolor)));
4219                 colorModule->mainTextCF->setVisible(true);
4220         } else
4221                 colorModule->mainTextCF->setVisible(false);
4222         set_fontcolor = bp_.fontcolor;
4223         is_fontcolor = bp_.isfontcolor;
4224
4225         colorModule->noteFontCF->setStyleSheet(
4226                 colorFrameStyleSheet(rgb2qcolor(bp_.notefontcolor)));
4227         set_notefontcolor = bp_.notefontcolor;
4228         is_notefontcolor = bp_.isnotefontcolor;
4229
4230         if (bp_.isbackgroundcolor) {
4231                 colorModule->pageBackgroundCF->setStyleSheet(
4232                         colorFrameStyleSheet(rgb2qcolor(bp_.backgroundcolor)));
4233                 colorModule->pageBackgroundCF->setVisible(true);
4234         } else
4235                 colorModule->pageBackgroundCF->setVisible(false);
4236         set_backgroundcolor = bp_.backgroundcolor;
4237         is_backgroundcolor = bp_.isbackgroundcolor;
4238
4239         colorModule->boxBackgroundCF->setStyleSheet(
4240                 colorFrameStyleSheet(rgb2qcolor(bp_.boxbgcolor)));
4241         set_boxbgcolor = bp_.boxbgcolor;
4242         is_boxbgcolor = bp_.isboxbgcolor;
4243
4244         // numbering
4245         int const min_toclevel = documentClass().min_toclevel();
4246         int const max_toclevel = documentClass().max_toclevel();
4247         if (documentClass().hasTocLevels()) {
4248                 numberingModule->setEnabled(true);
4249                 numberingModule->depthSL->setMinimum(min_toclevel - 1);
4250                 numberingModule->depthSL->setMaximum(max_toclevel);
4251                 numberingModule->depthSL->setValue(bp_.secnumdepth);
4252                 numberingModule->tocSL->setMaximum(min_toclevel - 1);
4253                 numberingModule->tocSL->setMaximum(max_toclevel);
4254                 numberingModule->tocSL->setValue(bp_.tocdepth);
4255                 updateNumbering();
4256         } else {
4257                 numberingModule->setEnabled(false);
4258                 numberingModule->tocTW->clear();
4259         }
4260
4261         numberingModule->linenoCB->setChecked(bp_.use_lineno);
4262         numberingModule->linenoLE->setEnabled(bp_.use_lineno);
4263         numberingModule->linenoLA->setEnabled(bp_.use_lineno);
4264         numberingModule->linenoLE->setText(toqstr(bp_.lineno_opts));
4265
4266         // bullets
4267         bulletsModule->setBullet(0, bp_.user_defined_bullet(0));
4268         bulletsModule->setBullet(1, bp_.user_defined_bullet(1));
4269         bulletsModule->setBullet(2, bp_.user_defined_bullet(2));
4270         bulletsModule->setBullet(3, bp_.user_defined_bullet(3));
4271         bulletsModule->init();
4272
4273         // packages
4274         int nitem = findToken(tex_graphics, bp_.graphics_driver);
4275         if (nitem >= 0)
4276                 latexModule->psdriverCO->setCurrentIndex(nitem);
4277         updateModuleInfo();
4278
4279         // math
4280         mathsModule->MathIndentCB->setChecked(bp_.is_math_indent);
4281         if (bp_.is_math_indent) {
4282                 Length const mathindent = bp_.getMathIndent();
4283                 int indent = 0;
4284                 if (!mathindent.empty()) {
4285                         lengthToWidgets(mathsModule->MathIndentLE,
4286                                         mathsModule->MathIndentLengthCO,
4287                                         mathindent, default_unit);
4288                         indent = 1;
4289                 }
4290                 mathsModule->MathIndentCO->setCurrentIndex(indent);
4291                 enableMathIndent(indent);
4292         }
4293         switch(bp_.math_numbering_side) {
4294         case BufferParams::LEFT:
4295                 mathsModule->MathNumberingPosCO->setCurrentIndex(0);
4296                 break;
4297         case BufferParams::DEFAULT:
4298                 mathsModule->MathNumberingPosCO->setCurrentIndex(1);
4299                 break;
4300         case BufferParams::RIGHT:
4301                 mathsModule->MathNumberingPosCO->setCurrentIndex(2);
4302         }
4303
4304         map<string, string> const & packages = BufferParams::auto_packages();
4305         for (map<string, string>::const_iterator it = packages.begin();
4306              it != packages.end(); ++it) {
4307                 QTableWidgetItem * item = mathsModule->packagesTW->findItems(toqstr(it->first), Qt::MatchExactly)[0];
4308                 if (!item)
4309                         continue;
4310                 int row = mathsModule->packagesTW->row(item);
4311                 switch (bp_.use_package(it->first)) {
4312                         case BufferParams::package_off: {
4313                                 QRadioButton * rb =
4314                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
4315                                 rb->setChecked(true);
4316                                 break;
4317                         }
4318                         case BufferParams::package_on: {
4319                                 QRadioButton * rb =
4320                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
4321                                 rb->setChecked(true);
4322                                 break;
4323                         }
4324                         case BufferParams::package_auto: {
4325                                 QRadioButton * rb =
4326                                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
4327                                 rb->setChecked(true);
4328                                 break;
4329                         }
4330                 }
4331         }
4332
4333         switch (bp_.spacing().getSpace()) {
4334                 case Spacing::Other: nitem = 3; break;
4335                 case Spacing::Double: nitem = 2; break;
4336                 case Spacing::Onehalf: nitem = 1; break;
4337                 case Spacing::Default: case Spacing::Single: nitem = 0; break;
4338         }
4339
4340         // text layout
4341         string const & layoutID = bp_.baseClassID();
4342         setLayoutComboByIDString(layoutID);
4343
4344         updatePagestyle(documentClass().opt_pagestyle(),
4345                                  bp_.pagestyle);
4346
4347         textLayoutModule->lspacingCO->setCurrentIndex(nitem);
4348         if (bp_.spacing().getSpace() == Spacing::Other) {
4349                 doubleToWidget(textLayoutModule->lspacingLE,
4350                         bp_.spacing().getValueAsString());
4351         }
4352         setLSpacing(nitem);
4353         int ts = textLayoutModule->tableStyleCO->findData(toqstr(bp_.tablestyle));
4354         if (ts != -1)
4355                 textLayoutModule->tableStyleCO->setCurrentIndex(ts);
4356
4357         if (bp_.paragraph_separation == BufferParams::ParagraphIndentSeparation) {
4358                 textLayoutModule->indentRB->setChecked(true);
4359                 string parindent = bp_.getParIndent().asString();
4360                 QString indent = toqstr("default");
4361                 if (!parindent.empty()) {
4362                         lengthToWidgets(textLayoutModule->indentLE,
4363                                         textLayoutModule->indentLengthCO,
4364                                         parindent, default_unit);
4365                         indent = toqstr("custom");
4366                 }
4367                 textLayoutModule->indentCO->setCurrentIndex(textLayoutModule->indentCO->findData(indent));
4368                 setIndent(textLayoutModule->indentCO->currentIndex());
4369         } else {
4370                 textLayoutModule->skipRB->setChecked(true);
4371                 VSpace::VSpaceKind skip = bp_.getDefSkip().kind();
4372                 textLayoutModule->skipCO->setCurrentIndex(textLayoutModule->skipCO->findData(skip));
4373                 if (skip == VSpace::LENGTH) {
4374                         string const length = bp_.getDefSkip().asLyXCommand();
4375                         lengthToWidgets(textLayoutModule->skipLE,
4376                                 textLayoutModule->skipLengthCO,
4377                                 length, default_unit);
4378                 }
4379                 setSkip(textLayoutModule->skipCO->currentIndex());
4380         }
4381
4382         textLayoutModule->twoColumnCB->setChecked(
4383                 bp_.columns == 2);
4384         textLayoutModule->justCB->setChecked(bp_.justification);
4385
4386         if (!bp_.options.empty()) {
4387                 latexModule->optionsLE->setText(
4388                         toqstr(bp_.options));
4389         } else {
4390                 latexModule->optionsLE->setText(QString());
4391         }
4392
4393         // latex
4394         latexModule->defaultOptionsCB->setChecked(
4395                         bp_.use_default_options);
4396         updateSelectedModules();
4397         selectionManager->updateProvidedModules(
4398                         bp_.baseClass()->providedModules());
4399         selectionManager->updateExcludedModules(
4400                         bp_.baseClass()->excludedModules());
4401
4402         if (!documentClass().options().empty()) {
4403                 latexModule->defaultOptionsLE->setText(
4404                         toqstr(documentClass().options()));
4405         } else {
4406                 latexModule->defaultOptionsLE->setText(
4407                         toqstr(_("[No options predefined]")));
4408         }
4409
4410         latexModule->defaultOptionsLE->setEnabled(
4411                 bp_.use_default_options
4412                 && !documentClass().options().empty());
4413
4414         latexModule->defaultOptionsCB->setEnabled(
4415                 !documentClass().options().empty());
4416
4417         if (!bp_.master.empty()) {
4418                 latexModule->childDocGB->setChecked(true);
4419                 latexModule->childDocLE->setText(
4420                         toqstr(bp_.master));
4421         } else {
4422                 latexModule->childDocLE->setText(QString());
4423                 latexModule->childDocGB->setChecked(false);
4424         }
4425
4426         // Master/Child
4427         if (!bufferview() || !buffer().hasChildren()) {
4428                 masterChildModule->childrenTW->clear();
4429                 includeonlys_.clear();
4430                 docPS->showPanel("Child Documents", false);
4431                 if (docPS->isCurrentPanel("Child Documents"))
4432                         docPS->setCurrentPanel("Document Class");
4433         } else {
4434                 docPS->showPanel("Child Documents", true);
4435                 masterChildModule->setEnabled(true);
4436                 includeonlys_ = bp_.getIncludedChildren();
4437                 updateIncludeonlys();
4438                 updateIncludeonlyDisplay();
4439         }
4440         switch (bp_.maintain_unincluded_children) {
4441         case BufferParams::CM_None:
4442                 masterChildModule->maintainCRNoneRB->setChecked(true);
4443                 break;
4444         case BufferParams::CM_Mostly:
4445                 masterChildModule->maintainCRMostlyRB->setChecked(true);
4446                 break;
4447         case BufferParams::CM_Strict:
4448         default:
4449                 masterChildModule->maintainCRStrictRB->setChecked(true);
4450                 break;
4451         }
4452
4453         // Float Settings
4454         floatModule->setPlacement(bp_.float_placement);
4455         floatModule->setAlignment(bp_.float_alignment);
4456
4457         // ListingsSettings
4458         // break listings_params to multiple lines
4459         string lstparams =
4460                 InsetListingsParams(bp_.listings_params).separatedParams();
4461         listingsModule->listingsED->setPlainText(toqstr(lstparams));
4462         int nn = findToken(lst_packages, bp_.use_minted ? "Minted" : "Listings");
4463         if (nn >= 0)
4464                 listingsModule->packageCO->setCurrentIndex(nn);
4465
4466         // Fonts
4467         // some languages only work with Polyglossia (which requires non-TeX fonts)
4468         Language const * lang = lyx::languages.getLanguage(
4469                 fromqstr(langModule->languageCO->itemData(
4470                         langModule->languageCO->currentIndex()).toString()));
4471         bool const need_fontspec =
4472                 lang->babel().empty() && !lang->polyglossia().empty()
4473                 && lang->required() != "CJK" && lang->required() != "japanese";
4474         bool const os_fonts_available =
4475                 bp_.baseClass()->outputType() == lyx::LATEX
4476                 && LaTeXFeatures::isAvailable("fontspec");
4477         fontModule->osFontsCB->setEnabled(os_fonts_available && !need_fontspec);
4478         fontModule->osFontsCB->setChecked(
4479                 (os_fonts_available && bp_.useNonTeXFonts) || need_fontspec);
4480         updateFontsize(documentClass().opt_fontsize(),
4481                         bp_.fontsize);
4482
4483         QString font = toqstr(bp_.fontsRoman());
4484         bool foundfont = fontModule->fontsRomanCO->set(font, false);
4485         if (!foundfont) {
4486                 fontModule->fontsRomanCO->addItemSort(font, font + qt_(" (not installed)"),
4487                                                       qt_("Uninstalled used fonts"),
4488                                                       qt_("This font is not installed and won't be used in output"),
4489                                                       false, false, false, true);
4490                 fontModule->fontsRomanCO->set(font);
4491         }
4492         fontModule->font_roman = toqstr(bp_.fonts_roman[!bp_.useNonTeXFonts]);
4493
4494         font = toqstr(bp_.fontsSans());
4495         foundfont = fontModule->fontsSansCO->set(font, false);
4496         if (!foundfont) {
4497                 fontModule->fontsSansCO->addItemSort(font, font + qt_(" (not installed)"),
4498                                                      qt_("Uninstalled used fonts"),
4499                                                      qt_("This font is not installed and won't be used in output"),
4500                                                      false, false, false, true);
4501                 fontModule->fontsSansCO->set(font);
4502         }
4503         fontModule->font_sans = toqstr(bp_.fonts_sans[!bp_.useNonTeXFonts]);
4504
4505         font = toqstr(bp_.fontsTypewriter());
4506         foundfont = fontModule->fontsTypewriterCO->set(font, false);
4507         if (!foundfont) {
4508                 fontModule->fontsTypewriterCO->addItemSort(font, font + qt_(" (not installed)"),
4509                                                            qt_("Uninstalled used fonts"),
4510                                                            qt_("This font is not installed and won't be used in output"),
4511                                                            false, false, false, true);
4512                 fontModule->fontsTypewriterCO->set(font);
4513         }
4514         fontModule->font_typewriter = toqstr(bp_.fonts_typewriter[!bp_.useNonTeXFonts]);
4515
4516         font = toqstr(bp_.fontsMath());
4517         int mpos = fontModule->fontsMathCO->findData(font);
4518         if (mpos == -1) {
4519                 mpos = fontModule->fontsMathCO->count();
4520                 fontModule->fontsMathCO->addItem(font + qt_(" (not installed)"), font);
4521         }
4522         fontModule->fontsMathCO->setCurrentIndex(mpos);
4523         fontModule->font_math = toqstr(bp_.fonts_math[!bp_.useNonTeXFonts]);
4524
4525         if (bp_.useNonTeXFonts && os_fonts_available) {
4526                 fontModule->fontencLA->setEnabled(false);
4527                 fontModule->fontencCO->setEnabled(false);
4528                 fontModule->fontencLE->setEnabled(false);
4529         } else {
4530                 fontModule->fontencLA->setEnabled(true);
4531                 fontModule->fontencCO->setEnabled(true);
4532                 fontModule->fontencLE->setEnabled(true);
4533                 romanChanged(fontModule->fontsRomanCO->currentIndex());
4534                 sansChanged(fontModule->fontsSansCO->currentIndex());
4535                 ttChanged(fontModule->fontsTypewriterCO->currentIndex());
4536         }
4537         // Handle options enabling
4538         updateFontOptions();
4539
4540         if (!bp_.fonts_cjk.empty())
4541                 fontModule->cjkFontLE->setText(
4542                         toqstr(bp_.fonts_cjk));
4543         else
4544                 fontModule->cjkFontLE->setText(QString());
4545
4546         fontModule->microtypeCB->setChecked(bp_.use_microtype);
4547         fontModule->dashesCB->setChecked(!bp_.use_dash_ligatures);
4548
4549         fontModule->fontScCB->setChecked(bp_.fonts_expert_sc);
4550         fontModule->fontOsfCB->setChecked(bp_.fonts_roman_osf);
4551         fontModule->fontSansOsfCB->setChecked(bp_.fonts_sans_osf);
4552         fontModule->fontTypewriterOsfCB->setChecked(bp_.fonts_typewriter_osf);
4553         fontModule->scaleSansSB->setValue(bp_.fontsSansScale());
4554         fontModule->font_sf_scale = bp_.fonts_sans_scale[!bp_.useNonTeXFonts];
4555         fontModule->scaleTypewriterSB->setValue(bp_.fontsTypewriterScale());
4556         fontModule->font_tt_scale = bp_.fonts_typewriter_scale[!bp_.useNonTeXFonts];
4557         if (!bp_.font_roman_opts.empty())
4558                 fontModule->fontspecRomanLE->setText(
4559                         toqstr(bp_.font_roman_opts));
4560         else
4561                 fontModule->fontspecRomanLE->setText(QString());
4562         if (!bp_.font_sans_opts.empty())
4563                 fontModule->fontspecSansLE->setText(
4564                         toqstr(bp_.font_sans_opts));
4565         else
4566                 fontModule->fontspecSansLE->setText(QString());
4567         if (!bp_.font_typewriter_opts.empty())
4568                 fontModule->fontspecTypewriterLE->setText(
4569                         toqstr(bp_.font_typewriter_opts));
4570         else
4571                 fontModule->fontspecTypewriterLE->setText(QString());
4572
4573         nn = findToken(GuiDocument::fontfamilies, bp_.fonts_default_family);
4574         if (nn >= 0)
4575                 fontModule->fontsDefaultCO->setCurrentIndex(nn);
4576
4577         if (bp_.fontenc == "auto" || bp_.fontenc == "default") {
4578                 fontModule->fontencCO->setCurrentIndex(
4579                         fontModule->fontencCO->findData(toqstr(bp_.fontenc)));
4580                 fontModule->fontencLE->setEnabled(false);
4581         } else {
4582                 fontModule->fontencCO->setCurrentIndex(
4583                                         fontModule->fontencCO->findData("custom"));
4584                 fontModule->fontencLE->setText(toqstr(bp_.fontenc));
4585         }
4586
4587         // LaTeX input encoding
4588         // Set after fonts because non-tex fonts override "\inputencoding".
4589         inputencodingToDialog();
4590
4591         // Formats
4592         // This must be set _after_ fonts since updateDefaultFormat()
4593         // checks osFontsCB settings.
4594         // update combobox with formats
4595         updateDefaultFormat();
4596         int index = outputModule->defaultFormatCO->findData(toqstr(
4597                 bp_.default_output_format));
4598         // set to default if format is not found
4599         if (index == -1)
4600                 index = 0;
4601         outputModule->defaultFormatCO->setCurrentIndex(index);
4602
4603         outputModule->shellescapeCB->setChecked(bp_.shell_escape);
4604         outputModule->outputsyncCB->setChecked(bp_.output_sync);
4605         outputModule->synccustomCB->setEditText(toqstr(bp_.output_sync_macro));
4606         outputModule->synccustomCB->setEnabled(bp_.output_sync);
4607         outputModule->synccustomLA->setEnabled(bp_.output_sync);
4608
4609         outputModule->mathimgSB->setValue(bp_.html_math_img_scale);
4610         outputModule->mathoutCB->setCurrentIndex(bp_.html_math_output);
4611         outputModule->strictCB->setChecked(bp_.html_be_strict);
4612         outputModule->cssCB->setChecked(bp_.html_css_as_file);
4613
4614         outputModule->tableoutCB->setCurrentIndex(bp_.docbook_table_output);
4615         outputModule->mathmlprefixCB->setCurrentIndex(bp_.docbook_mathml_prefix);
4616
4617         outputModule->saveTransientPropertiesCB
4618                 ->setChecked(bp_.save_transient_properties);
4619         outputModule->postponeFragileCB
4620                 ->setChecked(bp_.postpone_fragile_content);
4621
4622         // paper
4623         bool const extern_geometry =
4624                 documentClass().provides("geometry");
4625         int const psize = bp_.papersize;
4626         pageLayoutModule->papersizeCO->setCurrentIndex(psize);
4627         setCustomPapersize(!extern_geometry && psize == 1);
4628         pageLayoutModule->papersizeCO->setEnabled(!extern_geometry);
4629
4630         bool const landscape =
4631                 bp_.orientation == ORIENTATION_LANDSCAPE;
4632         pageLayoutModule->landscapeRB->setChecked(landscape);
4633         pageLayoutModule->portraitRB->setChecked(!landscape);
4634         pageLayoutModule->landscapeRB->setEnabled(!extern_geometry);
4635         pageLayoutModule->portraitRB->setEnabled(!extern_geometry);
4636
4637         pageLayoutModule->facingPagesCB->setChecked(
4638                 bp_.sides == TwoSides);
4639
4640         lengthToWidgets(pageLayoutModule->paperwidthLE,
4641                 pageLayoutModule->paperwidthUnitCO, bp_.paperwidth, default_unit);
4642         lengthToWidgets(pageLayoutModule->paperheightLE,
4643                 pageLayoutModule->paperheightUnitCO, bp_.paperheight, default_unit);
4644
4645         // margins
4646         Ui::MarginsUi * m = marginsModule;
4647
4648         tmp_leftmargin_ = bp_.leftmargin;
4649         tmp_topmargin_ = bp_.topmargin;
4650         tmp_rightmargin_ = bp_.rightmargin;
4651         tmp_bottommargin_ = bp_.bottommargin;
4652         tmp_headheight_ = bp_.headheight;
4653         tmp_headsep_ = bp_.headsep;
4654         tmp_footskip_ = bp_.footskip;
4655         tmp_columnsep_ = bp_.columnsep;
4656
4657         lengthToWidgets(m->topLE, m->topUnit,
4658                 bp_.topmargin, default_unit);
4659         lengthToWidgets(m->bottomLE, m->bottomUnit,
4660                 bp_.bottommargin, default_unit);
4661         lengthToWidgets(m->innerLE, m->innerUnit,
4662                 bp_.leftmargin, default_unit);
4663         lengthToWidgets(m->outerLE, m->outerUnit,
4664                 bp_.rightmargin, default_unit);
4665         lengthToWidgets(m->headheightLE, m->headheightUnit,
4666                 bp_.headheight, default_unit);
4667         lengthToWidgets(m->headsepLE, m->headsepUnit,
4668                 bp_.headsep, default_unit);
4669         lengthToWidgets(m->footskipLE, m->footskipUnit,
4670                 bp_.footskip, default_unit);
4671         lengthToWidgets(m->columnsepLE, m->columnsepUnit,
4672                 bp_.columnsep, default_unit);
4673
4674         setMargins();
4675
4676         // branches
4677         updateUnknownBranches();
4678         branchesModule->update(bp_);
4679
4680         // PDF support
4681         PDFOptions const & pdf = bp_.pdfoptions();
4682         pdfSupportModule->use_hyperrefGB->setChecked(pdf.use_hyperref);
4683         if (bp_.documentClass().provides("hyperref"))
4684                 pdfSupportModule->use_hyperrefGB->setTitle(qt_("C&ustomize Hyperref Options"));
4685         else
4686                 pdfSupportModule->use_hyperrefGB->setTitle(qt_("&Use Hyperref Support"));
4687         pdfSupportModule->titleLE->setText(toqstr(pdf.title));
4688         pdfSupportModule->authorLE->setText(toqstr(pdf.author));
4689         pdfSupportModule->subjectLE->setText(toqstr(pdf.subject));
4690         pdfSupportModule->keywordsLE->setText(toqstr(pdf.keywords));
4691
4692         pdfSupportModule->bookmarksGB->setChecked(pdf.bookmarks);
4693         pdfSupportModule->bookmarksnumberedCB->setChecked(pdf.bookmarksnumbered);
4694         pdfSupportModule->bookmarksopenGB->setChecked(pdf.bookmarksopen);
4695
4696         pdfSupportModule->bookmarksopenlevelSB->setValue(pdf.bookmarksopenlevel);
4697         pdfSupportModule->bookmarksopenlevelSB->setEnabled(pdf.bookmarksopen);
4698         pdfSupportModule->bookmarksopenlevelLA->setEnabled(pdf.bookmarksopen);
4699
4700         pdfSupportModule->breaklinksCB->setChecked(pdf.breaklinks);
4701         pdfSupportModule->pdfborderCB->setChecked(pdf.pdfborder);
4702         pdfSupportModule->pdfusetitleCB->setChecked(pdf.pdfusetitle);
4703         pdfSupportModule->colorlinksCB->setChecked(pdf.colorlinks);
4704
4705         nn = findToken(backref_opts, pdf.backref);
4706         if (nn >= 0)
4707                 pdfSupportModule->backrefCO->setCurrentIndex(nn);
4708
4709         pdfSupportModule->fullscreenCB->setChecked
4710                 (pdf.pagemode == pdf.pagemode_fullscreen);
4711
4712         pdfSupportModule->optionsTE->setPlainText(
4713                 toqstr(pdf.quoted_options));
4714
4715         pdfSupportModule->metadataTE->setPlainText(
4716                 toqstr(rtrim(bp_.document_metadata, "\n")));
4717
4718         // change tracking
4719         changesModule->trackChangesCB->setChecked(bp_.track_changes);
4720         changesModule->outputChangesCB->setChecked(bp_.output_changes);
4721         changesModule->changeBarsCB->setChecked(bp_.change_bars);
4722         changesModule->changeBarsCB->setEnabled(bp_.output_changes);
4723
4724         // Make sure that the bc is in the INITIAL state
4725         if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
4726                 bc().restore();
4727
4728         // clear changed branches cache
4729         changedBranches_.clear();
4730
4731         // re-initiate module filter
4732         if (!filter_->text().isEmpty())
4733                 moduleFilterPressed();
4734
4735         // reset trackers
4736         nonModuleChanged_ = false;
4737         shellescapeChanged_ = false;
4738 }
4739
4740
4741 void GuiDocument::saveDocDefault()
4742 {
4743         // we have to apply the params first
4744         applyView();
4745         saveAsDefault();
4746 }
4747
4748
4749 void GuiDocument::updateAvailableModules()
4750 {
4751         modules_av_model_.clear();
4752         list<modInfoStruct> modInfoList = getModuleInfo();
4753         // Sort names according to the locale
4754         modInfoList.sort([](modInfoStruct const & a, modInfoStruct const & b) {
4755                         return 0 < b.name.localeAwareCompare(a.name);
4756                 });
4757         QIcon user_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-user")
4758                                : getPixmap("images/", "lyxfiles-user", "svgz,png"));
4759         QIcon system_icon(guiApp ? guiApp->getScaledPixmap("images/", "lyxfiles-system")
4760                                  : getPixmap("images/", "lyxfiles-system", "svgz,png"));
4761         int i = 0;
4762         QFont catfont;
4763         catfont.setBold(true);
4764         QBrush unavbrush;
4765         unavbrush.setColor(Qt::gray);
4766         for (modInfoStruct const & m : modInfoList) {
4767                 QStandardItem * item = new QStandardItem();
4768                 QStandardItem * catItem;
4769                 QString const catname = m.category;
4770                 QList<QStandardItem *> fcats = modules_av_model_.findItems(catname, Qt::MatchExactly);
4771                 if (!fcats.empty())
4772                         catItem = fcats.first();
4773                 else {
4774                         catItem = new QStandardItem();
4775                         catItem->setText(catname);
4776                         catItem->setFont(catfont);
4777                         modules_av_model_.insertRow(i, catItem);
4778                         ++i;
4779                 }
4780                 item->setEditable(false);
4781                 catItem->setEditable(false);
4782                 item->setData(m.name, Qt::DisplayRole);
4783                 if (m.missingreqs)
4784                         item->setForeground(unavbrush);
4785                 item->setData(toqstr(m.id), Qt::UserRole);
4786                 item->setData(m.description, Qt::ToolTipRole);
4787                 if (m.local)
4788                         item->setIcon(user_icon);
4789                 else
4790                         item->setIcon(system_icon);
4791                 catItem->appendRow(item);
4792         }
4793         modules_av_model_.sort(0);
4794 }
4795
4796
4797 void GuiDocument::updateSelectedModules()
4798 {
4799         modules_sel_model_.clear();
4800         list<modInfoStruct> const selModList = getSelectedModules();
4801         int i = 0;
4802         for (modInfoStruct const & m : selModList) {
4803                 modules_sel_model_.insertRow(i, m.name, m.id, m.description);
4804                 ++i;
4805         }
4806 }
4807
4808
4809 void GuiDocument::updateIncludeonlyDisplay()
4810 {
4811         if (includeonlys_.empty()) {
4812                 masterChildModule->includeallRB->setChecked(true);
4813                 masterChildModule->childrenTW->setEnabled(false);
4814                 masterChildModule->maintainGB->setEnabled(false);
4815         } else {
4816                 masterChildModule->includeonlyRB->setChecked(true);
4817                 masterChildModule->childrenTW->setEnabled(true);
4818                 masterChildModule->maintainGB->setEnabled(true);
4819         }
4820 }
4821
4822
4823 void GuiDocument::updateIncludeonlys(bool const cleanup)
4824 {
4825         masterChildModule->childrenTW->clear();
4826         QString const no = qt_("No");
4827         QString const yes = qt_("Yes");
4828
4829         ListOfBuffers children = buffer().getChildren();
4830         ListOfBuffers::const_iterator it  = children.begin();
4831         ListOfBuffers::const_iterator end = children.end();
4832         bool has_unincluded = false;
4833         bool all_unincluded = true;
4834         for (; it != end; ++it) {
4835                 QTreeWidgetItem * item = new QTreeWidgetItem(masterChildModule->childrenTW);
4836                 // FIXME Unicode
4837                 string const name =
4838                         to_utf8(makeRelPath(from_utf8((*it)->fileName().absFileName()),
4839                                                         from_utf8(buffer().filePath())));
4840                 item->setText(0, toqstr(name));
4841                 item->setText(1, isChildIncluded(name) ? yes : no);
4842                 if (!isChildIncluded(name))
4843                         has_unincluded = true;
4844                 else
4845                         all_unincluded = false;
4846         }
4847         // Both if all children are included and if none is included
4848         // is equal to "include all" (i.e., omit \includeonly).
4849         if (cleanup && (!has_unincluded || all_unincluded))
4850                 includeonlys_.clear();
4851 }
4852
4853
4854 bool GuiDocument::isBiblatex() const
4855 {
4856         QString const engine =
4857                 biblioModule->citeEngineCO->itemData(
4858                                 biblioModule->citeEngineCO->currentIndex()).toString();
4859
4860         // this can happen if the cite engine is unknown, which can happen
4861         // if one is using a file that came from someone else, etc. in that
4862         // case, we crash if we proceed.
4863         if (engine.isEmpty())
4864             return false;
4865
4866         return theCiteEnginesList[fromqstr(engine)]->getCiteFramework() == "biblatex";
4867 }
4868
4869
4870 void GuiDocument::updateDefaultBiblio(string const & style,
4871                                       string const & which)
4872 {
4873         QString const bibstyle = toqstr(style);
4874         biblioModule->defaultBiblioCO->clear();
4875
4876         int item_nr = -1;
4877
4878         if (isBiblatex()) {
4879                 if (which != "cbx") {
4880                         // First the bbx styles
4881                         biblioModule->biblatexBbxCO->clear();
4882                         QStringList str = texFileList("bbxFiles.lst");
4883                         // test whether we have a valid list, otherwise run rescan
4884                         if (str.isEmpty()) {
4885                                 rescanTexStyles("bbx");
4886                                 str = texFileList("bbxFiles.lst");
4887                         }
4888                         for (int i = 0; i != str.size(); ++i)
4889                                 str[i] = onlyFileName(str[i]);
4890                         // sort on filename only (no path)
4891                         str.sort();
4892
4893                         for (int i = 0; i != str.count(); ++i) {
4894                                 QString item = changeExtension(str[i], "");
4895                                 if (item == bibstyle)
4896                                         item_nr = i;
4897                                 biblioModule->biblatexBbxCO->addItem(item);
4898                         }
4899
4900                         if (item_nr == -1 && !bibstyle.isEmpty()) {
4901                                 biblioModule->biblatexBbxCO->addItem(bibstyle);
4902                                 item_nr = biblioModule->biblatexBbxCO->count() - 1;
4903                         }
4904
4905                         if (item_nr != -1)
4906                                 biblioModule->biblatexBbxCO->setCurrentIndex(item_nr);
4907                         else
4908                                 biblioModule->biblatexBbxCO->clearEditText();
4909                 }
4910
4911                 if (which != "bbx") {
4912                         // now the cbx styles
4913                         biblioModule->biblatexCbxCO->clear();
4914                         QStringList str = texFileList("cbxFiles.lst");
4915                         // test whether we have a valid list, otherwise run rescan
4916                         if (str.isEmpty()) {
4917                                 rescanTexStyles("cbx");
4918                                 str = texFileList("cbxFiles.lst");
4919                         }
4920                         for (int i = 0; i != str.size(); ++i)
4921                                 str[i] = onlyFileName(str[i]);
4922                         // sort on filename only (no path)
4923                         str.sort();
4924
4925                         for (int i = 0; i != str.count(); ++i) {
4926                                 QString item = changeExtension(str[i], "");
4927                                 if (item == bibstyle)
4928                                         item_nr = i;
4929                                 biblioModule->biblatexCbxCO->addItem(item);
4930                         }
4931
4932                         if (item_nr == -1 && !bibstyle.isEmpty()) {
4933                                 biblioModule->biblatexCbxCO->addItem(bibstyle);
4934                                 item_nr = biblioModule->biblatexCbxCO->count() - 1;
4935                         }
4936
4937                         if (item_nr != -1)
4938                                 biblioModule->biblatexCbxCO->setCurrentIndex(item_nr);
4939                         else
4940                                 biblioModule->biblatexCbxCO->clearEditText();
4941                 }
4942         } else {// BibTeX
4943                 biblioModule->biblatexBbxCO->clear();
4944                 biblioModule->biblatexCbxCO->clear();
4945                 QStringList str = texFileList("bstFiles.lst");
4946                 // test whether we have a valid list, otherwise run rescan
4947                 if (str.isEmpty()) {
4948                         rescanTexStyles("bst");
4949                         str = texFileList("bstFiles.lst");
4950                 }
4951                 for (int i = 0; i != str.size(); ++i)
4952                         str[i] = onlyFileName(str[i]);
4953                 // sort on filename only (no path)
4954                 str.sort();
4955
4956                 for (int i = 0; i != str.count(); ++i) {
4957                         QString item = changeExtension(str[i], "");
4958                         if (item == bibstyle)
4959                                 item_nr = i;
4960                         biblioModule->defaultBiblioCO->addItem(item);
4961                 }
4962
4963                 if (item_nr == -1 && !bibstyle.isEmpty()) {
4964                         biblioModule->defaultBiblioCO->addItem(bibstyle);
4965                         item_nr = biblioModule->defaultBiblioCO->count() - 1;
4966                 }
4967
4968                 if (item_nr != -1)
4969                         biblioModule->defaultBiblioCO->setCurrentIndex(item_nr);
4970                 else
4971                         biblioModule->defaultBiblioCO->clearEditText();
4972         }
4973
4974         updateResetDefaultBiblio();
4975 }
4976
4977
4978 void GuiDocument::updateResetDefaultBiblio()
4979 {
4980         QString const engine =
4981                 biblioModule->citeEngineCO->itemData(
4982                                 biblioModule->citeEngineCO->currentIndex()).toString();
4983         CiteEngineType const cet =
4984                 CiteEngineType(biblioModule->citeStyleCO->itemData(
4985                                                           biblioModule->citeStyleCO->currentIndex()).toInt());
4986
4987         string const defbib = theCiteEnginesList[fromqstr(engine)]->getDefaultBiblio(cet);
4988         if (isBiblatex()) {
4989                 QString const bbx = biblioModule->biblatexBbxCO->currentText();
4990                 QString const cbx = biblioModule->biblatexCbxCO->currentText();
4991                 biblioModule->resetCbxPB->setEnabled(defbib != fromqstr(cbx));
4992                 biblioModule->resetBbxPB->setEnabled(defbib != fromqstr(bbx));
4993                 biblioModule->matchBbxPB->setEnabled(bbx != cbx && !cbx.isEmpty()
4994                         && biblioModule->biblatexBbxCO->findText(cbx) != -1);
4995         } else
4996                 biblioModule->resetDefaultBiblioPB->setEnabled(
4997                         defbib != fromqstr(biblioModule->defaultBiblioCO->currentText()));
4998 }
4999
5000
5001 void GuiDocument::matchBiblatexStyles()
5002 {
5003         updateDefaultBiblio(fromqstr(biblioModule->biblatexCbxCO->currentText()), "bbx");
5004         biblioChanged();
5005 }
5006
5007
5008 void GuiDocument::updateContents()
5009 {
5010         // Nothing to do here as the document settings is not cursor dependent.
5011         return;
5012 }
5013
5014
5015 void GuiDocument::useClassDefaults()
5016 {
5017         if (buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
5018                 int const ret = Alert::prompt(_("Unapplied changes"),
5019                                 _("Some changes in the dialog were not yet applied.\n"
5020                                   "If you do not apply now, they will be lost after this action."),
5021                                 1, 1, _("&Apply"), _("&Dismiss"));
5022                 if (ret == 0)
5023                         applyView();
5024         }
5025
5026         int idx = latexModule->classCO->currentIndex();
5027         string const classname = fromqstr(latexModule->classCO->getData(idx));
5028         if (!bp_.setBaseClass(classname, buffer().layoutPos())) {
5029                 Alert::error(_("Error"), _("Unable to set document class."));
5030                 return;
5031         }
5032         bp_.useClassDefaults();
5033         paramsToDialog();
5034         changed();
5035 }
5036
5037
5038 void GuiDocument::setLayoutComboByIDString(string const & idString)
5039 {
5040         if (!latexModule->classCO->set(toqstr(idString)))
5041                 Alert::warning(_("Can't set layout!"),
5042                         bformat(_("Unable to set layout for ID: %1$s"), from_utf8(idString)));
5043 }
5044
5045
5046 bool GuiDocument::isValid()
5047 {
5048         bool const listings_valid = validateListingsParameters().isEmpty();
5049         bool const local_layout_valid = !localLayout->editing();
5050         bool const preamble_valid = !preambleModule->editing();
5051
5052         docPS->markPanelValid(N_("Listings[[inset]]"), listings_valid);
5053         docPS->markPanelValid(N_("Local Layout"), local_layout_valid && localLayout->isValid());
5054         docPS->markPanelValid(N_("LaTeX Preamble"), preamble_valid);
5055         
5056         return listings_valid && local_layout_valid && preamble_valid;
5057 }
5058
5059
5060 char const * const GuiDocument::fontfamilies[5] = {
5061         "default", "rmdefault", "sfdefault", "ttdefault", ""
5062 };
5063
5064
5065 char const * GuiDocument::fontfamilies_gui[5] = {
5066         N_("Default"), N_("Roman"), N_("Sans Serif"), N_("Typewriter"), ""
5067 };
5068
5069
5070 bool GuiDocument::initialiseParams(string const &)
5071 {
5072         BufferView const * view = bufferview();
5073         if (!view) {
5074                 bp_ = BufferParams();
5075                 paramsToDialog();
5076                 return true;
5077         }
5078         prev_buffer_filename_ = view->buffer().absFileName();
5079         bp_ = view->buffer().params();
5080         loadModuleInfo();
5081         updateAvailableModules();
5082         //FIXME It'd be nice to make sure here that the selected
5083         //modules are consistent: That required modules are actually
5084         //selected, and that we don't have conflicts. If so, we could
5085         //at least pop up a warning.
5086         paramsToDialog();
5087         return true;
5088 }
5089
5090
5091 void GuiDocument::clearParams()
5092 {
5093         bp_ = BufferParams();
5094 }
5095
5096
5097 BufferId GuiDocument::id() const
5098 {
5099         BufferView const * const view = bufferview();
5100         return view? &view->buffer() : nullptr;
5101 }
5102
5103
5104 list<GuiDocument::modInfoStruct> const & GuiDocument::getModuleInfo()
5105 {
5106         return moduleNames_;
5107 }
5108
5109
5110 list<GuiDocument::modInfoStruct> const
5111 GuiDocument::makeModuleInfo(LayoutModuleList const & mods)
5112 {
5113         list<modInfoStruct> mInfo;
5114         for (string const & name : mods) {
5115                 modInfoStruct m;
5116                 LyXModule const * const mod = theModuleList[name];
5117                 if (mod)
5118                         m = modInfo(*mod);
5119                 else {
5120                         m.id = name;
5121                         m.name = toqstr(name + " (") + qt_("Not Found") + toqstr(")");
5122                         m.local = false;
5123                         m.missingreqs = true;
5124                 }
5125                 mInfo.push_back(m);
5126         }
5127         return mInfo;
5128 }
5129
5130
5131 list<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
5132 {
5133         return makeModuleInfo(params().getModules());
5134 }
5135
5136
5137 list<GuiDocument::modInfoStruct> const GuiDocument::getProvidedModules()
5138 {
5139         return makeModuleInfo(params().baseClass()->providedModules());
5140 }
5141
5142
5143 DocumentClass const & GuiDocument::documentClass() const
5144 {
5145         return bp_.documentClass();
5146 }
5147
5148
5149 static void dispatch_bufferparams(Dialog const & dialog,
5150         BufferParams const & bp, FuncCode lfun, Buffer const * buf)
5151 {
5152         ostringstream ss;
5153         ss << "\\begin_header\n";
5154         bp.writeFile(ss, buf);
5155         ss << "\\end_header\n";
5156         dialog.dispatch(FuncRequest(lfun, ss.str()));
5157 }
5158
5159
5160 void GuiDocument::dispatchParams()
5161 {
5162         // We need a non-const buffer object.
5163         Buffer & buf = const_cast<BufferView *>(bufferview())->buffer();
5164         // There may be several undo records; group them (bug #8998)
5165         // This handles undo groups automagically
5166         UndoGroupHelper ugh(&buf);
5167
5168         // This must come first so that a language change is correctly noticed
5169         setLanguage();
5170
5171         // We need to load the master before we formally update the params,
5172         // since otherwise we run updateBuffer, etc, before the child's master
5173         // has been set.
5174         if (!params().master.empty()) {
5175                 FileName const master_file = support::makeAbsPath(params().master,
5176                            support::onlyPath(buffer().absFileName()));
5177                 if (isLyXFileName(master_file.absFileName())) {
5178                         Buffer * master = checkAndLoadLyXFile(master_file, true);
5179                         if (master) {
5180                                 if (master->isChild(const_cast<Buffer *>(&buffer())))
5181                                         const_cast<Buffer &>(buffer()).setParent(master);
5182                                 else
5183                                         Alert::warning(_("Assigned master does not include this file"),
5184                                                 bformat(_("You must include this file in the document\n"
5185                                                           "'%1$s' in order to use the master document\n"
5186                                                           "feature."), from_utf8(params().master)));
5187                         } else
5188                                 Alert::warning(_("Could not load master"),
5189                                                 bformat(_("The master document '%1$s'\n"
5190                                                            "could not be loaded."),
5191                                                            from_utf8(params().master)));
5192                 }
5193         }
5194
5195         // Apply the BufferParams. Note that this will set the base class
5196         // and then update the buffer's layout.
5197         dispatch_bufferparams(*this, params(), LFUN_BUFFER_PARAMS_APPLY, &buffer());
5198
5199         // Generate the colours requested by each new branch.
5200         BranchList & branchlist = params().branchlist();
5201         if (!branchlist.empty()) {
5202                 BranchList::const_iterator it = branchlist.begin();
5203                 BranchList::const_iterator const end = branchlist.end();
5204                 for (; it != end; ++it) {
5205                         docstring const & current_branch = it->branch();
5206                         Branch const * branch = branchlist.find(current_branch);
5207                         string const bcolor = branch->color();
5208                         RGBColor rgbcol;
5209                         if (bcolor.size() == 7 && bcolor[0] == '#')
5210                                 rgbcol = lyx::rgbFromHexName(bcolor);
5211                         else
5212                                 guiApp->getRgbColor(lcolor.getFromLyXName(bcolor), rgbcol);
5213                         string const x11hexname = X11hexname(rgbcol);
5214                         // display the new color
5215                         docstring const str = current_branch + ' ' + from_ascii(x11hexname);
5216                         dispatch(FuncRequest(LFUN_SET_COLOR, str));
5217                 }
5218         }
5219         // rename branches in the document
5220         executeBranchRenaming();
5221         // and clear changed branches cache
5222         changedBranches_.clear();
5223
5224         // Generate the colours requested by indices.
5225         IndicesList & indiceslist = params().indiceslist();
5226         if (!indiceslist.empty()) {
5227                 IndicesList::const_iterator it = indiceslist.begin();
5228                 IndicesList::const_iterator const end = indiceslist.end();
5229                 for (; it != end; ++it) {
5230                         docstring const & current_index = it->shortcut();
5231                         Index const * index = indiceslist.findShortcut(current_index);
5232                         string const x11hexname = X11hexname(index->color());
5233                         // display the new color
5234                         docstring const str = current_index + ' ' + from_ascii(x11hexname);
5235                         dispatch(FuncRequest(LFUN_SET_COLOR, str));
5236                 }
5237         }
5238         // FIXME LFUN
5239         // If we used an LFUN, we would not need these two lines:
5240         BufferView * bv = const_cast<BufferView *>(bufferview());
5241         bv->processUpdateFlags(Update::Force | Update::FitCursor);
5242 }
5243
5244
5245 void GuiDocument::setLanguage() const
5246 {
5247         Language const * const newL = bp_.language;
5248         if (buffer().params().language == newL)
5249                 return;
5250
5251         string const & lang_name = newL->lang();
5252         dispatch(FuncRequest(LFUN_BUFFER_LANGUAGE, lang_name));
5253 }
5254
5255
5256 void GuiDocument::saveAsDefault() const
5257 {
5258         dispatch_bufferparams(*this, params(), LFUN_BUFFER_SAVE_AS_DEFAULT, &buffer());
5259 }
5260
5261
5262 bool GuiDocument::providesOSF(QString const & font) const
5263 {
5264         if (fontModule->osFontsCB->isChecked())
5265                 // FIXME: we should check if the fonts really
5266                 // have OSF support. But how?
5267                 return font != "default";
5268         return theLaTeXFonts().getLaTeXFont(
5269                                 qstring_to_ucs4(font)).providesOSF(ot1(),
5270                                                                    completeFontset(),
5271                                                                    noMathFont());
5272 }
5273
5274
5275 bool GuiDocument::providesSC(QString const & font) const
5276 {
5277         if (fontModule->osFontsCB->isChecked())
5278                 return false;
5279         return theLaTeXFonts().getLaTeXFont(
5280                                 qstring_to_ucs4(font)).providesSC(ot1(),
5281                                                                   completeFontset(),
5282                                                                   noMathFont());
5283 }
5284
5285
5286 bool GuiDocument::providesScale(QString const & font) const
5287 {
5288         if (fontModule->osFontsCB->isChecked())
5289                 return font != "default";
5290         return theLaTeXFonts().getLaTeXFont(
5291                                 qstring_to_ucs4(font)).providesScale(ot1(),
5292                                                                      completeFontset(),
5293                                                                      noMathFont());
5294 }
5295
5296
5297 bool GuiDocument::providesExtraOpts(QString const & font) const
5298 {
5299         if (fontModule->osFontsCB->isChecked())
5300                 return font != "default";
5301         return theLaTeXFonts().getLaTeXFont(
5302                                 qstring_to_ucs4(font)).providesMoreOptions(ot1(),
5303                                                                      completeFontset(),
5304                                                                      noMathFont());
5305 }
5306
5307
5308 bool GuiDocument::providesNoMath(QString const & font) const
5309 {
5310         if (fontModule->osFontsCB->isChecked())
5311                 return false;
5312         return theLaTeXFonts().getLaTeXFont(
5313                                 qstring_to_ucs4(font)).providesNoMath(ot1(),
5314                                                                       completeFontset());
5315 }
5316
5317
5318 bool GuiDocument::hasMonolithicExpertSet(QString const & font) const
5319 {
5320         if (fontModule->osFontsCB->isChecked())
5321                 return false;
5322         return theLaTeXFonts().getLaTeXFont(
5323                                 qstring_to_ucs4(font)).hasMonolithicExpertSet(ot1(),
5324                                                                               completeFontset(),
5325                                                                               noMathFont());
5326 }
5327
5328
5329 //static
5330 GuiDocument::modInfoStruct GuiDocument::modInfo(LyXModule const & mod)
5331 {
5332         // FIXME Unicode: docstrings would be better for these parameters but this
5333         // change requires a lot of others
5334         modInfoStruct m;
5335         m.id = mod.getID();
5336         QString const guiname = toqstr(translateIfPossible(from_utf8(mod.getName())));
5337         m.missingreqs = !isModuleAvailable(mod.getID());
5338         if (m.missingreqs) {
5339                 m.name = qt_("%1 (missing req.)").arg(guiname);
5340         } else
5341                 m.name = guiname;
5342         m.category = mod.category().empty() ? qt_("Miscellaneous")
5343                                             : toqstr(translateIfPossible(from_utf8(mod.category())));
5344         QString desc = toqstr(translateIfPossible(from_utf8(mod.getDescription())));
5345         // Find the first sentence of the description
5346         QTextBoundaryFinder bf(QTextBoundaryFinder::Sentence, desc);
5347         int pos = bf.toNextBoundary();
5348         if (pos > 0)
5349                 desc.truncate(pos);
5350         m.local = mod.isLocal();
5351         QString const mtype = m.local ? qt_("personal module") : qt_("distributed module");
5352         QString modulename = qt_("<b>Module name:</b> <i>%1</i> (%2)").arg(toqstr(m.id)).arg(mtype);
5353         // Tooltip is the desc followed by the module name and the type
5354         m.description = QString("%1%2")
5355                 .arg(desc.isEmpty() ? QString() : QString("<p>%1</p>").arg(desc),
5356                      modulename);
5357         if (m.missingreqs)
5358                 m.description += QString("<p>%1</p>").arg(qt_("<b>Note:</b> Some requirements for this module are missing!"));
5359         return m;
5360 }
5361
5362
5363 void GuiDocument::loadModuleInfo()
5364 {
5365         moduleNames_.clear();
5366         for (LyXModule const & mod : theModuleList)
5367                 moduleNames_.push_back(modInfo(mod));
5368 }
5369
5370
5371 void GuiDocument::updateUnknownBranches()
5372 {
5373         if (!bufferview())
5374                 return;
5375         list<docstring> used_branches;
5376         buffer().getUsedBranches(used_branches);
5377         list<docstring>::const_iterator it = used_branches.begin();
5378         QStringList unknown_branches;
5379         for (; it != used_branches.end() ; ++it) {
5380                 if (!buffer().params().branchlist().find(*it))
5381                         unknown_branches.append(toqstr(*it));
5382         }
5383         branchesModule->setUnknownBranches(unknown_branches);
5384 }
5385
5386
5387 void GuiDocument::branchesRename(docstring const & oldname, docstring const & newname)
5388 {
5389         map<docstring, docstring>::iterator it = changedBranches_.begin();
5390         for (; it != changedBranches_.end() ; ++it) {
5391                 if (it->second == oldname) {
5392                         // branch has already been renamed
5393                         it->second = newname;
5394                         return;
5395                 }
5396         }
5397         // store new name
5398         changedBranches_[oldname] = newname;
5399 }
5400
5401
5402 void GuiDocument::executeBranchRenaming() const
5403 {
5404         map<docstring, docstring>::const_iterator it = changedBranches_.begin();
5405         for (; it != changedBranches_.end() ; ++it) {
5406                 docstring const arg = '"' + it->first + '"' + " " + '"' + it->second + '"';
5407                 dispatch(FuncRequest(LFUN_BRANCHES_RENAME, arg));
5408         }
5409 }
5410
5411
5412 void GuiDocument::allPackagesAuto()
5413 {
5414         allPackages(1);
5415 }
5416
5417
5418 void GuiDocument::allPackagesAlways()
5419 {
5420         allPackages(2);
5421 }
5422
5423
5424 void GuiDocument::allPackagesNot()
5425 {
5426         allPackages(3);
5427 }
5428
5429
5430 void GuiDocument::allPackages(int col)
5431 {
5432         for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) {
5433                 QRadioButton * rb =
5434                         (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col)->layout()->itemAt(0)->widget();
5435                 rb->setChecked(true);
5436         }
5437 }
5438
5439
5440 void GuiDocument::linenoToggled(bool on)
5441 {
5442         numberingModule->linenoLE->setEnabled(on);
5443         numberingModule->linenoLA->setEnabled(on);
5444 }
5445
5446
5447 void GuiDocument::outputChangesToggled(bool on)
5448 {
5449         changesModule->changeBarsCB->setEnabled(on);
5450         change_adaptor();
5451 }
5452
5453 void GuiDocument::setOutputSync(bool on)
5454 {
5455         outputModule->synccustomCB->setEnabled(on);
5456         outputModule->synccustomLA->setEnabled(on);
5457         change_adaptor();
5458 }
5459
5460
5461 bool GuiDocument::eventFilter(QObject * sender, QEvent * event)
5462 {
5463         if (event->type() == QEvent::ApplicationPaletteChange) {
5464                 // mode switch: colors need to be updated
5465                 // and the highlighting redone
5466                 if (pdf_options_highlighter_) {
5467                         pdf_options_highlighter_->setupColors();
5468                         pdf_options_highlighter_->rehighlight();
5469                 }
5470                 if (pdf_metadata_highlighter_) {
5471                         pdf_metadata_highlighter_->setupColors();
5472                         pdf_metadata_highlighter_->rehighlight();
5473                 }
5474         }
5475         return QWidget::eventFilter(sender, event);
5476 }
5477
5478
5479 } // namespace frontend
5480 } // namespace lyx
5481
5482 #include "moc_GuiDocument.cpp"