]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiPrefs.cpp
Cleanup included headers
[lyx.git] / src / frontends / qt / GuiPrefs.cpp
1 /**
2  * \file GuiPrefs.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Bo Peng
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiPrefs.h"
15
16 #include "ColorCache.h"
17 #include "FileDialog.h"
18 #include "GuiApplication.h"
19 #include "GuiFontExample.h"
20 #include "GuiFontLoader.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiLyXFiles.h"
23 #include "GuiView.h"
24 #include "qt_helpers.h"
25 #include "Validator.h"
26
27 #include "Author.h"
28 #include "BufferList.h"
29 #include "Color.h"
30 #include "ColorSet.h"
31 #include "ConverterCache.h"
32 #include "FontEnums.h"
33 #include "FuncRequest.h"
34 #include "KeySequence.h"
35 #include "Language.h"
36 #include "LyXAction.h"
37 #include "LyX.h"
38 #include "PanelStack.h"
39 #include "Session.h"
40 #include "SpellChecker.h"
41
42 #include "support/debug.h"
43 #include "support/FileName.h"
44 #include "support/filetools.h"
45 #include "support/gettext.h"
46 #include "support/lassert.h"
47 #include "support/lstrings.h"
48 #include "support/Messages.h"
49 #include "support/os.h"
50 #include "support/Package.h"
51
52 #include "frontends/alert.h"
53 #include "frontends/Application.h"
54 #include "frontends/FontLoader.h"
55
56 #include <QAbstractItemModel>
57 #include <QCheckBox>
58 #include <QColorDialog>
59 #include <QFontDatabase>
60 #include <QHeaderView>
61 #include <QLineEdit>
62 #include <QMessageBox>
63 #include <QPushButton>
64 #include <QSpinBox>
65 #include <QString>
66 #include <QTreeWidget>
67 #include <QTreeWidgetItem>
68 #include <QValidator>
69
70 #include <iomanip>
71 #include <sstream>
72 #include <algorithm>
73 #include <math.h>
74
75 using namespace Ui;
76
77 using namespace std;
78 using namespace lyx::support;
79 using namespace lyx::support::os;
80
81 namespace lyx {
82 namespace frontend {
83
84 /////////////////////////////////////////////////////////////////////
85 //
86 // Browser Helpers
87 //
88 /////////////////////////////////////////////////////////////////////
89
90 /** Launch a file dialog and return the chosen file.
91         filename: a suggested filename.
92         title: the title of the dialog.
93         filters: *.ps etc.
94         dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
95 */
96 QString browseFile(QString const & filename,
97         QString const & title,
98         QStringList const & filters,
99         bool save = false,
100         QString const & label1 = QString(),
101         QString const & dir1 = QString(),
102         QString const & label2 = QString(),
103         QString const & dir2 = QString(),
104         QString const & fallback_dir = QString())
105 {
106         QString lastPath = ".";
107         if (!filename.isEmpty())
108                 lastPath = onlyPath(filename);
109         else if(!fallback_dir.isEmpty())
110                 lastPath = fallback_dir;
111
112         FileDialog dlg(title);
113         dlg.setButton1(label1, dir1);
114         dlg.setButton2(label2, dir2);
115
116         FileDialog::Result result;
117
118         if (save)
119                 result = dlg.save(lastPath, filters, onlyFileName(filename));
120         else
121                 result = dlg.open(lastPath, filters, onlyFileName(filename));
122
123         return result.second;
124 }
125
126
127 /** Launch a file dialog and return the chosen directory.
128         pathname: a suggested pathname.
129         title: the title of the dialog.
130         dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
131 */
132 QString browseDir(QString const & pathname,
133         QString const & title,
134         QString const & label1 = QString(),
135         QString const & dir1 = QString(),
136         QString const & label2 = QString(),
137         QString const & dir2 = QString())
138 {
139         QString lastPath = ".";
140         if (!pathname.isEmpty())
141                 lastPath = onlyPath(pathname);
142
143         FileDialog dlg(title);
144         dlg.setButton1(label1, dir1);
145         dlg.setButton2(label2, dir2);
146
147         FileDialog::Result const result =
148                 dlg.opendir(lastPath, onlyFileName(pathname));
149
150         return result.second;
151 }
152
153
154 } // namespace frontend
155
156
157 QString browseRelToParent(QString const & filename, QString const & relpath,
158         QString const & title, QStringList const & filters, bool save,
159         QString const & label1, QString const & dir1,
160         QString const & label2, QString const & dir2)
161 {
162         QString const fname = makeAbsPath(filename, relpath);
163
164         QString const outname =
165                 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
166
167         QString const reloutname =
168                 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
169
170         if (reloutname.startsWith("../"))
171                 return outname;
172         else
173                 return reloutname;
174 }
175
176
177 QString browseRelToSub(QString const & filename, QString const & relpath,
178         QString const & title, QStringList const & filters, bool save,
179         QString const & label1, QString const & dir1,
180         QString const & label2, QString const & dir2)
181 {
182         QString const fname = makeAbsPath(filename, relpath);
183
184         QString const outname =
185                 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
186
187         QString const reloutname =
188                 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
189
190         QString testname = reloutname;
191         testname.remove(QRegExp("^(\\.\\./)+"));
192
193         if (testname.contains("/"))
194                 return outname;
195         else
196                 return reloutname;
197 }
198
199
200
201 /////////////////////////////////////////////////////////////////////
202 //
203 // Helpers
204 //
205 /////////////////////////////////////////////////////////////////////
206
207 namespace frontend {
208
209 QString const catLookAndFeel = N_("Look & Feel");
210 QString const catEditing = N_("Editing");
211 QString const catLanguage = N_("Language Settings");
212 QString const catOutput = N_("Output");
213 QString const catFiles = N_("File Handling");
214
215 static void parseFontName(QString const & mangled0,
216         string & name, string & foundry)
217 {
218         string mangled = fromqstr(mangled0);
219         size_t const idx = mangled.find('[');
220         if (idx == string::npos || idx == 0) {
221                 name = mangled;
222                 foundry.clear();
223         } else {
224                 name = mangled.substr(0, idx - 1);
225                 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
226         }
227 }
228
229
230 static void setComboxFont(QComboBox * cb, string const & family,
231         string const & foundry)
232 {
233         QString fontname = toqstr(family);
234         if (!foundry.empty())
235                 fontname += " [" + toqstr(foundry) + ']';
236
237         for (int i = 0; i != cb->count(); ++i) {
238                 if (cb->itemText(i) == fontname) {
239                         cb->setCurrentIndex(i);
240                         return;
241                 }
242         }
243
244         // Try matching without foundry name
245
246         // We count in reverse in order to prefer the Xft foundry
247         for (int i = cb->count(); --i >= 0;) {
248                 string name, fnt_foundry;
249                 parseFontName(cb->itemText(i), name, fnt_foundry);
250                 if (compare_ascii_no_case(name, family) == 0) {
251                         cb->setCurrentIndex(i);
252                         return;
253                 }
254         }
255
256         // family alone can contain e.g. "Helvetica [Adobe]"
257         string tmpname, tmpfoundry;
258         parseFontName(toqstr(family), tmpname, tmpfoundry);
259
260         // We count in reverse in order to prefer the Xft foundry
261         for (int i = cb->count(); --i >= 0; ) {
262                 string name, fnt_foundry;
263                 parseFontName(cb->itemText(i), name, fnt_foundry);
264                 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
265                         cb->setCurrentIndex(i);
266                         return;
267                 }
268         }
269
270         // Bleh, default fonts, and the names couldn't be found. Hack
271         // for bug 1063.
272
273         QFont font;
274
275         QString const font_family = toqstr(family);
276         if (font_family == guiApp->romanFontName()) {
277                 font.setStyleHint(QFont::Serif);
278                 font.setFamily(font_family);
279         } else if (font_family == guiApp->sansFontName()) {
280                 font.setStyleHint(QFont::SansSerif);
281                 font.setFamily(font_family);
282         } else if (font_family == guiApp->typewriterFontName()) {
283                 font.setStyleHint(QFont::TypeWriter);
284                 font.setFamily(font_family);
285         } else {
286                 LYXERR0("FAILED to find the default font: '"
287                        << foundry << "', '" << family << '\'');
288                 return;
289         }
290
291         QFontInfo info(font);
292         string default_font_name, dummyfoundry;
293         parseFontName(info.family(), default_font_name, dummyfoundry);
294         LYXERR0("Apparent font is " << default_font_name);
295
296         for (int i = 0; i < cb->count(); ++i) {
297                 LYXERR0("Looking at " << cb->itemText(i));
298                 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
299                                     default_font_name) == 0) {
300                         cb->setCurrentIndex(i);
301                         return;
302                 }
303         }
304
305         LYXERR0("FAILED to find the font: '"
306                << foundry << "', '" << family << '\'');
307 }
308
309
310 /////////////////////////////////////////////////////////////////////
311 //
312 // PrefOutput
313 //
314 /////////////////////////////////////////////////////////////////////
315
316 PrefOutput::PrefOutput(GuiPreferences * form)
317         : PrefModule(catOutput, N_("General[[settings]]"), form)
318 {
319         setupUi(this);
320
321         dviCB->setValidator(new NoNewLineValidator(dviCB));
322         pdfCB->setValidator(new NoNewLineValidator(pdfCB));
323
324         connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
325                 this, SIGNAL(changed()));
326         connect(overwriteCO, SIGNAL(activated(int)),
327                 this, SIGNAL(changed()));
328         connect(dviCB, SIGNAL(editTextChanged(QString)),
329                 this, SIGNAL(changed()));
330         connect(pdfCB, SIGNAL(editTextChanged(QString)),
331                 this, SIGNAL(changed()));
332         connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
333                 this, SIGNAL(changed()));
334         connect(printerLandscapeED, SIGNAL(textChanged(QString)),
335                 this, SIGNAL(changed()));
336         connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
337                 this, SIGNAL(changed()));
338
339         printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
340         printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
341         printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
342
343         dviCB->addItem("");
344         dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
345         dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
346         dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
347         dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
348         pdfCB->addItem("");
349         pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
350         pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
351         pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
352         pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
353         pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
354         pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
355         pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
356 }
357
358
359 void PrefOutput::applyRC(LyXRC & rc) const
360 {
361         rc.plaintext_linelen = plaintextLinelengthSB->value();
362         rc.forward_search_dvi = fromqstr(dviCB->currentText());
363         rc.forward_search_pdf = fromqstr(pdfCB->currentText());
364
365         switch (overwriteCO->currentIndex()) {
366         case 0:
367                 rc.export_overwrite = NO_FILES;
368                 break;
369         case 1:
370                 rc.export_overwrite = MAIN_FILE;
371                 break;
372         case 2:
373                 rc.export_overwrite = ALL_FILES;
374                 break;
375         }
376
377         rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
378         rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
379         rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
380 }
381
382
383 void PrefOutput::updateRC(LyXRC const & rc)
384 {
385         plaintextLinelengthSB->setValue(rc.plaintext_linelen);
386         dviCB->setEditText(toqstr(rc.forward_search_dvi));
387         pdfCB->setEditText(toqstr(rc.forward_search_pdf));
388
389         switch (rc.export_overwrite) {
390         case NO_FILES:
391                 overwriteCO->setCurrentIndex(0);
392                 break;
393         case MAIN_FILE:
394                 overwriteCO->setCurrentIndex(1);
395                 break;
396         case ALL_FILES:
397                 overwriteCO->setCurrentIndex(2);
398                 break;
399         }
400
401         printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
402         printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
403         printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
404 }
405
406
407 /////////////////////////////////////////////////////////////////////
408 //
409 // PrefInput
410 //
411 /////////////////////////////////////////////////////////////////////
412
413 PrefInput::PrefInput(GuiPreferences * form)
414         : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
415 {
416         setupUi(this);
417
418         connect(keymapCB, SIGNAL(clicked()),
419                 this, SIGNAL(changed()));
420         connect(firstKeymapED, SIGNAL(textChanged(QString)),
421                 this, SIGNAL(changed()));
422         connect(secondKeymapED, SIGNAL(textChanged(QString)),
423                 this, SIGNAL(changed()));
424         connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
425                 this, SIGNAL(changed()));
426         connect(scrollzoomEnableCB, SIGNAL(clicked()),
427                 this, SIGNAL(changed()));
428         connect(scrollzoomValueCO, SIGNAL(activated(int)),
429                 this, SIGNAL(changed()));
430         connect(dontswapCB, SIGNAL(toggled(bool)),
431                 this, SIGNAL(changed()));
432         connect(mmPasteCB, SIGNAL(toggled(bool)),
433                 this, SIGNAL(changed()));
434
435         // reveal checkbox for switching Ctrl and Meta on Mac:
436         bool swapcb = false;
437 #ifdef Q_OS_MAC
438 #if QT_VERSION > 0x040600
439         swapcb = true;
440 #endif
441 #endif
442         dontswapCB->setVisible(swapcb);
443 }
444
445
446 void PrefInput::applyRC(LyXRC & rc) const
447 {
448         // FIXME: can derive CB from the two EDs
449         rc.use_kbmap = keymapCB->isChecked();
450         rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
451         rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
452         rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
453         if (scrollzoomEnableCB->isChecked()) {
454                 switch (scrollzoomValueCO->currentIndex()) {
455                 case 0:
456                         rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
457                         break;
458                 case 1:
459                         rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
460                         break;
461                 case 2:
462                         rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
463                         break;
464                 }
465         } else {
466                 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
467         }
468         rc.mac_dontswap_ctrl_meta  = dontswapCB->isChecked();
469         rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
470 }
471
472
473 void PrefInput::updateRC(LyXRC const & rc)
474 {
475         // FIXME: can derive CB from the two EDs
476         keymapCB->setChecked(rc.use_kbmap);
477         firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
478         secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
479         mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
480         switch (rc.scroll_wheel_zoom) {
481         case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
482                 scrollzoomEnableCB->setChecked(false);
483                 break;
484         case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
485                 scrollzoomEnableCB->setChecked(true);
486                 scrollzoomValueCO->setCurrentIndex(0);
487                 break;
488         case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
489                 scrollzoomEnableCB->setChecked(true);
490                 scrollzoomValueCO->setCurrentIndex(1);
491                 break;
492         case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
493                 scrollzoomEnableCB->setChecked(true);
494                 scrollzoomValueCO->setCurrentIndex(2);
495                 break;
496         }
497         dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
498         mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
499 }
500
501
502 QString PrefInput::testKeymap(QString const & keymap)
503 {
504         return form_->browsekbmap(internalPath(keymap));
505 }
506
507
508 void PrefInput::on_firstKeymapPB_clicked(bool)
509 {
510         QString const file = testKeymap(firstKeymapED->text());
511         if (!file.isEmpty())
512                 firstKeymapED->setText(file);
513 }
514
515
516 void PrefInput::on_secondKeymapPB_clicked(bool)
517 {
518         QString const file = testKeymap(secondKeymapED->text());
519         if (!file.isEmpty())
520                 secondKeymapED->setText(file);
521 }
522
523
524 void PrefInput::on_keymapCB_toggled(bool keymap)
525 {
526         firstKeymapLA->setEnabled(keymap);
527         secondKeymapLA->setEnabled(keymap);
528         firstKeymapED->setEnabled(keymap);
529         secondKeymapED->setEnabled(keymap);
530         firstKeymapPB->setEnabled(keymap);
531         secondKeymapPB->setEnabled(keymap);
532 }
533
534
535 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
536 {
537         scrollzoomValueCO->setEnabled(enabled);
538 }
539
540
541 /////////////////////////////////////////////////////////////////////
542 //
543 // PrefCompletion
544 //
545 /////////////////////////////////////////////////////////////////////
546
547 PrefCompletion::PrefCompletion(GuiPreferences * form)
548         : PrefModule(catEditing, N_("Input Completion"), form)
549 {
550         setupUi(this);
551
552         connect(inlineDelaySB, SIGNAL(valueChanged(double)),
553                 this, SIGNAL(changed()));
554         connect(inlineMathCB, SIGNAL(clicked()),
555                 this, SIGNAL(changed()));
556         connect(inlineTextCB, SIGNAL(clicked()),
557                 this, SIGNAL(changed()));
558         connect(inlineDotsCB, SIGNAL(clicked()),
559                 this, SIGNAL(changed()));
560         connect(popupDelaySB, SIGNAL(valueChanged(double)),
561                 this, SIGNAL(changed()));
562         connect(popupMathCB, SIGNAL(clicked()),
563                 this, SIGNAL(changed()));
564         connect(autocorrectionCB, SIGNAL(clicked()),
565                 this, SIGNAL(changed()));
566         connect(popupTextCB, SIGNAL(clicked()),
567                 this, SIGNAL(changed()));
568         connect(popupAfterCompleteCB, SIGNAL(clicked()),
569                 this, SIGNAL(changed()));
570         connect(cursorTextCB, SIGNAL(clicked()),
571                 this, SIGNAL(changed()));
572         connect(minlengthSB, SIGNAL(valueChanged(int)),
573                         this, SIGNAL(changed()));
574 }
575
576
577 void PrefCompletion::on_inlineTextCB_clicked()
578 {
579         enableCB();
580 }
581
582
583 void PrefCompletion::on_popupTextCB_clicked()
584 {
585         enableCB();
586 }
587
588
589 void PrefCompletion::enableCB()
590 {
591         cursorTextCB->setEnabled(
592                 popupTextCB->isChecked() || inlineTextCB->isChecked());
593 }
594
595
596 void PrefCompletion::applyRC(LyXRC & rc) const
597 {
598         rc.completion_inline_delay = inlineDelaySB->value();
599         rc.completion_inline_math = inlineMathCB->isChecked();
600         rc.completion_inline_text = inlineTextCB->isChecked();
601         rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
602         rc.completion_popup_delay = popupDelaySB->value();
603         rc.completion_popup_math = popupMathCB->isChecked();
604         rc.autocorrection_math = autocorrectionCB->isChecked();
605         rc.completion_popup_text = popupTextCB->isChecked();
606         rc.completion_cursor_text = cursorTextCB->isChecked();
607         rc.completion_popup_after_complete =
608                 popupAfterCompleteCB->isChecked();
609         rc.completion_minlength = minlengthSB->value();
610 }
611
612
613 void PrefCompletion::updateRC(LyXRC const & rc)
614 {
615         inlineDelaySB->setValue(rc.completion_inline_delay);
616         inlineMathCB->setChecked(rc.completion_inline_math);
617         inlineTextCB->setChecked(rc.completion_inline_text);
618         inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
619         popupDelaySB->setValue(rc.completion_popup_delay);
620         popupMathCB->setChecked(rc.completion_popup_math);
621         autocorrectionCB->setChecked(rc.autocorrection_math);
622         popupTextCB->setChecked(rc.completion_popup_text);
623         cursorTextCB->setChecked(rc.completion_cursor_text);
624         popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
625         enableCB();
626         minlengthSB->setValue(rc.completion_minlength);
627 }
628
629
630
631 /////////////////////////////////////////////////////////////////////
632 //
633 // PrefLatex
634 //
635 /////////////////////////////////////////////////////////////////////
636
637 PrefLatex::PrefLatex(GuiPreferences * form)
638         : PrefModule(catOutput, N_("LaTeX"), form)
639 {
640         setupUi(this);
641
642         latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
643         latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
644         latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
645         latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
646         latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
647         latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
648         latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
649
650         connect(latexChecktexED, SIGNAL(textChanged(QString)),
651                 this, SIGNAL(changed()));
652         connect(latexBibtexCO, SIGNAL(activated(int)),
653                 this, SIGNAL(changed()));
654         connect(latexBibtexED, SIGNAL(textChanged(QString)),
655                 this, SIGNAL(changed()));
656         connect(latexJBibtexCO, SIGNAL(activated(int)),
657                 this, SIGNAL(changed()));
658         connect(latexJBibtexED, SIGNAL(textChanged(QString)),
659                 this, SIGNAL(changed()));
660         connect(latexIndexCO, SIGNAL(activated(int)),
661                 this, SIGNAL(changed()));
662         connect(latexIndexED, SIGNAL(textChanged(QString)),
663                 this, SIGNAL(changed()));
664         connect(latexJIndexED, SIGNAL(textChanged(QString)),
665                 this, SIGNAL(changed()));
666         connect(latexAutoresetCB, SIGNAL(clicked()),
667                 this, SIGNAL(changed()));
668         connect(latexDviPaperED, SIGNAL(textChanged(QString)),
669                 this, SIGNAL(changed()));
670         connect(latexNomenclED, SIGNAL(textChanged(QString)),
671                 this, SIGNAL(changed()));
672
673 #if defined(__CYGWIN__) || defined(_WIN32)
674         pathCB->setVisible(true);
675         connect(pathCB, SIGNAL(clicked()),
676                 this, SIGNAL(changed()));
677 #else
678         pathCB->setVisible(false);
679 #endif
680 }
681
682
683 void PrefLatex::on_latexBibtexCO_activated(int n)
684 {
685         QString const bibtex = latexBibtexCO->itemData(n).toString();
686         if (bibtex.isEmpty()) {
687                 latexBibtexED->clear();
688                 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
689                 return;
690         }
691         for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
692              it != bibtex_alternatives.end(); ++it) {
693                 QString const bib = toqstr(*it);
694                 int ind = bib.indexOf(" ");
695                 QString sel_command = bib.left(ind);
696                 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
697                 if (bibtex == sel_command) {
698                         if (ind < 0)
699                                 latexBibtexED->clear();
700                         else
701                                 latexBibtexED->setText(sel_options.trimmed());
702                 }
703         }
704         latexBibtexOptionsLA->setText(qt_("&Options:"));
705 }
706
707
708 void PrefLatex::on_latexJBibtexCO_activated(int n)
709 {
710         QString const jbibtex = latexJBibtexCO->itemData(n).toString();
711         if (jbibtex.isEmpty()) {
712                 latexJBibtexED->clear();
713                 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
714                 return;
715         }
716         for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
717              it != jbibtex_alternatives.end(); ++it) {
718                 QString const bib = toqstr(*it);
719                 int ind = bib.indexOf(" ");
720                 QString sel_command = bib.left(ind);
721                 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
722                 if (jbibtex == sel_command) {
723                         if (ind < 0)
724                                 latexJBibtexED->clear();
725                         else
726                                 latexJBibtexED->setText(sel_options.trimmed());
727                 }
728         }
729         latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
730 }
731
732
733 void PrefLatex::on_latexIndexCO_activated(int n)
734 {
735         QString const index = latexIndexCO->itemData(n).toString();
736         if (index.isEmpty()) {
737                 latexIndexED->clear();
738                 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
739                 return;
740         }
741         for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
742              it != index_alternatives.end(); ++it) {
743                 QString const idx = toqstr(*it);
744                 int ind = idx.indexOf(" ");
745                 QString sel_command = idx.left(ind);
746                 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
747                 if (index == sel_command) {
748                         if (ind < 0)
749                                 latexIndexED->clear();
750                         else
751                                 latexIndexED->setText(sel_options.trimmed());
752                 }
753         }
754         latexIndexOptionsLA->setText(qt_("Op&tions:"));
755 }
756
757
758 void PrefLatex::applyRC(LyXRC & rc) const
759 {
760         // If bibtex is not empty, bibopt contains the options, otherwise
761         // it is a customized bibtex command with options.
762         QString const bibtex = latexBibtexCO->itemData(
763                 latexBibtexCO->currentIndex()).toString();
764         QString const bibopt = latexBibtexED->text();
765         if (bibtex.isEmpty())
766                 rc.bibtex_command = fromqstr(bibopt);
767         else if (bibopt.isEmpty())
768                 rc.bibtex_command = fromqstr(bibtex);
769         else
770                 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
771
772         // If jbibtex is not empty, jbibopt contains the options, otherwise
773         // it is a customized bibtex command with options.
774         QString const jbibtex = latexJBibtexCO->itemData(
775                 latexJBibtexCO->currentIndex()).toString();
776         QString const jbibopt = latexJBibtexED->text();
777         if (jbibtex.isEmpty())
778                 rc.jbibtex_command = fromqstr(jbibopt);
779         else if (jbibopt.isEmpty())
780                 rc.jbibtex_command = fromqstr(jbibtex);
781         else
782                 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
783
784         // If index is not empty, idxopt contains the options, otherwise
785         // it is a customized index command with options.
786         QString const index = latexIndexCO->itemData(
787                 latexIndexCO->currentIndex()).toString();
788         QString const idxopt = latexIndexED->text();
789         if (index.isEmpty())
790                 rc.index_command = fromqstr(idxopt);
791         else if (idxopt.isEmpty())
792                 rc.index_command = fromqstr(index);
793         else
794                 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
795
796         rc.chktex_command = fromqstr(latexChecktexED->text());
797         rc.jindex_command = fromqstr(latexJIndexED->text());
798         rc.nomencl_command = fromqstr(latexNomenclED->text());
799         rc.auto_reset_options = latexAutoresetCB->isChecked();
800         rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
801 #if defined(__CYGWIN__) || defined(_WIN32)
802         rc.windows_style_tex_paths = pathCB->isChecked();
803 #endif
804 }
805
806
807 void PrefLatex::updateRC(LyXRC const & rc)
808 {
809         latexBibtexCO->clear();
810
811         latexBibtexCO->addItem(qt_("Automatic"), "automatic");
812         latexBibtexCO->addItem(qt_("Custom"), QString());
813         for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
814                              it != rc.bibtex_alternatives.end(); ++it) {
815                 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
816                 latexBibtexCO->addItem(command, command);
817         }
818
819         bibtex_alternatives = rc.bibtex_alternatives;
820
821         QString const bib = toqstr(rc.bibtex_command);
822         int ind = bib.indexOf(" ");
823         QString sel_command = bib.left(ind);
824         QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
825
826         int pos = latexBibtexCO->findData(sel_command);
827         if (pos != -1) {
828                 latexBibtexCO->setCurrentIndex(pos);
829                 latexBibtexED->setText(sel_options.trimmed());
830                 latexBibtexOptionsLA->setText(qt_("&Options:"));
831         } else {
832                 latexBibtexED->setText(toqstr(rc.bibtex_command));
833                 latexBibtexCO->setCurrentIndex(0);
834                 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
835         }
836
837         latexJBibtexCO->clear();
838
839         latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
840         latexJBibtexCO->addItem(qt_("Custom"), QString());
841         for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
842                              it != rc.jbibtex_alternatives.end(); ++it) {
843                 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
844                 latexJBibtexCO->addItem(command, command);
845         }
846
847         jbibtex_alternatives = rc.jbibtex_alternatives;
848
849         QString const jbib = toqstr(rc.jbibtex_command);
850         ind = jbib.indexOf(" ");
851         sel_command = jbib.left(ind);
852         sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
853
854         pos = latexJBibtexCO->findData(sel_command);
855         if (pos != -1) {
856                 latexJBibtexCO->setCurrentIndex(pos);
857                 latexJBibtexED->setText(sel_options.trimmed());
858                 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
859         } else {
860                 latexJBibtexED->setText(toqstr(rc.bibtex_command));
861                 latexJBibtexCO->setCurrentIndex(0);
862                 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
863         }
864
865         latexIndexCO->clear();
866
867         latexIndexCO->addItem(qt_("Custom"), QString());
868         for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
869                              it != rc.index_alternatives.end(); ++it) {
870                 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
871                 latexIndexCO->addItem(command, command);
872         }
873
874         index_alternatives = rc.index_alternatives;
875
876         QString const idx = toqstr(rc.index_command);
877         ind = idx.indexOf(" ");
878         sel_command = idx.left(ind);
879         sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
880
881         pos = latexIndexCO->findData(sel_command);
882         if (pos != -1) {
883                 latexIndexCO->setCurrentIndex(pos);
884                 latexIndexED->setText(sel_options.trimmed());
885                 latexIndexOptionsLA->setText(qt_("Op&tions:"));
886         } else {
887                 latexIndexED->setText(toqstr(rc.index_command));
888                 latexIndexCO->setCurrentIndex(0);
889                 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
890         }
891
892         latexChecktexED->setText(toqstr(rc.chktex_command));
893         latexJIndexED->setText(toqstr(rc.jindex_command));
894         latexNomenclED->setText(toqstr(rc.nomencl_command));
895         latexAutoresetCB->setChecked(rc.auto_reset_options);
896         latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
897 #if defined(__CYGWIN__) || defined(_WIN32)
898         pathCB->setChecked(rc.windows_style_tex_paths);
899 #endif
900 }
901
902
903 /////////////////////////////////////////////////////////////////////
904 //
905 // PrefScreenFonts
906 //
907 /////////////////////////////////////////////////////////////////////
908
909 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
910         : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
911 {
912         setupUi(this);
913
914         connect(screenRomanCO, SIGNAL(activated(QString)),
915                 this, SLOT(selectRoman(QString)));
916         connect(screenSansCO, SIGNAL(activated(QString)),
917                 this, SLOT(selectSans(QString)));
918         connect(screenTypewriterCO, SIGNAL(activated(QString)),
919                 this, SLOT(selectTypewriter(QString)));
920
921         QFontDatabase fontdb;
922         QStringList families(fontdb.families());
923         for (auto const & family : families) {
924                 screenRomanCO->addItem(family);
925                 screenSansCO->addItem(family);
926                 screenTypewriterCO->addItem(family);
927         }
928         connect(screenRomanCO, SIGNAL(activated(QString)),
929                 this, SIGNAL(changed()));
930         connect(screenSansCO, SIGNAL(activated(QString)),
931                 this, SIGNAL(changed()));
932         connect(screenTypewriterCO, SIGNAL(activated(QString)),
933                 this, SIGNAL(changed()));
934         connect(screenZoomSB, SIGNAL(valueChanged(int)),
935                 this, SIGNAL(changed()));
936         connect(screenTinyED, SIGNAL(textChanged(QString)),
937                 this, SIGNAL(changed()));
938         connect(screenSmallestED, SIGNAL(textChanged(QString)),
939                 this, SIGNAL(changed()));
940         connect(screenSmallerED, SIGNAL(textChanged(QString)),
941                 this, SIGNAL(changed()));
942         connect(screenSmallED, SIGNAL(textChanged(QString)),
943                 this, SIGNAL(changed()));
944         connect(screenNormalED, SIGNAL(textChanged(QString)),
945                 this, SIGNAL(changed()));
946         connect(screenLargeED, SIGNAL(textChanged(QString)),
947                 this, SIGNAL(changed()));
948         connect(screenLargerED, SIGNAL(textChanged(QString)),
949                 this, SIGNAL(changed()));
950         connect(screenLargestED, SIGNAL(textChanged(QString)),
951                 this, SIGNAL(changed()));
952         connect(screenHugeED, SIGNAL(textChanged(QString)),
953                 this, SIGNAL(changed()));
954         connect(screenHugerED, SIGNAL(textChanged(QString)),
955                 this, SIGNAL(changed()));
956
957         screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
958         screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
959         screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
960         screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
961         screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
962         screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
963         screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
964         screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
965         screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
966         screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
967 }
968
969
970 void PrefScreenFonts::applyRC(LyXRC & rc) const
971 {
972         LyXRC const oldrc = rc;
973
974         parseFontName(screenRomanCO->currentText(),
975                 rc.roman_font_name, rc.roman_font_foundry);
976         parseFontName(screenSansCO->currentText(),
977                 rc.sans_font_name, rc.sans_font_foundry);
978         parseFontName(screenTypewriterCO->currentText(),
979                 rc.typewriter_font_name, rc.typewriter_font_foundry);
980
981         rc.defaultZoom = screenZoomSB->value();
982         rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
983         rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
984         rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
985         rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
986         rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
987         rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
988         rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
989         rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
990         rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
991         rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
992 }
993
994
995 void PrefScreenFonts::updateRC(LyXRC const & rc)
996 {
997         setComboxFont(screenRomanCO, rc.roman_font_name,
998                         rc.roman_font_foundry);
999         setComboxFont(screenSansCO, rc.sans_font_name,
1000                         rc.sans_font_foundry);
1001         setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1002                         rc.typewriter_font_foundry);
1003
1004         selectRoman(screenRomanCO->currentText());
1005         selectSans(screenSansCO->currentText());
1006         selectTypewriter(screenTypewriterCO->currentText());
1007
1008         screenZoomSB->setValue(rc.defaultZoom);
1009         updateScreenFontSizes(rc);
1010 }
1011
1012
1013 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1014 {
1015         doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1016         doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1017         doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1018         doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1019         doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1020         doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1021         doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1022         doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1023         doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1024         doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1025 }
1026
1027
1028 void PrefScreenFonts::selectRoman(const QString & name)
1029 {
1030         screenRomanFE->set(QFont(name), name);
1031 }
1032
1033
1034 void PrefScreenFonts::selectSans(const QString & name)
1035 {
1036         screenSansFE->set(QFont(name), name);
1037 }
1038
1039
1040 void PrefScreenFonts::selectTypewriter(const QString & name)
1041 {
1042         screenTypewriterFE->set(QFont(name), name);
1043 }
1044
1045
1046 /////////////////////////////////////////////////////////////////////
1047 //
1048 // PrefColors
1049 //
1050 /////////////////////////////////////////////////////////////////////
1051
1052
1053 PrefColors::PrefColors(GuiPreferences * form)
1054         : PrefModule(catLookAndFeel, N_("Colors"), form)
1055 {
1056         setupUi(this);
1057
1058         // FIXME: all of this initialization should be put into the controller.
1059         // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1060         // for some discussion of why that is not trivial.
1061         QPixmap icon(32, 32);
1062         for (int i = 0; i < Color_ignore; ++i) {
1063                 ColorCode lc = static_cast<ColorCode>(i);
1064                 if (lc == Color_none
1065                     || lc == Color_black
1066                     || lc == Color_white
1067                     || lc == Color_blue
1068                     || lc == Color_brown
1069                     || lc == Color_cyan
1070                     || lc == Color_darkgray
1071                     || lc == Color_gray
1072                     || lc == Color_green
1073                     || lc == Color_lightgray
1074                     || lc == Color_lime
1075                     || lc == Color_magenta
1076                     || lc == Color_olive
1077                     || lc == Color_orange
1078                     || lc == Color_pink
1079                     || lc == Color_purple
1080                     || lc == Color_red
1081                     || lc == Color_teal
1082                     || lc == Color_violet
1083                     || lc == Color_yellow
1084                     || lc == Color_inherit
1085                     || lc == Color_ignore)
1086                         continue;
1087                 lcolors_.push_back(lc);
1088         }
1089         sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1090         vector<ColorCode>::const_iterator cit = lcolors_.begin();
1091         vector<ColorCode>::const_iterator const end = lcolors_.end();
1092         for (; cit != end; ++cit) {
1093                 (void) new QListWidgetItem(QIcon(icon),
1094                         toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1095         }
1096         curcolors_.resize(lcolors_.size());
1097         newcolors_.resize(lcolors_.size());
1098         // End initialization
1099
1100         connect(colorChangePB, SIGNAL(clicked()),
1101                 this, SLOT(changeColor()));
1102         connect(colorResetPB, SIGNAL(clicked()),
1103                 this, SLOT(resetColor()));
1104         connect(colorResetAllPB, SIGNAL(clicked()),
1105                 this, SLOT(resetAllColor()));
1106         connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1107                 this, SLOT(changeLyxObjectsSelection()));
1108         connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1109                 this, SLOT(changeColor()));
1110         connect(syscolorsCB, SIGNAL(toggled(bool)),
1111                 this, SIGNAL(changed()));
1112         connect(syscolorsCB, SIGNAL(toggled(bool)),
1113                 this, SLOT(changeSysColor()));
1114 }
1115
1116
1117 void PrefColors::applyRC(LyXRC & rc) const
1118 {
1119         LyXRC oldrc = rc;
1120
1121         for (unsigned int i = 0; i < lcolors_.size(); ++i)
1122                 if (curcolors_[i] != newcolors_[i])
1123                         form_->setColor(lcolors_[i], newcolors_[i]);
1124         rc.use_system_colors = syscolorsCB->isChecked();
1125
1126         if (oldrc.use_system_colors != rc.use_system_colors)
1127                 guiApp->colorCache().clear();
1128 }
1129
1130
1131 void PrefColors::updateRC(LyXRC const & rc)
1132 {
1133         for (size_type i = 0; i < lcolors_.size(); ++i) {
1134                 QColor color = QColor(guiApp->colorCache().get(lcolors_[i], false));
1135                 QPixmap coloritem(32, 32);
1136                 coloritem.fill(color);
1137                 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1138                 newcolors_[i] = curcolors_[i] = color.name();
1139         }
1140         syscolorsCB->setChecked(rc.use_system_colors);
1141         changeLyxObjectsSelection();
1142
1143         setDisabledResets();
1144 }
1145
1146
1147 void PrefColors::changeColor()
1148 {
1149         int const row = lyxObjectsLW->currentRow();
1150
1151         // just to be sure
1152         if (row < 0)
1153                 return;
1154
1155         QString const color = newcolors_[size_t(row)];
1156         QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1157
1158         if (setColor(row, c, color)) {
1159                 setDisabledResets();
1160                 // emit signal
1161                 changed();
1162         }
1163 }
1164
1165
1166 void PrefColors::resetColor()
1167 {
1168         int const row = lyxObjectsLW->currentRow();
1169
1170         // just to be sure
1171         if (row < 0)
1172                 return;
1173
1174         QString const color = newcolors_[size_t(row)];
1175         QColor const c = getDefaultColorByRow(row);
1176
1177         if (setColor(row, c, color)) {
1178                 setDisabledResets();
1179                 // emit signal
1180                 changed();
1181         }
1182 }
1183
1184
1185 void PrefColors::resetAllColor()
1186 {
1187         bool isChanged = false;
1188
1189         colorResetAllPB->setDisabled(true);
1190
1191         for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1192                 QString const color = newcolors_[size_t(irow)];
1193                 QColor const c = getDefaultColorByRow(irow);
1194
1195                 if (setColor(irow, c, color))
1196                         isChanged = true;
1197         }
1198
1199         if (isChanged) {
1200                 setDisabledResets();
1201                 // emit signal
1202                 changed();
1203         }
1204 }
1205
1206
1207 bool PrefColors::setColor(int const row, QColor const & new_color,
1208                           QString const & old_color)
1209 {
1210         if (new_color.isValid() && new_color.name() != old_color) {
1211                 newcolors_[size_t(row)] = new_color.name();
1212                 QPixmap coloritem(32, 32);
1213                 coloritem.fill(new_color);
1214                 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1215                 return true;
1216         }
1217         return false;
1218 }
1219
1220
1221 void PrefColors::setDisabledResets()
1222 {
1223         int const row = lyxObjectsLW->currentRow();
1224         // set disable reset buttons ...
1225         if (row >= 0)
1226                 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1227
1228         colorResetAllPB->setDisabled(true);
1229
1230         // ... in between process qt events to give quicker visual feedback to the user ...
1231         guiApp->processEvents();
1232
1233         // ... set disable Reset All button
1234         for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1235                 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1236                         colorResetAllPB->setDisabled(false);
1237                         // the break condition might hide performance issues
1238                         // if a non-default color is at the top of the list
1239                         break;
1240                 }
1241         }
1242 }
1243
1244
1245 bool PrefColors::isDefaultColor(int const row, QString const & color)
1246 {
1247         return color == getDefaultColorByRow(row).name();
1248 }
1249
1250
1251 QColor PrefColors::getDefaultColorByRow(int const row)
1252 {
1253         ColorSet const defaultcolor;
1254         return defaultcolor.getX11HexName(lcolors_[size_t(row)]).c_str();
1255 }
1256
1257
1258 void PrefColors::changeSysColor()
1259 {
1260         for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1261                 // skip colors that are taken from system palette
1262                 bool const disable = syscolorsCB->isChecked()
1263                         && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1264
1265                 QListWidgetItem * const item = lyxObjectsLW->item(row);
1266                 Qt::ItemFlags const flags = item->flags();
1267
1268                 if (disable)
1269                         item->setFlags(flags & ~Qt::ItemIsEnabled);
1270                 else
1271                         item->setFlags(flags | Qt::ItemIsEnabled);
1272         }
1273 }
1274
1275
1276 void PrefColors::changeLyxObjectsSelection()
1277 {
1278         int currentRow = lyxObjectsLW->currentRow();
1279         colorChangePB->setDisabled(currentRow < 0);
1280
1281         if (currentRow < 0)
1282                 colorResetPB->setDisabled(true);
1283         else
1284                 colorResetPB->setDisabled(
1285                         isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1286 }
1287
1288
1289 /////////////////////////////////////////////////////////////////////
1290 //
1291 // PrefDisplay
1292 //
1293 /////////////////////////////////////////////////////////////////////
1294
1295 PrefDisplay::PrefDisplay(GuiPreferences * form)
1296         : PrefModule(catLookAndFeel, N_("Display"), form)
1297 {
1298         setupUi(this);
1299         connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1300         connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1301         connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1302         connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1303         connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1304 }
1305
1306
1307 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1308 {
1309         previewSizeSB->setEnabled(index != 0);
1310 }
1311
1312
1313 void PrefDisplay::applyRC(LyXRC & rc) const
1314 {
1315         switch (instantPreviewCO->currentIndex()) {
1316                 case 0:
1317                         rc.preview = LyXRC::PREVIEW_OFF;
1318                         break;
1319                 case 1:
1320                         rc.preview = LyXRC::PREVIEW_NO_MATH;
1321                         break;
1322                 case 2:
1323                         rc.preview = LyXRC::PREVIEW_ON;
1324                         break;
1325         }
1326
1327         rc.display_graphics = displayGraphicsCB->isChecked();
1328         rc.preview_scale_factor = previewSizeSB->value();
1329         rc.paragraph_markers = paragraphMarkerCB->isChecked();
1330         rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1331
1332         // FIXME!! The graphics cache no longer has a changeDisplay method.
1333 #if 0
1334         if (old_value != rc.display_graphics) {
1335                 graphics::GCache & gc = graphics::GCache::get();
1336                 gc.changeDisplay();
1337         }
1338 #endif
1339 }
1340
1341
1342 void PrefDisplay::updateRC(LyXRC const & rc)
1343 {
1344         switch (rc.preview) {
1345         case LyXRC::PREVIEW_OFF:
1346                 instantPreviewCO->setCurrentIndex(0);
1347                 break;
1348         case LyXRC::PREVIEW_NO_MATH :
1349                 instantPreviewCO->setCurrentIndex(1);
1350                 break;
1351         case LyXRC::PREVIEW_ON :
1352                 instantPreviewCO->setCurrentIndex(2);
1353                 break;
1354         }
1355
1356         displayGraphicsCB->setChecked(rc.display_graphics);
1357         previewSizeSB->setValue(rc.preview_scale_factor);
1358         paragraphMarkerCB->setChecked(rc.paragraph_markers);
1359         ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1360         previewSizeSB->setEnabled(
1361                 rc.display_graphics
1362                 && rc.preview != LyXRC::PREVIEW_OFF);
1363 }
1364
1365
1366 /////////////////////////////////////////////////////////////////////
1367 //
1368 // PrefPaths
1369 //
1370 /////////////////////////////////////////////////////////////////////
1371
1372 PrefPaths::PrefPaths(GuiPreferences * form)
1373         : PrefModule(QString(), N_("Paths"), form)
1374 {
1375         setupUi(this);
1376
1377         connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1378         connect(workingDirED, SIGNAL(textChanged(QString)),
1379                 this, SIGNAL(changed()));
1380
1381         connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1382         connect(templateDirED, SIGNAL(textChanged(QString)),
1383                 this, SIGNAL(changed()));
1384
1385         connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1386         connect(exampleDirED, SIGNAL(textChanged(QString)),
1387                 this, SIGNAL(changed()));
1388
1389         connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1390         connect(backupDirED, SIGNAL(textChanged(QString)),
1391                 this, SIGNAL(changed()));
1392
1393         connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1394         connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1395                 this, SIGNAL(changed()));
1396
1397         connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1398         connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1399                 this, SIGNAL(changed()));
1400
1401         connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1402         connect(tempDirED, SIGNAL(textChanged(QString)),
1403                 this, SIGNAL(changed()));
1404
1405 #if defined(USE_HUNSPELL)
1406         connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1407         connect(hunspellDirED, SIGNAL(textChanged(QString)),
1408                 this, SIGNAL(changed()));
1409 #else
1410         hunspellDirPB->setEnabled(false);
1411         hunspellDirED->setEnabled(false);
1412 #endif
1413
1414         connect(pathPrefixED, SIGNAL(textChanged(QString)),
1415                 this, SIGNAL(changed()));
1416
1417         connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1418                 this, SIGNAL(changed()));
1419
1420         pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1421         texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1422 }
1423
1424
1425 void PrefPaths::applyRC(LyXRC & rc) const
1426 {
1427         rc.document_path = internal_path(fromqstr(workingDirED->text()));
1428         rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1429         rc.template_path = internal_path(fromqstr(templateDirED->text()));
1430         rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1431         rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1432         rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1433         rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1434         rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1435         rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1436         // FIXME: should be a checkbox only
1437         rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1438 }
1439
1440
1441 void PrefPaths::updateRC(LyXRC const & rc)
1442 {
1443         workingDirED->setText(toqstr(external_path(rc.document_path)));
1444         exampleDirED->setText(toqstr(external_path(rc.example_path)));
1445         templateDirED->setText(toqstr(external_path(rc.template_path)));
1446         backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1447         tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1448         thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1449         hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1450         pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1451         texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1452         // FIXME: should be a checkbox only
1453         lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1454 }
1455
1456
1457 void PrefPaths::selectExampledir()
1458 {
1459         QString file = browseDir(internalPath(exampleDirED->text()),
1460                 qt_("Select directory for example files"));
1461         if (!file.isEmpty())
1462                 exampleDirED->setText(file);
1463 }
1464
1465
1466 void PrefPaths::selectTemplatedir()
1467 {
1468         QString file = browseDir(internalPath(templateDirED->text()),
1469                 qt_("Select a document templates directory"));
1470         if (!file.isEmpty())
1471                 templateDirED->setText(file);
1472 }
1473
1474
1475 void PrefPaths::selectTempdir()
1476 {
1477         QString file = browseDir(internalPath(tempDirED->text()),
1478                 qt_("Select a temporary directory"));
1479         if (!file.isEmpty())
1480                 tempDirED->setText(file);
1481 }
1482
1483
1484 void PrefPaths::selectBackupdir()
1485 {
1486         QString file = browseDir(internalPath(backupDirED->text()),
1487                 qt_("Select a backups directory"));
1488         if (!file.isEmpty())
1489                 backupDirED->setText(file);
1490 }
1491
1492
1493 void PrefPaths::selectWorkingdir()
1494 {
1495         QString file = browseDir(internalPath(workingDirED->text()),
1496                 qt_("Select a document directory"));
1497         if (!file.isEmpty())
1498                 workingDirED->setText(file);
1499 }
1500
1501
1502 void PrefPaths::selectThesaurusdir()
1503 {
1504         QString file = browseDir(internalPath(thesaurusDirED->text()),
1505                 qt_("Set the path to the thesaurus dictionaries"));
1506         if (!file.isEmpty())
1507                 thesaurusDirED->setText(file);
1508 }
1509
1510
1511 void PrefPaths::selectHunspelldir()
1512 {
1513         QString file = browseDir(internalPath(hunspellDirED->text()),
1514                 qt_("Set the path to the Hunspell dictionaries"));
1515         if (!file.isEmpty())
1516                 hunspellDirED->setText(file);
1517 }
1518
1519
1520 void PrefPaths::selectLyxPipe()
1521 {
1522         QString file = form_->browse(internalPath(lyxserverDirED->text()),
1523                 qt_("Give a filename for the LyX server pipe"));
1524         if (!file.isEmpty())
1525                 lyxserverDirED->setText(file);
1526 }
1527
1528
1529 /////////////////////////////////////////////////////////////////////
1530 //
1531 // PrefSpellchecker
1532 //
1533 /////////////////////////////////////////////////////////////////////
1534
1535 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1536         : PrefModule(catLanguage, N_("Spellchecker"), form)
1537 {
1538         setupUi(this);
1539
1540 // FIXME: this check should test the target platform (darwin)
1541 #if defined(USE_MACOSX_PACKAGING)
1542         spellcheckerCB->addItem(qt_("Native"), QString("native"));
1543 #define CONNECT_APPLESPELL
1544 #else
1545 #undef CONNECT_APPLESPELL
1546 #endif
1547 #if defined(USE_ASPELL)
1548         spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1549 #endif
1550 #if defined(USE_ENCHANT)
1551         spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1552 #endif
1553 #if defined(USE_HUNSPELL)
1554         spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1555 #endif
1556
1557         #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1558                 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1559                         this, SIGNAL(changed()));
1560                 connect(altLanguageED, SIGNAL(textChanged(QString)),
1561                         this, SIGNAL(changed()));
1562                 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1563                         this, SIGNAL(changed()));
1564                 connect(compoundWordCB, SIGNAL(clicked()),
1565                         this, SIGNAL(changed()));
1566                 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1567                         this, SIGNAL(changed()));
1568                 connect(spellcheckNotesCB, SIGNAL(clicked()),
1569                         this, SIGNAL(changed()));
1570
1571                 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1572                 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1573         #else
1574                 spellcheckerCB->setEnabled(false);
1575                 altLanguageED->setEnabled(false);
1576                 escapeCharactersED->setEnabled(false);
1577                 compoundWordCB->setEnabled(false);
1578                 spellcheckContinuouslyCB->setEnabled(false);
1579                 spellcheckNotesCB->setEnabled(false);
1580         #endif
1581 }
1582
1583
1584 void PrefSpellchecker::applyRC(LyXRC & rc) const
1585 {
1586         string const speller = fromqstr(spellcheckerCB->
1587                 itemData(spellcheckerCB->currentIndex()).toString());
1588         if (!speller.empty())
1589                 rc.spellchecker = speller;
1590         rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1591         rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1592         rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1593         rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1594         rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1595 }
1596
1597
1598 void PrefSpellchecker::updateRC(LyXRC const & rc)
1599 {
1600         spellcheckerCB->setCurrentIndex(
1601                 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1602         altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1603         escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1604         compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1605         spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1606         spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1607 }
1608
1609
1610 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1611 {
1612         QString spellchecker = spellcheckerCB->itemData(index).toString();
1613
1614         compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1615 }
1616
1617
1618
1619 /////////////////////////////////////////////////////////////////////
1620 //
1621 // PrefConverters
1622 //
1623 /////////////////////////////////////////////////////////////////////
1624
1625
1626 PrefConverters::PrefConverters(GuiPreferences * form)
1627         : PrefModule(catFiles, N_("Converters"), form)
1628 {
1629         setupUi(this);
1630
1631         connect(converterNewPB, SIGNAL(clicked()),
1632                 this, SLOT(updateConverter()));
1633         connect(converterRemovePB, SIGNAL(clicked()),
1634                 this, SLOT(removeConverter()));
1635         connect(converterModifyPB, SIGNAL(clicked()),
1636                 this, SLOT(updateConverter()));
1637         connect(convertersLW, SIGNAL(currentRowChanged(int)),
1638                 this, SLOT(switchConverter()));
1639         connect(converterFromCO, SIGNAL(activated(QString)),
1640                 this, SLOT(changeConverter()));
1641         connect(converterToCO, SIGNAL(activated(QString)),
1642                 this, SLOT(changeConverter()));
1643         connect(converterED, SIGNAL(textEdited(QString)),
1644                 this, SLOT(changeConverter()));
1645         connect(converterFlagED, SIGNAL(textEdited(QString)),
1646                 this, SLOT(changeConverter()));
1647         connect(converterNewPB, SIGNAL(clicked()),
1648                 this, SIGNAL(changed()));
1649         connect(converterRemovePB, SIGNAL(clicked()),
1650                 this, SIGNAL(changed()));
1651         connect(converterModifyPB, SIGNAL(clicked()),
1652                 this, SIGNAL(changed()));
1653         connect(maxAgeLE, SIGNAL(textEdited(QString)),
1654                 this, SIGNAL(changed()));
1655         connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1656                 this, SIGNAL(changed()));
1657
1658         converterED->setValidator(new NoNewLineValidator(converterED));
1659         converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1660         maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1661         //converterDefGB->setFocusProxy(convertersLW);
1662 }
1663
1664
1665 void PrefConverters::applyRC(LyXRC & rc) const
1666 {
1667         rc.use_converter_cache = cacheCB->isChecked();
1668         rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1669         rc.use_converter_needauth = needauthCB->isChecked();
1670         rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1671 }
1672
1673
1674 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1675         cb->blockSignals(true);
1676         cb->setChecked(checked);
1677         cb->blockSignals(false);
1678 }
1679
1680
1681 void PrefConverters::updateRC(LyXRC const & rc)
1682 {
1683         cacheCB->setChecked(rc.use_converter_cache);
1684         needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1685         setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1686         QString max_age;
1687         doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1688         updateGui();
1689 }
1690
1691
1692 void PrefConverters::updateGui()
1693 {
1694         QString const pattern("%1 -> %2");
1695         form_->formats().sort();
1696         form_->converters().update(form_->formats());
1697         // save current selection
1698         QString current =
1699                 pattern
1700                 .arg(converterFromCO->currentText())
1701                 .arg(converterToCO->currentText());
1702
1703         converterFromCO->clear();
1704         converterToCO->clear();
1705
1706         for (Format const & f : form_->formats()) {
1707                 QString const name = toqstr(translateIfPossible(f.prettyname()));
1708                 converterFromCO->addItem(name);
1709                 converterToCO->addItem(name);
1710         }
1711
1712         // currentRowChanged(int) is also triggered when updating the listwidget
1713         // block signals to avoid unnecessary calls to switchConverter()
1714         convertersLW->blockSignals(true);
1715         convertersLW->clear();
1716
1717         for (Converter const & c : form_->converters()) {
1718                 QString const name =
1719                         pattern
1720                         .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1721                         .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1722                 int type = form_->converters().getNumber(c.From()->name(),
1723                                                          c.To()->name());
1724                 new QListWidgetItem(name, convertersLW, type);
1725         }
1726         convertersLW->sortItems(Qt::AscendingOrder);
1727         convertersLW->blockSignals(false);
1728
1729         // restore selection
1730         if (current != pattern.arg(QString()).arg(QString())) {
1731                 QList<QListWidgetItem *> const item =
1732                         convertersLW->findItems(current, Qt::MatchExactly);
1733                 if (!item.isEmpty())
1734                         convertersLW->setCurrentItem(item.at(0));
1735         }
1736
1737         // select first element if restoring failed
1738         if (convertersLW->currentRow() == -1)
1739                 convertersLW->setCurrentRow(0);
1740
1741         updateButtons();
1742 }
1743
1744
1745 void PrefConverters::switchConverter()
1746 {
1747         int const cnr = convertersLW->currentItem()->type();
1748         Converter const & c(form_->converters().get(cnr));
1749         converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1750         converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1751         converterED->setText(toqstr(c.command()));
1752         converterFlagED->setText(toqstr(c.flags()));
1753
1754         updateButtons();
1755 }
1756
1757
1758 void PrefConverters::changeConverter()
1759 {
1760         updateButtons();
1761 }
1762
1763
1764 void PrefConverters::updateButtons()
1765 {
1766         if (form_->formats().empty())
1767                 return;
1768         Format const & from = form_->formats().get(converterFromCO->currentIndex());
1769         Format const & to = form_->formats().get(converterToCO->currentIndex());
1770         int const sel = form_->converters().getNumber(from.name(), to.name());
1771         bool const known = sel >= 0;
1772         bool const valid = !(converterED->text().isEmpty()
1773                 || from.name() == to.name());
1774
1775         string old_command;
1776         string old_flag;
1777
1778         if (convertersLW->count() > 0) {
1779                 int const cnr = convertersLW->currentItem()->type();
1780                 Converter const & c = form_->converters().get(cnr);
1781                 old_command = c.command();
1782                 old_flag = c.flags();
1783         }
1784
1785         string const new_command = fromqstr(converterED->text());
1786         string const new_flag = fromqstr(converterFlagED->text());
1787
1788         bool modified = (old_command != new_command || old_flag != new_flag);
1789
1790         converterModifyPB->setEnabled(valid && known && modified);
1791         converterNewPB->setEnabled(valid && !known);
1792         converterRemovePB->setEnabled(known);
1793
1794         maxAgeLE->setEnabled(cacheCB->isChecked());
1795         maxAgeLA->setEnabled(cacheCB->isChecked());
1796 }
1797
1798
1799 // FIXME: user must
1800 // specify unique from/to or it doesn't appear. This is really bad UI
1801 // this is why we can use the same function for both new and modify
1802 void PrefConverters::updateConverter()
1803 {
1804         Format const & from = form_->formats().get(converterFromCO->currentIndex());
1805         Format const & to = form_->formats().get(converterToCO->currentIndex());
1806         string const flags = fromqstr(converterFlagED->text());
1807         string const command = fromqstr(converterED->text());
1808
1809         Converter const * old =
1810                 form_->converters().getConverter(from.name(), to.name());
1811         form_->converters().add(from.name(), to.name(), command, flags);
1812
1813         if (!old)
1814                 form_->converters().updateLast(form_->formats());
1815
1816         updateGui();
1817
1818         // Remove all files created by this converter from the cache, since
1819         // the modified converter might create different files.
1820         ConverterCache::get().remove_all(from.name(), to.name());
1821 }
1822
1823
1824 void PrefConverters::removeConverter()
1825 {
1826         Format const & from = form_->formats().get(converterFromCO->currentIndex());
1827         Format const & to = form_->formats().get(converterToCO->currentIndex());
1828         form_->converters().erase(from.name(), to.name());
1829
1830         updateGui();
1831
1832         // Remove all files created by this converter from the cache, since
1833         // a possible new converter might create different files.
1834         ConverterCache::get().remove_all(from.name(), to.name());
1835 }
1836
1837
1838 void PrefConverters::on_cacheCB_stateChanged(int state)
1839 {
1840         maxAgeLE->setEnabled(state == Qt::Checked);
1841         maxAgeLA->setEnabled(state == Qt::Checked);
1842         changed();
1843 }
1844
1845
1846 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1847 {
1848         needauthCB->setEnabled(!checked);
1849 }
1850
1851
1852 void PrefConverters::on_needauthCB_toggled(bool checked)
1853 {
1854         if (checked) {
1855                 changed();
1856                 return;
1857         }
1858
1859         int ret = frontend::Alert::prompt(
1860                 _("SECURITY WARNING!"), _("Unchecking this option has the effect that potentially harmful converters would be run without asking your permission first. This is UNSAFE and NOT recommended, unless you know what you are doing. Are you sure you would like to proceed ? The recommended and safe answer is NO!"),
1861                 0, 0, _("&No"), _("&Yes"));
1862         if (ret == 1)
1863                 changed();
1864         else
1865                 setCheckboxBlockSignals(needauthCB, true);
1866 }
1867
1868
1869 /////////////////////////////////////////////////////////////////////
1870 //
1871 // FormatValidator
1872 //
1873 /////////////////////////////////////////////////////////////////////
1874
1875 class FormatValidator : public QValidator
1876 {
1877 public:
1878         FormatValidator(QWidget *, Formats const & f);
1879         void fixup(QString & input) const override;
1880         QValidator::State validate(QString & input, int & pos) const override;
1881 private:
1882         virtual QString toString(Format const & format) const = 0;
1883         int nr() const;
1884         Formats const & formats_;
1885 };
1886
1887
1888 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1889         : QValidator(parent), formats_(f)
1890 {
1891 }
1892
1893
1894 void FormatValidator::fixup(QString & input) const
1895 {
1896         Formats::const_iterator cit = formats_.begin();
1897         Formats::const_iterator end = formats_.end();
1898         for (; cit != end; ++cit) {
1899                 QString const name = toString(*cit);
1900                 if (distance(formats_.begin(), cit) == nr()) {
1901                         input = name;
1902                         return;
1903                 }
1904         }
1905 }
1906
1907
1908 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1909 {
1910         Formats::const_iterator cit = formats_.begin();
1911         Formats::const_iterator end = formats_.end();
1912         bool unknown = true;
1913         for (; unknown && cit != end; ++cit) {
1914                 QString const name = toString(*cit);
1915                 if (distance(formats_.begin(), cit) != nr())
1916                         unknown = name != input;
1917         }
1918
1919         if (unknown && !input.isEmpty())
1920                 return QValidator::Acceptable;
1921         else
1922                 return QValidator::Intermediate;
1923 }
1924
1925
1926 int FormatValidator::nr() const
1927 {
1928         QComboBox * p = qobject_cast<QComboBox *>(parent());
1929         return p->itemData(p->currentIndex()).toInt();
1930 }
1931
1932
1933 /////////////////////////////////////////////////////////////////////
1934 //
1935 // FormatNameValidator
1936 //
1937 /////////////////////////////////////////////////////////////////////
1938
1939 class FormatNameValidator : public FormatValidator
1940 {
1941 public:
1942         FormatNameValidator(QWidget * parent, Formats const & f)
1943                 : FormatValidator(parent, f)
1944         {}
1945 private:
1946         QString toString(Format const & format) const override
1947         {
1948                 return toqstr(format.name());
1949         }
1950 };
1951
1952
1953 /////////////////////////////////////////////////////////////////////
1954 //
1955 // FormatPrettynameValidator
1956 //
1957 /////////////////////////////////////////////////////////////////////
1958
1959 class FormatPrettynameValidator : public FormatValidator
1960 {
1961 public:
1962         FormatPrettynameValidator(QWidget * parent, Formats const & f)
1963                 : FormatValidator(parent, f)
1964         {}
1965 private:
1966         QString toString(Format const & format) const override
1967         {
1968                 return toqstr(translateIfPossible(format.prettyname()));
1969         }
1970 };
1971
1972
1973 /////////////////////////////////////////////////////////////////////
1974 //
1975 // PrefFileformats
1976 //
1977 /////////////////////////////////////////////////////////////////////
1978
1979 PrefFileformats::PrefFileformats(GuiPreferences * form)
1980         : PrefModule(catFiles, N_("File Formats"), form)
1981 {
1982         setupUi(this);
1983
1984         formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
1985         formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
1986         extensionsED->setValidator(new NoNewLineValidator(extensionsED));
1987         shortcutED->setValidator(new NoNewLineValidator(shortcutED));
1988         editorED->setValidator(new NoNewLineValidator(editorED));
1989         viewerED->setValidator(new NoNewLineValidator(viewerED));
1990         copierED->setValidator(new NoNewLineValidator(copierED));
1991
1992         connect(documentCB, SIGNAL(clicked()),
1993                 this, SLOT(setFlags()));
1994         connect(vectorCB, SIGNAL(clicked()),
1995                 this, SLOT(setFlags()));
1996         connect(exportMenuCB, SIGNAL(clicked()),
1997                 this, SLOT(setFlags()));
1998         connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
1999                 this, SLOT(updatePrettyname()));
2000         connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2001                 this, SIGNAL(changed()));
2002         connect(defaultFormatCB, SIGNAL(activated(QString)),
2003                 this, SIGNAL(changed()));
2004         connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2005                 this, SIGNAL(changed()));
2006         connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2007                 this, SIGNAL(changed()));
2008         connect(viewerCO, SIGNAL(activated(int)),
2009                 this, SIGNAL(changed()));
2010         connect(editorCO, SIGNAL(activated(int)),
2011                 this, SIGNAL(changed()));
2012 }
2013
2014
2015 namespace {
2016
2017 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2018 {
2019         if (shortcut.empty())
2020                 return string();
2021
2022         string l10n_format =
2023                 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2024         return split(l10n_format, '|');
2025 }
2026
2027 } // namespace
2028
2029
2030 void PrefFileformats::applyRC(LyXRC & rc) const
2031 {
2032         QString const default_format = defaultFormatCB->itemData(
2033                 defaultFormatCB->currentIndex()).toString();
2034         rc.default_view_format = fromqstr(default_format);
2035         QString const default_otf_format = defaultOTFFormatCB->itemData(
2036                 defaultOTFFormatCB->currentIndex()).toString();
2037         rc.default_otf_view_format = fromqstr(default_otf_format);
2038         QString const default_platex_format = defaultPlatexFormatCB->itemData(
2039                 defaultPlatexFormatCB->currentIndex()).toString();
2040         rc.default_platex_view_format = fromqstr(default_platex_format);
2041 }
2042
2043
2044 void PrefFileformats::updateRC(LyXRC const & rc)
2045 {
2046         viewer_alternatives = rc.viewer_alternatives;
2047         editor_alternatives = rc.editor_alternatives;
2048         bool const init = defaultFormatCB->currentText().isEmpty();
2049         updateView();
2050         if (init) {
2051                 int pos =
2052                         defaultFormatCB->findData(toqstr(rc.default_view_format));
2053                 defaultFormatCB->setCurrentIndex(pos);
2054                 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2055                                 defaultOTFFormatCB->setCurrentIndex(pos);
2056                 defaultOTFFormatCB->setCurrentIndex(pos);
2057                 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2058                                 defaultPlatexFormatCB->setCurrentIndex(pos);
2059                 defaultPlatexFormatCB->setCurrentIndex(pos);
2060         }
2061 }
2062
2063
2064 void PrefFileformats::updateView()
2065 {
2066         QString const current = formatsCB->currentText();
2067         QString const current_def = defaultFormatCB->currentText();
2068         QString const current_def_otf = defaultOTFFormatCB->currentText();
2069         QString const current_def_platex = defaultPlatexFormatCB->currentText();
2070
2071         // update comboboxes with formats
2072         formatsCB->blockSignals(true);
2073         defaultFormatCB->blockSignals(true);
2074         defaultOTFFormatCB->blockSignals(true);
2075         defaultPlatexFormatCB->blockSignals(true);
2076         formatsCB->clear();
2077         defaultFormatCB->clear();
2078         defaultOTFFormatCB->clear();
2079         defaultPlatexFormatCB->clear();
2080         form_->formats().sort();
2081         for (Format const & f : form_->formats()) {
2082                 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2083                 formatsCB->addItem(prettyname,
2084                                    QVariant(form_->formats().getNumber(f.name())));
2085                 if (f.viewer().empty())
2086                         continue;
2087                 if (form_->converters().isReachable("xhtml", f.name())
2088                     || form_->converters().isReachable("dviluatex", f.name())
2089                     || form_->converters().isReachable("luatex", f.name())
2090                     || form_->converters().isReachable("xetex", f.name())) {
2091                         defaultFormatCB->addItem(prettyname,
2092                                         QVariant(toqstr(f.name())));
2093                         defaultOTFFormatCB->addItem(prettyname,
2094                                         QVariant(toqstr(f.name())));
2095                 } else {
2096                         if (form_->converters().isReachable("latex", f.name())
2097                             || form_->converters().isReachable("pdflatex", f.name()))
2098                                 defaultFormatCB->addItem(prettyname,
2099                                         QVariant(toqstr(f.name())));
2100                         if (form_->converters().isReachable("platex", f.name()))
2101                                         defaultPlatexFormatCB->addItem(prettyname,
2102                                                 QVariant(toqstr(f.name())));
2103                 }
2104         }
2105
2106         // restore selections
2107         int item = formatsCB->findText(current, Qt::MatchExactly);
2108         formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2109         on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2110         item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2111         defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2112         item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2113         defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2114         item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2115         defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2116         formatsCB->blockSignals(false);
2117         defaultFormatCB->blockSignals(false);
2118         defaultOTFFormatCB->blockSignals(false);
2119         defaultPlatexFormatCB->blockSignals(false);
2120 }
2121
2122
2123 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2124 {
2125         if (form_->formats().empty())
2126                 return;
2127         int const nr = formatsCB->itemData(i).toInt();
2128         Format const f = form_->formats().get(nr);
2129
2130         formatED->setText(toqstr(f.name()));
2131         copierED->setText(toqstr(form_->movers().command(f.name())));
2132         extensionsED->setText(toqstr(f.extensions()));
2133         mimeED->setText(toqstr(f.mime()));
2134         shortcutED->setText(
2135                 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2136         documentCB->setChecked((f.documentFormat()));
2137         vectorCB->setChecked((f.vectorFormat()));
2138         exportMenuCB->setChecked((f.inExportMenu()));
2139         exportMenuCB->setEnabled((f.documentFormat()));
2140         updateViewers();
2141         updateEditors();
2142 }
2143
2144
2145 void PrefFileformats::setFlags()
2146 {
2147         int flags = Format::none;
2148         if (documentCB->isChecked())
2149                 flags |= Format::document;
2150         if (vectorCB->isChecked())
2151                 flags |= Format::vector;
2152         if (exportMenuCB->isChecked())
2153                 flags |= Format::export_menu;
2154         currentFormat().setFlags(flags);
2155         exportMenuCB->setEnabled(documentCB->isChecked());
2156         changed();
2157 }
2158
2159
2160 void PrefFileformats::on_copierED_textEdited(const QString & s)
2161 {
2162         string const fmt = fromqstr(formatED->text());
2163         form_->movers().set(fmt, fromqstr(s));
2164         changed();
2165 }
2166
2167
2168 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2169 {
2170         currentFormat().setExtensions(fromqstr(s));
2171         changed();
2172 }
2173
2174
2175 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2176 {
2177         currentFormat().setViewer(fromqstr(s));
2178         changed();
2179 }
2180
2181
2182 void PrefFileformats::on_editorED_textEdited(const QString & s)
2183 {
2184         currentFormat().setEditor(fromqstr(s));
2185         changed();
2186 }
2187
2188
2189 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2190 {
2191         currentFormat().setMime(fromqstr(s));
2192         changed();
2193 }
2194
2195
2196 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2197 {
2198         string const new_shortcut = fromqstr(s);
2199         if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2200                                           currentFormat().shortcut()))
2201                 return;
2202         currentFormat().setShortcut(new_shortcut);
2203         changed();
2204 }
2205
2206
2207 void PrefFileformats::on_formatED_editingFinished()
2208 {
2209         string const newname = fromqstr(formatED->displayText());
2210         string const oldname = currentFormat().name();
2211         if (newname == oldname)
2212                 return;
2213         if (form_->converters().formatIsUsed(oldname)) {
2214                 Alert::error(_("Format in use"),
2215                              _("You cannot change a format's short name "
2216                                "if the format is used by a converter. "
2217                                "Please remove the converter first."));
2218                 updateView();
2219                 return;
2220         }
2221
2222         currentFormat().setName(newname);
2223         changed();
2224 }
2225
2226
2227 void PrefFileformats::on_formatED_textChanged(const QString &)
2228 {
2229         QString t = formatED->text();
2230         int p = 0;
2231         bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2232         setValid(formatLA, valid);
2233 }
2234
2235
2236 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2237 {
2238         QString t = formatsCB->currentText();
2239         int p = 0;
2240         bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2241         setValid(formatsLA, valid);
2242 }
2243
2244
2245 void PrefFileformats::updatePrettyname()
2246 {
2247         QString const newname = formatsCB->currentText();
2248         if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2249                 return;
2250
2251         currentFormat().setPrettyname(qstring_to_ucs4(newname));
2252         formatsChanged();
2253         updateView();
2254         changed();
2255 }
2256
2257
2258 namespace {
2259         void updateComboBox(LyXRC::Alternatives const & alts,
2260                             string const & fmt, QComboBox * combo)
2261         {
2262                 LyXRC::Alternatives::const_iterator it =
2263                                 alts.find(fmt);
2264                 if (it != alts.end()) {
2265                         LyXRC::CommandSet const & cmds = it->second;
2266                         LyXRC::CommandSet::const_iterator sit =
2267                                         cmds.begin();
2268                         LyXRC::CommandSet::const_iterator const sen =
2269                                         cmds.end();
2270                         for (; sit != sen; ++sit) {
2271                                 QString const qcmd = toqstr(*sit);
2272                                 combo->addItem(qcmd, qcmd);
2273                         }
2274                 }
2275         }
2276 } // namespace
2277
2278
2279 void PrefFileformats::updateViewers()
2280 {
2281         Format const f = currentFormat();
2282         viewerCO->blockSignals(true);
2283         viewerCO->clear();
2284         viewerCO->addItem(qt_("None"), QString());
2285         updateComboBox(viewer_alternatives, f.name(), viewerCO);
2286         viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2287         viewerCO->blockSignals(false);
2288
2289         int pos = viewerCO->findData(toqstr(f.viewer()));
2290         if (pos != -1) {
2291                 viewerED->clear();
2292                 viewerED->setEnabled(false);
2293                 viewerCO->setCurrentIndex(pos);
2294         } else {
2295                 viewerED->setEnabled(true);
2296                 viewerED->setText(toqstr(f.viewer()));
2297                 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2298         }
2299 }
2300
2301
2302 void PrefFileformats::updateEditors()
2303 {
2304         Format const f = currentFormat();
2305         editorCO->blockSignals(true);
2306         editorCO->clear();
2307         editorCO->addItem(qt_("None"), QString());
2308         updateComboBox(editor_alternatives, f.name(), editorCO);
2309         editorCO->addItem(qt_("Custom"), QString("custom editor"));
2310         editorCO->blockSignals(false);
2311
2312         int pos = editorCO->findData(toqstr(f.editor()));
2313         if (pos != -1) {
2314                 editorED->clear();
2315                 editorED->setEnabled(false);
2316                 editorCO->setCurrentIndex(pos);
2317         } else {
2318                 editorED->setEnabled(true);
2319                 editorED->setText(toqstr(f.editor()));
2320                 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2321         }
2322 }
2323
2324
2325 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2326 {
2327         bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2328         viewerED->setEnabled(custom);
2329         if (!custom)
2330                 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2331 }
2332
2333
2334 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2335 {
2336         bool const custom = editorCO->itemData(i).toString() == "custom editor";
2337         editorED->setEnabled(custom);
2338         if (!custom)
2339                 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2340 }
2341
2342
2343 Format & PrefFileformats::currentFormat()
2344 {
2345         int const i = formatsCB->currentIndex();
2346         int const nr = formatsCB->itemData(i).toInt();
2347         return form_->formats().get(nr);
2348 }
2349
2350
2351 void PrefFileformats::on_formatNewPB_clicked()
2352 {
2353         form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2354         updateView();
2355         formatsCB->setCurrentIndex(0);
2356         formatsCB->setFocus(Qt::OtherFocusReason);
2357 }
2358
2359
2360 void PrefFileformats::on_formatRemovePB_clicked()
2361 {
2362         int const i = formatsCB->currentIndex();
2363         int const nr = formatsCB->itemData(i).toInt();
2364         string const current_text = form_->formats().get(nr).name();
2365         if (form_->converters().formatIsUsed(current_text)) {
2366                 Alert::error(_("Format in use"),
2367                              _("Cannot remove a Format used by a Converter. "
2368                                             "Remove the converter first."));
2369                 return;
2370         }
2371
2372         form_->formats().erase(current_text);
2373         formatsChanged();
2374         updateView();
2375         on_formatsCB_editTextChanged(formatsCB->currentText());
2376         changed();
2377 }
2378
2379
2380 /////////////////////////////////////////////////////////////////////
2381 //
2382 // PrefLanguage
2383 //
2384 /////////////////////////////////////////////////////////////////////
2385
2386 PrefLanguage::PrefLanguage(GuiPreferences * form)
2387         : PrefModule(catLanguage, N_("Language"), form)
2388 {
2389         setupUi(this);
2390
2391         connect(visualCursorRB, SIGNAL(clicked()),
2392                 this, SIGNAL(changed()));
2393         connect(logicalCursorRB, SIGNAL(clicked()),
2394                 this, SIGNAL(changed()));
2395         connect(markForeignCB, SIGNAL(clicked()),
2396                 this, SIGNAL(changed()));
2397         connect(respectOSkbdCB, SIGNAL(clicked()),
2398                 this, SIGNAL(changed()));
2399         connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2400                 this, SIGNAL(changed()));
2401         connect(explicitDocLangEndCB, SIGNAL(clicked()),
2402                 this, SIGNAL(changed()));
2403         connect(languagePackageCO, SIGNAL(activated(int)),
2404                 this, SIGNAL(changed()));
2405         connect(languagePackageED, SIGNAL(textChanged(QString)),
2406                 this, SIGNAL(changed()));
2407         connect(globalCB, SIGNAL(clicked()),
2408                 this, SIGNAL(changed()));
2409         connect(startCommandED, SIGNAL(textChanged(QString)),
2410                 this, SIGNAL(changed()));
2411         connect(endCommandED, SIGNAL(textChanged(QString)),
2412                 this, SIGNAL(changed()));
2413         connect(uiLanguageCO, SIGNAL(activated(int)),
2414                 this, SIGNAL(changed()));
2415         connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2416                 this, SIGNAL(changed()));
2417         connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2418                 this, SIGNAL(changed()));
2419         connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2420                 this, SIGNAL(changed()));
2421
2422         languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2423         startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2424         endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2425
2426         defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2427         defaultDecimalSepED->setMaxLength(1);
2428
2429         defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2430         defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2431
2432         QAbstractItemModel * language_model = guiApp->languageModel();
2433         language_model->sort(0);
2434         uiLanguageCO->blockSignals(true);
2435         uiLanguageCO->clear();
2436         uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2437         for (int i = 0; i != language_model->rowCount(); ++i) {
2438                 QModelIndex index = language_model->index(i, 0);
2439                 // Filter the list based on the available translation and add
2440                 // each language code only once
2441                 string const name = fromqstr(index.data(Qt::UserRole).toString());
2442                 Language const * lang = languages.getLanguage(name);
2443                 if (!lang)
2444                         continue;
2445                 // never remove the currently selected language
2446                 if (name != form->rc().gui_language
2447                     && name != lyxrc.gui_language
2448                     && (!Messages::available(lang->code())
2449                         || !lang->hasGuiSupport()))
2450                         continue;
2451                 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2452                                       index.data(Qt::UserRole).toString());
2453         }
2454         uiLanguageCO->blockSignals(false);
2455 }
2456
2457
2458 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2459 {
2460          QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2461                  qt_("The change of user interface language will be fully "
2462                  "effective only after a restart."));
2463 }
2464
2465
2466 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2467 {
2468         if (i == 2)
2469                 languagePackageED->setText(save_langpack_);
2470         else if (!languagePackageED->text().isEmpty()) {
2471                 save_langpack_ = languagePackageED->text();
2472                 languagePackageED->clear();
2473         }
2474         languagePackageED->setEnabled(i == 2);
2475 }
2476
2477
2478 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2479 {
2480         defaultDecimalSepED->setEnabled(i == 1);
2481 }
2482
2483
2484 void PrefLanguage::applyRC(LyXRC & rc) const
2485 {
2486         rc.visual_cursor = visualCursorRB->isChecked();
2487         rc.mark_foreign_language = markForeignCB->isChecked();
2488         rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2489         rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2490         rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2491         int const p = languagePackageCO->currentIndex();
2492         if (p == 0)
2493                 rc.language_package_selection = LyXRC::LP_AUTO;
2494         else if (p == 1)
2495                 rc.language_package_selection = LyXRC::LP_BABEL;
2496         else if (p == 2)
2497                 rc.language_package_selection = LyXRC::LP_CUSTOM;
2498         else if (p == 3)
2499                 rc.language_package_selection = LyXRC::LP_NONE;
2500         rc.language_custom_package = fromqstr(languagePackageED->text());
2501         rc.language_global_options = globalCB->isChecked();
2502         rc.language_command_begin = fromqstr(startCommandED->text());
2503         rc.language_command_end = fromqstr(endCommandED->text());
2504         rc.gui_language = fromqstr(
2505                 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2506         if (defaultDecimalSepCO->currentIndex() == 0)
2507                 rc.default_decimal_sep = "locale";
2508         else
2509                 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2510         rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2511 }
2512
2513
2514 void PrefLanguage::updateRC(LyXRC const & rc)
2515 {
2516         if (rc.visual_cursor)
2517                 visualCursorRB->setChecked(true);
2518         else
2519                 logicalCursorRB->setChecked(true);
2520         markForeignCB->setChecked(rc.mark_foreign_language);
2521         respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2522         explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2523         explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2524         languagePackageCO->setCurrentIndex(rc.language_package_selection);
2525         if (languagePackageCO->currentIndex() == 2) {
2526                 languagePackageED->setText(toqstr(rc.language_custom_package));
2527                 languagePackageED->setEnabled(true);
2528         } else {
2529                 languagePackageED->clear();
2530                 save_langpack_ = toqstr(rc.language_custom_package);
2531                 languagePackageED->setEnabled(false);
2532         }
2533         defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2534         globalCB->setChecked(rc.language_global_options);
2535         startCommandED->setText(toqstr(rc.language_command_begin));
2536         endCommandED->setText(toqstr(rc.language_command_end));
2537         if (rc.default_decimal_sep == "locale") {
2538                 defaultDecimalSepCO->setCurrentIndex(0);
2539                 defaultDecimalSepED->clear();
2540         } else {
2541                 defaultDecimalSepCO->setCurrentIndex(1);
2542                 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2543         }
2544         int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2545         defaultLengthUnitCO->setCurrentIndex(pos);
2546
2547         pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2548         uiLanguageCO->blockSignals(true);
2549         uiLanguageCO->setCurrentIndex(pos);
2550         uiLanguageCO->blockSignals(false);
2551 }
2552
2553
2554 /////////////////////////////////////////////////////////////////////
2555 //
2556 // PrefUserInterface
2557 //
2558 /////////////////////////////////////////////////////////////////////
2559
2560 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2561         : PrefModule(catLookAndFeel, N_("User Interface"), form)
2562 {
2563         setupUi(this);
2564
2565         connect(uiFilePB, SIGNAL(clicked()),
2566                 this, SLOT(selectUi()));
2567         connect(uiFileED, SIGNAL(textChanged(QString)),
2568                 this, SIGNAL(changed()));
2569         connect(iconSetCO, SIGNAL(activated(int)),
2570                 this, SIGNAL(changed()));
2571         connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2572                 this, SIGNAL(changed()));
2573         connect(lastfilesSB, SIGNAL(valueChanged(int)),
2574                 this, SIGNAL(changed()));
2575         connect(tooltipCB, SIGNAL(toggled(bool)),
2576                 this, SIGNAL(changed()));
2577         lastfilesSB->setMaximum(maxlastfiles);
2578
2579         iconSetCO->addItem(qt_("Default"), QString());
2580         iconSetCO->addItem(qt_("Classic"), "classic");
2581         iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2582
2583 #if (!(defined Q_WS_X11 || defined(QPA_XCB)) || QT_VERSION < 0x040600)
2584         useSystemThemeIconsCB->hide();
2585 #endif
2586 }
2587
2588
2589 void PrefUserInterface::applyRC(LyXRC & rc) const
2590 {
2591         rc.icon_set = fromqstr(iconSetCO->itemData(
2592                 iconSetCO->currentIndex()).toString());
2593
2594         rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2595         rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2596         rc.num_lastfiles = lastfilesSB->value();
2597         rc.use_tooltip = tooltipCB->isChecked();
2598 }
2599
2600
2601 void PrefUserInterface::updateRC(LyXRC const & rc)
2602 {
2603         int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2604         if (iconset < 0)
2605                 iconset = 0;
2606         iconSetCO->setCurrentIndex(iconset);
2607         useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2608         uiFileED->setText(toqstr(external_path(rc.ui_file)));
2609         lastfilesSB->setValue(rc.num_lastfiles);
2610         tooltipCB->setChecked(rc.use_tooltip);
2611 }
2612
2613
2614 void PrefUserInterface::selectUi()
2615 {
2616         QString file = form_->browseUI(internalPath(uiFileED->text()));
2617         if (!file.isEmpty())
2618                 uiFileED->setText(file);
2619 }
2620
2621
2622 /////////////////////////////////////////////////////////////////////
2623 //
2624 // PrefDocumentHandling
2625 //
2626 /////////////////////////////////////////////////////////////////////
2627
2628 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2629         : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2630 {
2631         setupUi(this);
2632
2633         connect(autoSaveCB, SIGNAL(toggled(bool)),
2634                 autoSaveSB, SLOT(setEnabled(bool)));
2635         connect(autoSaveCB, SIGNAL(toggled(bool)),
2636                 TextLabel1, SLOT(setEnabled(bool)));
2637         connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2638                 this, SIGNAL(changed()));
2639         connect(singleInstanceCB, SIGNAL(clicked()),
2640                 this, SIGNAL(changed()));
2641         connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2642                 this, SIGNAL(changed()));
2643         connect(closeLastViewCO, SIGNAL(activated(int)),
2644                 this, SIGNAL(changed()));
2645         connect(restoreCursorCB, SIGNAL(clicked()),
2646                 this, SIGNAL(changed()));
2647         connect(loadSessionCB, SIGNAL(clicked()),
2648                 this, SIGNAL(changed()));
2649         connect(allowGeometrySessionCB, SIGNAL(clicked()),
2650                 this, SIGNAL(changed()));
2651         connect(autoSaveSB, SIGNAL(valueChanged(int)),
2652                 this, SIGNAL(changed()));
2653         connect(autoSaveCB, SIGNAL(clicked()),
2654                 this, SIGNAL(changed()));
2655         connect(backupCB, SIGNAL(clicked()),
2656                 this, SIGNAL(changed()));
2657         connect(saveCompressedCB, SIGNAL(clicked()),
2658                 this, SIGNAL(changed()));
2659         connect(saveOriginCB, SIGNAL(clicked()),
2660                 this, SIGNAL(changed()));
2661 }
2662
2663
2664 void PrefDocHandling::applyRC(LyXRC & rc) const
2665 {
2666         rc.use_lastfilepos = restoreCursorCB->isChecked();
2667         rc.load_session = loadSessionCB->isChecked();
2668         rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2669         rc.autosave = autoSaveCB->isChecked() ?  autoSaveSB->value() * 60 : 0;
2670         rc.make_backup = backupCB->isChecked();
2671         rc.save_compressed = saveCompressedCB->isChecked();
2672         rc.save_origin = saveOriginCB->isChecked();
2673         rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2674         rc.single_instance = singleInstanceCB->isChecked();
2675         rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2676
2677         switch (closeLastViewCO->currentIndex()) {
2678         case 0:
2679                 rc.close_buffer_with_last_view = "yes";
2680                 break;
2681         case 1:
2682                 rc.close_buffer_with_last_view = "no";
2683                 break;
2684         case 2:
2685                 rc.close_buffer_with_last_view = "ask";
2686                 break;
2687         default:
2688                 ;
2689         }
2690 }
2691
2692
2693 void PrefDocHandling::updateRC(LyXRC const & rc)
2694 {
2695         restoreCursorCB->setChecked(rc.use_lastfilepos);
2696         loadSessionCB->setChecked(rc.load_session);
2697         allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2698         // convert to minutes
2699         bool autosave = rc.autosave > 0;
2700         int mins = rc.autosave / 60;
2701         if (!mins)
2702                 mins = 5;
2703         autoSaveSB->setValue(mins);
2704         autoSaveCB->setChecked(autosave);
2705         autoSaveSB->setEnabled(autosave);
2706         backupCB->setChecked(rc.make_backup);
2707         saveCompressedCB->setChecked(rc.save_compressed);
2708         saveOriginCB->setChecked(rc.save_origin);
2709         openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2710         singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2711         singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2712         singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2713         if (rc.close_buffer_with_last_view == "yes")
2714                 closeLastViewCO->setCurrentIndex(0);
2715         else if (rc.close_buffer_with_last_view == "no")
2716                 closeLastViewCO->setCurrentIndex(1);
2717         else if (rc.close_buffer_with_last_view == "ask")
2718                 closeLastViewCO->setCurrentIndex(2);
2719 }
2720
2721
2722 void PrefDocHandling::on_clearSessionPB_clicked()
2723 {
2724         guiApp->clearSession();
2725 }
2726
2727
2728
2729 /////////////////////////////////////////////////////////////////////
2730 //
2731 // PrefEdit
2732 //
2733 /////////////////////////////////////////////////////////////////////
2734
2735 PrefEdit::PrefEdit(GuiPreferences * form)
2736         : PrefModule(catEditing, N_("Control"), form)
2737 {
2738         setupUi(this);
2739
2740         connect(cursorFollowsCB, SIGNAL(clicked()),
2741                 this, SIGNAL(changed()));
2742         connect(scrollBelowCB, SIGNAL(clicked()),
2743                 this, SIGNAL(changed()));
2744         connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2745                 this, SIGNAL(changed()));
2746         connect(copyCTMarkupCB, SIGNAL(clicked()),
2747                 this, SIGNAL(changed()));
2748         connect(sortEnvironmentsCB, SIGNAL(clicked()),
2749                 this, SIGNAL(changed()));
2750         connect(groupEnvironmentsCB, SIGNAL(clicked()),
2751                 this, SIGNAL(changed()));
2752         connect(macroEditStyleCO, SIGNAL(activated(int)),
2753                 this, SIGNAL(changed()));
2754         connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2755                 this, SIGNAL(changed()));
2756         connect(citationSearchLE, SIGNAL(textChanged(QString)),
2757                 this, SIGNAL(changed()));
2758         connect(fullscreenWidthSB, SIGNAL(valueChanged(int)),
2759                 this, SIGNAL(changed()));
2760         connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2761                 this, SIGNAL(changed()));
2762         connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2763                 this, SIGNAL(changed()));
2764         connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2765                 this, SIGNAL(changed()));
2766         connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2767                 this, SIGNAL(changed()));
2768         connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2769                 this, SIGNAL(changed()));
2770 }
2771
2772
2773 void PrefEdit::on_fullscreenLimitCB_toggled(bool const state)
2774 {
2775         fullscreenWidthSB->setEnabled(state);
2776         fullscreenWidthLA->setEnabled(state);
2777         changed();
2778 }
2779
2780
2781 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2782 {
2783         citationSearchLE->setEnabled(state);
2784         citationSearchLA->setEnabled(state);
2785         changed();
2786 }
2787
2788
2789 void PrefEdit::applyRC(LyXRC & rc) const
2790 {
2791         rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2792         rc.scroll_below_document = scrollBelowCB->isChecked();
2793         rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2794         rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2795         rc.sort_layouts = sortEnvironmentsCB->isChecked();
2796         rc.group_layouts = groupEnvironmentsCB->isChecked();
2797         switch (macroEditStyleCO->currentIndex()) {
2798                 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2799                 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2800                 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST;   break;
2801         }
2802         rc.cursor_width = cursorWidthSB->value();
2803         rc.citation_search = citationSearchCB->isChecked();
2804         rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2805         rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2806         rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2807         rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2808         rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2809         rc.full_screen_menubar = toggleMenubarCB->isChecked();
2810         rc.full_screen_width = fullscreenWidthSB->value();
2811         rc.full_screen_limit = fullscreenLimitCB->isChecked();
2812 }
2813
2814
2815 void PrefEdit::updateRC(LyXRC const & rc)
2816 {
2817         cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2818         scrollBelowCB->setChecked(rc.scroll_below_document);
2819         macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2820         copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2821         sortEnvironmentsCB->setChecked(rc.sort_layouts);
2822         groupEnvironmentsCB->setChecked(rc.group_layouts);
2823         macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2824         cursorWidthSB->setValue(rc.cursor_width);
2825         citationSearchCB->setChecked(rc.citation_search);
2826         citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2827         citationSearchLE->setEnabled(rc.citation_search);
2828         citationSearchLA->setEnabled(rc.citation_search);
2829         toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2830         toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2831         toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2832         toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2833         toggleMenubarCB->setChecked(rc.full_screen_menubar);
2834         fullscreenWidthSB->setValue(rc.full_screen_width);
2835         fullscreenLimitCB->setChecked(rc.full_screen_limit);
2836         fullscreenWidthSB->setEnabled(rc.full_screen_limit);
2837         fullscreenWidthLA->setEnabled(rc.full_screen_limit);
2838 }
2839
2840
2841 /////////////////////////////////////////////////////////////////////
2842 //
2843 // PrefShortcuts
2844 //
2845 /////////////////////////////////////////////////////////////////////
2846
2847
2848 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2849 {
2850         Ui::shortcutUi::setupUi(this);
2851         QDialog::setModal(true);
2852         lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2853 }
2854
2855
2856 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2857         : PrefModule(catEditing, N_("Shortcuts"), form),
2858           editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2859           systemItem_(nullptr)
2860 {
2861         setupUi(this);
2862
2863         shortcutsTW->setColumnCount(2);
2864         shortcutsTW->headerItem()->setText(0, qt_("Function"));
2865         shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2866         shortcutsTW->setSortingEnabled(true);
2867         // Multi-selection can be annoying.
2868         // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2869
2870         connect(bindFilePB, SIGNAL(clicked()),
2871                 this, SLOT(selectBind()));
2872         connect(bindFileED, SIGNAL(textChanged(QString)),
2873                 this, SIGNAL(changed()));
2874
2875         shortcut_ = new GuiShortcutDialog(this);
2876         shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2877         shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2878         shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2879
2880         connect(shortcut_->buttonBox, SIGNAL(accepted()),
2881                 this, SIGNAL(changed()));
2882         connect(shortcut_->buttonBox, SIGNAL(rejected()),
2883                 shortcut_, SLOT(reject()));
2884         connect(shortcut_->clearPB, SIGNAL(clicked()),
2885                 this, SLOT(shortcutClearPressed()));
2886         connect(shortcut_->removePB, SIGNAL(clicked()),
2887                 this, SLOT(shortcutRemovePressed()));
2888         connect(shortcut_->buttonBox, SIGNAL(accepted()),
2889                 this, SLOT(shortcutOkPressed()));
2890         connect(shortcut_->buttonBox, SIGNAL(rejected()),
2891                 this, SLOT(shortcutCancelPressed()));
2892 }
2893
2894
2895 void PrefShortcuts::applyRC(LyXRC & rc) const
2896 {
2897         rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2898         // write user_bind and user_unbind to .lyx/bind/user.bind
2899         FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2900         if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2901                 lyxerr << "LyX could not create the user bind directory '"
2902                        << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2903                 return;
2904         }
2905         if (!bind_dir.isDirWritable()) {
2906                 lyxerr << "LyX could not write to the user bind directory '"
2907                        << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2908                 return;
2909         }
2910         FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2911         user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2912         user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2913         // immediately apply the keybindings. Why this is not done before?
2914         // The good thing is that the menus are updated automatically.
2915         theTopLevelKeymap().clear();
2916         theTopLevelKeymap().read("site");
2917         theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2918         theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2919 }
2920
2921
2922 void PrefShortcuts::updateRC(LyXRC const & rc)
2923 {
2924         bindFileED->setText(toqstr(external_path(rc.bind_file)));
2925         //
2926         system_bind_.clear();
2927         user_bind_.clear();
2928         user_unbind_.clear();
2929         system_bind_.read("site");
2930         system_bind_.read(rc.bind_file);
2931         // \unbind in user.bind is added to user_unbind_
2932         user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2933         updateShortcutsTW();
2934 }
2935
2936
2937 void PrefShortcuts::updateShortcutsTW()
2938 {
2939         shortcutsTW->clear();
2940
2941         editItem_ = new QTreeWidgetItem(shortcutsTW);
2942         editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2943         editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
2944
2945         mathItem_ = new QTreeWidgetItem(shortcutsTW);
2946         mathItem_->setText(0, qt_("Mathematical Symbols"));
2947         mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
2948
2949         bufferItem_ = new QTreeWidgetItem(shortcutsTW);
2950         bufferItem_->setText(0, qt_("Document and Window"));
2951         bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
2952
2953         layoutItem_ = new QTreeWidgetItem(shortcutsTW);
2954         layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
2955         layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
2956
2957         systemItem_ = new QTreeWidgetItem(shortcutsTW);
2958         systemItem_->setText(0, qt_("System and Miscellaneous"));
2959         systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
2960
2961         // listBindings(unbound=true) lists all bound and unbound lfuns
2962         // Items in this list is tagged by its source.
2963         KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
2964                 KeyMap::System);
2965         KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
2966                 KeyMap::UserBind);
2967         KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
2968                 KeyMap::UserUnbind);
2969         bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
2970                         user_bindinglist.end());
2971         bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
2972                         user_unbindinglist.end());
2973
2974         KeyMap::BindingList::const_iterator it = bindinglist.begin();
2975         KeyMap::BindingList::const_iterator it_end = bindinglist.end();
2976         for (; it != it_end; ++it)
2977                 insertShortcutItem(it->request, it->sequence, it->tag);
2978
2979         shortcutsTW->sortItems(0, Qt::AscendingOrder);
2980         on_shortcutsTW_itemSelectionChanged();
2981         on_searchLE_textEdited();
2982         shortcutsTW->resizeColumnToContents(0);
2983 }
2984
2985
2986 //static
2987 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
2988 {
2989         return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
2990 }
2991
2992
2993 //static
2994 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
2995 {
2996         // Hide rebound system settings that are empty
2997         return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
2998 }
2999
3000
3001 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3002 {
3003         item->setData(0, Qt::UserRole, QVariant(tag));
3004         QFont font;
3005
3006         switch (tag) {
3007         case KeyMap::System:
3008                 break;
3009         case KeyMap::UserBind:
3010                 font.setBold(true);
3011                 break;
3012         case KeyMap::UserUnbind:
3013                 font.setStrikeOut(true);
3014                 break;
3015         // this item is not displayed now.
3016         case KeyMap::UserExtraUnbind:
3017                 font.setStrikeOut(true);
3018                 break;
3019         }
3020         item->setHidden(isAlwaysHidden(*item));
3021         item->setFont(1, font);
3022 }
3023
3024
3025 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3026                 KeySequence const & seq, KeyMap::ItemType tag)
3027 {
3028         FuncCode const action = lfun.action();
3029         string const action_name = lyxaction.getActionName(action);
3030         QString const lfun_name = toqstr(from_utf8(action_name)
3031                         + ' ' + lfun.argument());
3032         QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3033
3034         QTreeWidgetItem * newItem = nullptr;
3035         // for unbind items, try to find an existing item in the system bind list
3036         if (tag == KeyMap::UserUnbind) {
3037                 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(lfun_name,
3038                         Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3039                 for (auto const & item : items) {
3040                         if (item->text(1) == shortcut) {
3041                                 newItem = item;
3042                                 break;
3043                         }
3044                 }
3045                 // if not found, this unbind item is KeyMap::UserExtraUnbind
3046                 // Such an item is not displayed to avoid confusion (what is
3047                 // unmatched removed?).
3048                 if (!newItem) {
3049                         return nullptr;
3050                 }
3051         }
3052         if (!newItem) {
3053                 switch(lyxaction.getActionType(action)) {
3054                 case LyXAction::Hidden:
3055                         return nullptr;
3056                 case LyXAction::Edit:
3057                         newItem = new QTreeWidgetItem(editItem_);
3058                         break;
3059                 case LyXAction::Math:
3060                         newItem = new QTreeWidgetItem(mathItem_);
3061                         break;
3062                 case LyXAction::Buffer:
3063                         newItem = new QTreeWidgetItem(bufferItem_);
3064                         break;
3065                 case LyXAction::Layout:
3066                         newItem = new QTreeWidgetItem(layoutItem_);
3067                         break;
3068                 case LyXAction::System:
3069                         newItem = new QTreeWidgetItem(systemItem_);
3070                         break;
3071                 default:
3072                         // this should not happen
3073                         newItem = new QTreeWidgetItem(shortcutsTW);
3074                 }
3075         }
3076
3077         newItem->setText(0, lfun_name);
3078         newItem->setText(1, shortcut);
3079         // record BindFile representation to recover KeySequence when needed.
3080         newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3081         setItemType(newItem, tag);
3082         return newItem;
3083 }
3084
3085
3086 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3087 {
3088         QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3089         removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3090         modifyPB->setEnabled(!items.isEmpty());
3091         if (items.isEmpty())
3092                 return;
3093
3094         if (itemType(*items[0]) == KeyMap::UserUnbind)
3095                 removePB->setText(qt_("Res&tore"));
3096         else
3097                 removePB->setText(qt_("Remo&ve"));
3098 }
3099
3100
3101 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3102 {
3103         modifyShortcut();
3104 }
3105
3106
3107 void PrefShortcuts::modifyShortcut()
3108 {
3109         QTreeWidgetItem * item = shortcutsTW->currentItem();
3110         if (item->flags() & Qt::ItemIsSelectable) {
3111                 shortcut_->lfunLE->setText(item->text(0));
3112                 save_lfun_ = item->text(0).trimmed();
3113                 shortcut_->shortcutWG->setText(item->text(1));
3114                 KeySequence seq;
3115                 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3116                 shortcut_->shortcutWG->setKeySequence(seq);
3117                 shortcut_->shortcutWG->setFocus();
3118                 shortcut_->exec();
3119         }
3120 }
3121
3122
3123 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3124 {
3125         // list of items that match lfun
3126         QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3127              Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3128         for (auto const & item : items) {
3129                 if (isAlwaysHidden(*item)) {
3130                         setItemType(item, KeyMap::System);
3131                         if (select)
3132                                 shortcutsTW->setCurrentItem(item);
3133                         return;
3134                 }
3135         }
3136 }
3137
3138
3139 void PrefShortcuts::removeShortcut()
3140 {
3141         // it seems that only one item can be selected, but I am
3142         // removing all selected items anyway.
3143         QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3144         for (auto & item : items) {
3145                 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3146                 string lfun = fromqstr(item->text(0));
3147                 FuncRequest const func = lyxaction.lookupFunc(lfun);
3148
3149                 switch (itemType(*item)) {
3150                 case KeyMap::System: {
3151                         // for system bind, we do not touch the item
3152                         // but add an user unbind item
3153                         user_unbind_.bind(shortcut, func);
3154                         setItemType(item, KeyMap::UserUnbind);
3155                         removePB->setText(qt_("Res&tore"));
3156                         break;
3157                 }
3158                 case KeyMap::UserBind: {
3159                         // for user_bind, we remove this bind
3160                         QTreeWidgetItem * parent = item->parent();
3161                         int itemIdx = parent->indexOfChild(item);
3162                         parent->takeChild(itemIdx);
3163                         if (itemIdx > 0)
3164                                 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3165                         else
3166                                 shortcutsTW->scrollToItem(parent);
3167                         user_bind_.unbind(shortcut, func);
3168                         // If this user binding hid an empty system binding, unhide the
3169                         // latter and select it.
3170                         unhideEmpty(item->text(0), true);
3171                         break;
3172                 }
3173                 case KeyMap::UserUnbind: {
3174                         // for user_unbind, we remove the unbind, and the item
3175                         // become KeyMap::System again.
3176                         KeySequence seq;
3177                         seq.parse(shortcut);
3178                         // Ask the user to replace current binding
3179                         if (!validateNewShortcut(func, seq, QString()))
3180                                 break;
3181                         user_unbind_.unbind(shortcut, func);
3182                         setItemType(item, KeyMap::System);
3183                         removePB->setText(qt_("Remo&ve"));
3184                         break;
3185                 }
3186                 case KeyMap::UserExtraUnbind: {
3187                         // for user unbind that is not in system bind file,
3188                         // remove this unbind file
3189                         QTreeWidgetItem * parent = item->parent();
3190                         parent->takeChild(parent->indexOfChild(item));
3191                         user_unbind_.unbind(shortcut, func);
3192                 }
3193                 }
3194         }
3195 }
3196
3197
3198 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3199 {
3200         for (auto item : items) {
3201                 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3202                 string lfun = fromqstr(item->text(0));
3203                 FuncRequest const func = lyxaction.lookupFunc(lfun);
3204
3205                 switch (itemType(*item)) {
3206                 case KeyMap::System:
3207                         // for system bind, we do not touch the item
3208                         // but add an user unbind item
3209                         user_unbind_.bind(shortcut, func);
3210                         setItemType(item, KeyMap::UserUnbind);
3211                         break;
3212
3213                 case KeyMap::UserBind: {
3214                         // for user_bind, we remove this bind
3215                         QTreeWidgetItem * parent = item->parent();
3216                         int itemIdx = parent->indexOfChild(item);
3217                         parent->takeChild(itemIdx);
3218                         user_bind_.unbind(shortcut, func);
3219                         unhideEmpty(item->text(0), false);
3220                         break;
3221                 }
3222                 default:
3223                         break;
3224                 }
3225         }
3226 }
3227
3228
3229 void PrefShortcuts::selectBind()
3230 {
3231         QString file = form_->browsebind(internalPath(bindFileED->text()));
3232         if (!file.isEmpty()) {
3233                 bindFileED->setText(file);
3234                 system_bind_ = KeyMap();
3235                 system_bind_.read(fromqstr(file));
3236                 updateShortcutsTW();
3237         }
3238 }
3239
3240
3241 void PrefShortcuts::on_modifyPB_pressed()
3242 {
3243         modifyShortcut();
3244 }
3245
3246
3247 void PrefShortcuts::on_newPB_pressed()
3248 {
3249         shortcut_->lfunLE->clear();
3250         shortcut_->shortcutWG->reset();
3251         save_lfun_ = QString();
3252         shortcut_->exec();
3253 }
3254
3255
3256 void PrefShortcuts::on_removePB_pressed()
3257 {
3258         changed();
3259         removeShortcut();
3260 }
3261
3262
3263 void PrefShortcuts::on_searchLE_textEdited()
3264 {
3265         if (searchLE->text().isEmpty()) {
3266                 // show all hidden items
3267                 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3268                 for (; *it; ++it)
3269                         (*it)->setHidden(isAlwaysHidden(**it));
3270                 // close all categories
3271                 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3272                         shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3273                 return;
3274         }
3275         // search both columns
3276         QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3277                 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3278         matched += shortcutsTW->findItems(searchLE->text(),
3279                 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3280
3281         // hide everyone (to avoid searching in matched QList repeatedly
3282         QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3283         while (*it)
3284                 (*it++)->setHidden(true);
3285         // show matched items
3286         for (auto & item : matched)
3287                 if (!isAlwaysHidden(*item)) {
3288                         item->setHidden(false);
3289                         if (item->parent())
3290                                 item->parent()->setExpanded(true);
3291                 }
3292 }
3293
3294
3295 docstring makeCmdString(FuncRequest const & f)
3296 {
3297         docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3298         if (!f.argument().empty())
3299                 actionStr += " " + f.argument();
3300         return actionStr;
3301 }
3302
3303
3304 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3305 {
3306         FuncRequest res = user_bind_.getBinding(k);
3307         if (res.action() != LFUN_UNKNOWN_ACTION)
3308                 return res;
3309         res = system_bind_.getBinding(k);
3310         // Check if it is unbound. Note: user_unbind_ can only unbind one
3311         // FuncRequest per key sequence.
3312         if (user_unbind_.getBinding(k) == res)
3313                 return FuncRequest::unknown;
3314         return res;
3315 }
3316
3317
3318 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3319                                         KeySequence const & k,
3320                                         QString const & lfun_to_modify)
3321 {
3322         if (func.action() == LFUN_UNKNOWN_ACTION) {
3323                 Alert::error(_("Failed to create shortcut"),
3324                         _("Unknown or invalid LyX function"));
3325                 return false;
3326         }
3327
3328         // It is not currently possible to bind Hidden lfuns such as self-insert. In
3329         // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3330         // and how it is used in GuiPrefs::shortcutOkPressed.
3331         if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3332                 Alert::error(_("Failed to create shortcut"),
3333                         _("This LyX function is hidden and cannot be bound."));
3334                 return false;
3335         }
3336
3337         if (k.length() == 0) {
3338                 Alert::error(_("Failed to create shortcut"),
3339                         _("Invalid or empty key sequence"));
3340                 return false;
3341         }
3342
3343         FuncRequest oldBinding = currentBinding(k);
3344         if (oldBinding == func)
3345                 // nothing to change
3346                 return false;
3347
3348         // make sure this key isn't already bound---and, if so, prompt user
3349         // (exclude the lfun the user already wants to modify)
3350         docstring const action_string = makeCmdString(oldBinding);
3351         if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3352             && lfun_to_modify != toqstr(action_string)) {
3353                 docstring const new_action_string = makeCmdString(func);
3354                 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3355                                                  "%2$s.\n"
3356                                                  "Are you sure you want to unbind the "
3357                                                  "current shortcut and bind it to %3$s?"),
3358                                                k.print(KeySequence::ForGui), action_string,
3359                                                new_action_string);
3360                 int ret = Alert::prompt(_("Redefine shortcut?"),
3361                                         text, 0, 1, _("&Redefine"), _("&Cancel"));
3362                 if (ret != 0)
3363                         return false;
3364                 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3365                 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3366                         Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3367                 deactivateShortcuts(items);
3368         }
3369         return true;
3370 }
3371
3372
3373 void PrefShortcuts::shortcutOkPressed()
3374 {
3375         QString const new_lfun = shortcut_->lfunLE->text();
3376         FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3377         KeySequence k = shortcut_->shortcutWG->getKeySequence();
3378
3379         // save_lfun_ contains the text of the lfun to modify, if the user clicked
3380         // "modify", or is empty if they clicked "new" (which I do not really like)
3381         if (!validateNewShortcut(func, k, save_lfun_))
3382                 return;
3383
3384         if (!save_lfun_.isEmpty()) {
3385                 // real modification of the lfun's shortcut,
3386                 // so remove the previous one
3387                 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3388                 deactivateShortcuts(to_modify);
3389         }
3390
3391         shortcut_->accept();
3392
3393         QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3394         if (item) {
3395                 user_bind_.bind(&k, func);
3396                 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3397                 item->parent()->setExpanded(true);
3398                 shortcutsTW->setCurrentItem(item);
3399                 shortcutsTW->scrollToItem(item);
3400         } else {
3401                 Alert::error(_("Failed to create shortcut"),
3402                         _("Can not insert shortcut to the list"));
3403                 return;
3404         }
3405 }
3406
3407
3408 void PrefShortcuts::shortcutCancelPressed()
3409 {
3410         shortcut_->shortcutWG->reset();
3411 }
3412
3413
3414 void PrefShortcuts::shortcutClearPressed()
3415 {
3416         shortcut_->shortcutWG->reset();
3417 }
3418
3419
3420 void PrefShortcuts::shortcutRemovePressed()
3421 {
3422         shortcut_->shortcutWG->removeFromSequence();
3423 }
3424
3425
3426 /////////////////////////////////////////////////////////////////////
3427 //
3428 // PrefIdentity
3429 //
3430 /////////////////////////////////////////////////////////////////////
3431
3432 PrefIdentity::PrefIdentity(GuiPreferences * form)
3433         : PrefModule(QString(), N_("Identity"), form)
3434 {
3435         setupUi(this);
3436
3437         connect(nameED, SIGNAL(textChanged(QString)),
3438                 this, SIGNAL(changed()));
3439         connect(emailED, SIGNAL(textChanged(QString)),
3440                 this, SIGNAL(changed()));
3441         connect(initialsED, SIGNAL(textChanged(QString)),
3442                 this, SIGNAL(changed()));
3443
3444         nameED->setValidator(new NoNewLineValidator(nameED));
3445         emailED->setValidator(new NoNewLineValidator(emailED));
3446         initialsED->setValidator(new NoNewLineValidator(initialsED));
3447 }
3448
3449
3450 void PrefIdentity::applyRC(LyXRC & rc) const
3451 {
3452         rc.user_name = fromqstr(nameED->text());
3453         rc.user_email = fromqstr(emailED->text());
3454         rc.user_initials = fromqstr(initialsED->text());
3455 }
3456
3457
3458 void PrefIdentity::updateRC(LyXRC const & rc)
3459 {
3460         nameED->setText(toqstr(rc.user_name));
3461         emailED->setText(toqstr(rc.user_email));
3462         initialsED->setText(toqstr(rc.user_initials));
3463 }
3464
3465
3466
3467 /////////////////////////////////////////////////////////////////////
3468 //
3469 // GuiPreferences
3470 //
3471 /////////////////////////////////////////////////////////////////////
3472
3473 GuiPreferences::GuiPreferences(GuiView & lv)
3474         : GuiDialog(lv, "prefs", qt_("Preferences"))
3475 {
3476         setupUi(this);
3477
3478         QDialog::setModal(false);
3479
3480         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3481                 this, SLOT(slotButtonBox(QAbstractButton *)));
3482
3483         addModule(new PrefUserInterface(this));
3484         addModule(new PrefDocHandling(this));
3485         addModule(new PrefEdit(this));
3486         addModule(new PrefShortcuts(this));
3487         PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3488         connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3489                         screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3490         addModule(screenfonts);
3491         addModule(new PrefColors(this));
3492         addModule(new PrefDisplay(this));
3493         addModule(new PrefInput(this));
3494         addModule(new PrefCompletion(this));
3495
3496         addModule(new PrefPaths(this));
3497
3498         addModule(new PrefIdentity(this));
3499
3500         addModule(new PrefLanguage(this));
3501         addModule(new PrefSpellchecker(this));
3502
3503         PrefOutput * output = new PrefOutput(this);
3504         addModule(output);
3505         addModule(new PrefLatex(this));
3506
3507         PrefConverters * converters = new PrefConverters(this);
3508         PrefFileformats * formats = new PrefFileformats(this);
3509         connect(formats, SIGNAL(formatsChanged()),
3510                         converters, SLOT(updateGui()));
3511         addModule(converters);
3512         addModule(formats);
3513
3514         prefsPS->setCurrentPanel("User Interface");
3515 // FIXME: hack to work around resizing bug in Qt >= 4.2
3516 // bug verified with Qt 4.2.{0-3} (JSpitzm)
3517 #if QT_VERSION >= 0x040200
3518         prefsPS->updateGeometry();
3519 #endif
3520
3521         bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3522         bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3523         bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3524         bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3525         bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3526
3527         guilyxfiles_ = new GuiLyXFiles(lv);
3528         connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3529                         this, SLOT(slotFileSelected(QString)));
3530 }
3531
3532
3533 void GuiPreferences::addModule(PrefModule * module)
3534 {
3535         LASSERT(module, return);
3536         if (module->category().isEmpty())
3537                 prefsPS->addPanel(module, module->title());
3538         else
3539                 prefsPS->addPanel(module, module->title(), module->category());
3540         connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3541         modules_.push_back(module);
3542 }
3543
3544
3545 void GuiPreferences::change_adaptor()
3546 {
3547         changed();
3548 }
3549
3550
3551 void GuiPreferences::applyRC(LyXRC & rc) const
3552 {
3553         size_t end = modules_.size();
3554         for (size_t i = 0; i != end; ++i)
3555                 modules_[i]->applyRC(rc);
3556 }
3557
3558
3559 void GuiPreferences::updateRC(LyXRC const & rc)
3560 {
3561         size_t const end = modules_.size();
3562         for (size_t i = 0; i != end; ++i)
3563                 modules_[i]->updateRC(rc);
3564 }
3565
3566
3567 void GuiPreferences::applyView()
3568 {
3569         applyRC(rc());
3570 }
3571
3572
3573 bool GuiPreferences::initialiseParams(string const &)
3574 {
3575         rc_ = lyxrc;
3576         formats_ = theFormats();
3577         converters_ = theConverters();
3578         converters_.update(formats_);
3579         movers_ = theMovers();
3580         colors_.clear();
3581
3582         updateRC(rc_);
3583         // Make sure that the bc is in the INITIAL state
3584         if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3585                 bc().restore();
3586
3587         return true;
3588 }
3589
3590
3591 void GuiPreferences::dispatchParams()
3592 {
3593         ostringstream ss;
3594         rc_.write(ss, true);
3595         dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3596         // issue prefsApplied signal. This will update the
3597         // localized screen font sizes.
3598         prefsApplied(rc_);
3599         // FIXME: these need lfuns
3600         // FIXME UNICODE
3601         Author const & author =
3602                 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3603                        from_utf8(rc_.user_initials));
3604         theBufferList().recordCurrentAuthor(author);
3605
3606         theFormats() = formats_;
3607
3608         theConverters() = converters_;
3609         theConverters().update(formats_);
3610         theConverters().buildGraph();
3611         theBufferList().invalidateConverterCache();
3612
3613         theMovers() = movers_;
3614
3615         for (string const & color : colors_)
3616                 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3617         colors_.clear();
3618
3619         // Save permanently
3620         if (!tempSaveCB->isChecked())
3621                 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3622 }
3623
3624
3625 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3626 {
3627         colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3628 }
3629
3630
3631 void GuiPreferences::slotFileSelected(QString const file)
3632 {
3633         uifile_ = file;
3634 }
3635
3636
3637 QString GuiPreferences::browseLibFile(QString const & dir,
3638         QString const & name, QString const & ext)
3639 {
3640         uifile_.clear();
3641
3642         guilyxfiles_->passParams(fromqstr(dir));
3643         guilyxfiles_->selectItem(name);
3644         guilyxfiles_->exec();
3645
3646         QString const result = uifile_;
3647
3648         // remove the extension if it is the default one
3649         QString noextresult;
3650         if (getExtension(result) == ext)
3651                 noextresult = removeExtension(result);
3652         else
3653                 noextresult = result;
3654
3655         // remove the directory, if it is the default one
3656         QString const file = onlyFileName(noextresult);
3657         if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3658                 return file;
3659         else
3660                 return noextresult;
3661 }
3662
3663
3664 QString GuiPreferences::browsebind(QString const & file)
3665 {
3666         return browseLibFile("bind", file, "bind");
3667 }
3668
3669
3670 QString GuiPreferences::browseUI(QString const & file)
3671 {
3672         return browseLibFile("ui", file, "ui");
3673 }
3674
3675
3676 QString GuiPreferences::browsekbmap(QString const & file)
3677 {
3678         return browseLibFile("kbd", file, "kmap");
3679 }
3680
3681
3682 QString GuiPreferences::browse(QString const & file,
3683         QString const & title) const
3684 {
3685         return browseFile(file, title, QStringList(), true);
3686 }
3687
3688
3689 Dialog * createGuiPreferences(GuiView & lv) { return new GuiPreferences(lv); }
3690
3691
3692 } // namespace frontend
3693 } // namespace lyx
3694
3695 #include "moc_GuiPrefs.cpp"