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