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