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