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