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