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