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