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