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