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