3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
16 #include "ColorCache.h"
17 #include "FileDialog.h"
18 #include "GuiApplication.h"
19 #include "GuiFontExample.h"
20 #include "GuiFontLoader.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiLyXFiles.h"
24 #include "qt_helpers.h"
25 #include "Validator.h"
28 #include "BufferList.h"
31 #include "ConverterCache.h"
32 #include "FontEnums.h"
33 #include "FuncRequest.h"
34 #include "KeySequence.h"
36 #include "LyXAction.h"
38 #include "PanelStack.h"
40 #include "SpellChecker.h"
42 #include "support/debug.h"
43 #include "support/FileName.h"
44 #include "support/filetools.h"
45 #include "support/gettext.h"
46 #include "support/lassert.h"
47 #include "support/lstrings.h"
48 #include "support/Messages.h"
49 #include "support/os.h"
50 #include "support/Package.h"
52 #include "frontends/alert.h"
53 #include "frontends/Application.h"
54 #include "frontends/FontLoader.h"
56 #include <QAbstractItemModel>
58 #include <QColorDialog>
59 #include <QFontDatabase>
60 #include <QHeaderView>
62 #include <QMessageBox>
63 #include <QPushButton>
66 #include <QTreeWidget>
67 #include <QTreeWidgetItem>
78 using namespace lyx::support;
79 using namespace lyx::support::os;
84 /////////////////////////////////////////////////////////////////////
88 /////////////////////////////////////////////////////////////////////
90 /** Launch a file dialog and return the chosen file.
91 filename: a suggested filename.
92 title: the title of the dialog.
94 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
96 QString browseFile(QString const & filename,
97 QString const & title,
98 QStringList const & filters,
100 QString const & label1 = QString(),
101 QString const & dir1 = QString(),
102 QString const & label2 = QString(),
103 QString const & dir2 = QString(),
104 QString const & fallback_dir = QString())
106 QString lastPath = ".";
107 if (!filename.isEmpty())
108 lastPath = onlyPath(filename);
109 else if(!fallback_dir.isEmpty())
110 lastPath = fallback_dir;
112 FileDialog dlg(title);
113 dlg.setButton1(label1, dir1);
114 dlg.setButton2(label2, dir2);
116 FileDialog::Result result;
119 result = dlg.save(lastPath, filters, onlyFileName(filename));
121 result = dlg.open(lastPath, filters, onlyFileName(filename));
123 return result.second;
127 /** Launch a file dialog and return the chosen directory.
128 pathname: a suggested pathname.
129 title: the title of the dialog.
130 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
132 QString browseDir(QString const & pathname,
133 QString const & title,
134 QString const & label1 = QString(),
135 QString const & dir1 = QString(),
136 QString const & label2 = QString(),
137 QString const & dir2 = QString())
139 QString lastPath = ".";
140 if (!pathname.isEmpty())
141 lastPath = onlyPath(pathname);
143 FileDialog dlg(title);
144 dlg.setButton1(label1, dir1);
145 dlg.setButton2(label2, dir2);
147 FileDialog::Result const result =
148 dlg.opendir(lastPath, onlyFileName(pathname));
150 return result.second;
154 } // namespace frontend
157 QString browseRelToParent(QString const & filename, QString const & relpath,
158 QString const & title, QStringList const & filters, bool save,
159 QString const & label1, QString const & dir1,
160 QString const & label2, QString const & dir2)
162 QString const fname = makeAbsPath(filename, relpath);
164 QString const outname =
165 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
167 QString const reloutname =
168 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
170 if (reloutname.startsWith("../"))
177 QString browseRelToSub(QString const & filename, QString const & relpath,
178 QString const & title, QStringList const & filters, bool save,
179 QString const & label1, QString const & dir1,
180 QString const & label2, QString const & dir2)
182 QString const fname = makeAbsPath(filename, relpath);
184 QString const outname =
185 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
187 QString const reloutname =
188 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
190 QString testname = reloutname;
191 #if QT_VERSION < 0x060000
192 testname.remove(QRegExp("^(\\.\\./)+"));
194 testname.remove(QRegularExpression("^(\\.\\./)+"));
197 if (testname.contains("/"))
205 /////////////////////////////////////////////////////////////////////
209 /////////////////////////////////////////////////////////////////////
213 QString const catLookAndFeel = N_("Look & Feel");
214 QString const catEditing = N_("Editing");
215 QString const catLanguage = N_("Language Settings");
216 QString const catOutput = N_("Output");
217 QString const catFiles = N_("File Handling");
219 static void parseFontName(QString const & mangled0,
220 string & name, string & foundry)
222 string mangled = fromqstr(mangled0);
223 size_t const idx = mangled.find('[');
224 if (idx == string::npos || idx == 0) {
228 name = mangled.substr(0, idx - 1);
229 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
234 static void setComboxFont(QComboBox * cb, string const & family,
235 string const & foundry)
237 QString fontname = toqstr(family);
238 if (!foundry.empty())
239 fontname += " [" + toqstr(foundry) + ']';
241 for (int i = 0; i != cb->count(); ++i) {
242 if (cb->itemText(i) == fontname) {
243 cb->setCurrentIndex(i);
248 // Try matching without foundry name
250 // We count in reverse in order to prefer the Xft foundry
251 for (int i = cb->count(); --i >= 0;) {
252 string name, fnt_foundry;
253 parseFontName(cb->itemText(i), name, fnt_foundry);
254 if (compare_ascii_no_case(name, family) == 0) {
255 cb->setCurrentIndex(i);
260 // family alone can contain e.g. "Helvetica [Adobe]"
261 string tmpname, tmpfoundry;
262 parseFontName(toqstr(family), tmpname, tmpfoundry);
264 // We count in reverse in order to prefer the Xft foundry
265 for (int i = cb->count(); --i >= 0; ) {
266 string name, fnt_foundry;
267 parseFontName(cb->itemText(i), name, fnt_foundry);
268 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
269 cb->setCurrentIndex(i);
274 // Bleh, default fonts, and the names couldn't be found. Hack
279 QString const font_family = toqstr(family);
280 if (font_family == guiApp->romanFontName()) {
281 font.setStyleHint(QFont::Serif);
282 font.setFamily(font_family);
283 } else if (font_family == guiApp->sansFontName()) {
284 font.setStyleHint(QFont::SansSerif);
285 font.setFamily(font_family);
286 } else if (font_family == guiApp->typewriterFontName()) {
287 font.setStyleHint(QFont::TypeWriter);
288 font.setFamily(font_family);
290 LYXERR0("FAILED to find the default font: '"
291 << foundry << "', '" << family << '\'');
295 QFontInfo info(font);
296 string default_font_name, dummyfoundry;
297 parseFontName(info.family(), default_font_name, dummyfoundry);
298 LYXERR0("Apparent font is " << default_font_name);
300 for (int i = 0; i < cb->count(); ++i) {
301 LYXERR0("Looking at " << cb->itemText(i));
302 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
303 default_font_name) == 0) {
304 cb->setCurrentIndex(i);
309 LYXERR0("FAILED to find the font: '"
310 << foundry << "', '" << family << '\'');
314 /////////////////////////////////////////////////////////////////////
318 /////////////////////////////////////////////////////////////////////
320 PrefOutput::PrefOutput(GuiPreferences * form)
321 : PrefModule(catOutput, N_("General[[settings]]"), form)
325 dviCB->setValidator(new NoNewLineValidator(dviCB));
326 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
328 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
329 this, SIGNAL(changed()));
330 connect(overwriteCO, SIGNAL(activated(int)),
331 this, SIGNAL(changed()));
332 connect(dviCB, SIGNAL(editTextChanged(QString)),
333 this, SIGNAL(changed()));
334 connect(pdfCB, SIGNAL(editTextChanged(QString)),
335 this, SIGNAL(changed()));
336 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
337 this, SIGNAL(changed()));
338 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
339 this, SIGNAL(changed()));
340 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
341 this, SIGNAL(changed()));
343 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
344 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
345 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
348 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
349 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
350 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
351 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
353 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
354 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
355 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
356 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
357 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
358 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
359 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
363 void PrefOutput::applyRC(LyXRC & rc) const
365 rc.plaintext_linelen = plaintextLinelengthSB->value();
366 rc.forward_search_dvi = fromqstr(dviCB->currentText());
367 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
369 switch (overwriteCO->currentIndex()) {
371 rc.export_overwrite = NO_FILES;
374 rc.export_overwrite = MAIN_FILE;
377 rc.export_overwrite = ALL_FILES;
381 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
382 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
383 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
387 void PrefOutput::updateRC(LyXRC const & rc)
389 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
390 dviCB->setEditText(toqstr(rc.forward_search_dvi));
391 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
393 switch (rc.export_overwrite) {
395 overwriteCO->setCurrentIndex(0);
398 overwriteCO->setCurrentIndex(1);
401 overwriteCO->setCurrentIndex(2);
405 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
406 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
407 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
411 /////////////////////////////////////////////////////////////////////
415 /////////////////////////////////////////////////////////////////////
417 PrefInput::PrefInput(GuiPreferences * form)
418 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
422 connect(keymapCB, SIGNAL(clicked()),
423 this, SIGNAL(changed()));
424 connect(firstKeymapED, SIGNAL(textChanged(QString)),
425 this, SIGNAL(changed()));
426 connect(secondKeymapED, SIGNAL(textChanged(QString)),
427 this, SIGNAL(changed()));
428 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
429 this, SIGNAL(changed()));
430 connect(scrollzoomEnableCB, SIGNAL(clicked()),
431 this, SIGNAL(changed()));
432 connect(scrollzoomValueCO, SIGNAL(activated(int)),
433 this, SIGNAL(changed()));
434 connect(dontswapCB, SIGNAL(toggled(bool)),
435 this, SIGNAL(changed()));
436 connect(mmPasteCB, SIGNAL(toggled(bool)),
437 this, SIGNAL(changed()));
439 // reveal checkbox for switching Ctrl and Meta on Mac:
442 #if QT_VERSION > 0x040600
446 dontswapCB->setVisible(swapcb);
450 void PrefInput::applyRC(LyXRC & rc) const
452 // FIXME: can derive CB from the two EDs
453 rc.use_kbmap = keymapCB->isChecked();
454 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
455 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
456 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
457 if (scrollzoomEnableCB->isChecked()) {
458 switch (scrollzoomValueCO->currentIndex()) {
460 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
463 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
466 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
470 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
472 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
473 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
477 void PrefInput::updateRC(LyXRC const & rc)
479 // FIXME: can derive CB from the two EDs
480 keymapCB->setChecked(rc.use_kbmap);
481 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
482 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
483 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
484 switch (rc.scroll_wheel_zoom) {
485 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
486 scrollzoomEnableCB->setChecked(false);
488 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
489 scrollzoomEnableCB->setChecked(true);
490 scrollzoomValueCO->setCurrentIndex(0);
492 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
493 scrollzoomEnableCB->setChecked(true);
494 scrollzoomValueCO->setCurrentIndex(1);
496 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
497 scrollzoomEnableCB->setChecked(true);
498 scrollzoomValueCO->setCurrentIndex(2);
501 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
502 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
506 QString PrefInput::testKeymap(QString const & keymap)
508 return form_->browsekbmap(internalPath(keymap));
512 void PrefInput::on_firstKeymapPB_clicked(bool)
514 QString const file = testKeymap(firstKeymapED->text());
516 firstKeymapED->setText(file);
520 void PrefInput::on_secondKeymapPB_clicked(bool)
522 QString const file = testKeymap(secondKeymapED->text());
524 secondKeymapED->setText(file);
528 void PrefInput::on_keymapCB_toggled(bool keymap)
530 firstKeymapLA->setEnabled(keymap);
531 secondKeymapLA->setEnabled(keymap);
532 firstKeymapED->setEnabled(keymap);
533 secondKeymapED->setEnabled(keymap);
534 firstKeymapPB->setEnabled(keymap);
535 secondKeymapPB->setEnabled(keymap);
539 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
541 scrollzoomValueCO->setEnabled(enabled);
545 /////////////////////////////////////////////////////////////////////
549 /////////////////////////////////////////////////////////////////////
551 PrefCompletion::PrefCompletion(GuiPreferences * form)
552 : PrefModule(catEditing, N_("Input Completion"), form)
556 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
557 this, SIGNAL(changed()));
558 connect(inlineMathCB, SIGNAL(clicked()),
559 this, SIGNAL(changed()));
560 connect(inlineTextCB, SIGNAL(clicked()),
561 this, SIGNAL(changed()));
562 connect(inlineDotsCB, SIGNAL(clicked()),
563 this, SIGNAL(changed()));
564 connect(popupDelaySB, SIGNAL(valueChanged(double)),
565 this, SIGNAL(changed()));
566 connect(popupMathCB, SIGNAL(clicked()),
567 this, SIGNAL(changed()));
568 connect(autocorrectionCB, SIGNAL(clicked()),
569 this, SIGNAL(changed()));
570 connect(popupTextCB, SIGNAL(clicked()),
571 this, SIGNAL(changed()));
572 connect(popupAfterCompleteCB, SIGNAL(clicked()),
573 this, SIGNAL(changed()));
574 connect(cursorTextCB, SIGNAL(clicked()),
575 this, SIGNAL(changed()));
576 connect(minlengthSB, SIGNAL(valueChanged(int)),
577 this, SIGNAL(changed()));
581 void PrefCompletion::on_inlineTextCB_clicked()
587 void PrefCompletion::on_popupTextCB_clicked()
593 void PrefCompletion::enableCB()
595 cursorTextCB->setEnabled(
596 popupTextCB->isChecked() || inlineTextCB->isChecked());
600 void PrefCompletion::applyRC(LyXRC & rc) const
602 rc.completion_inline_delay = inlineDelaySB->value();
603 rc.completion_inline_math = inlineMathCB->isChecked();
604 rc.completion_inline_text = inlineTextCB->isChecked();
605 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
606 rc.completion_popup_delay = popupDelaySB->value();
607 rc.completion_popup_math = popupMathCB->isChecked();
608 rc.autocorrection_math = autocorrectionCB->isChecked();
609 rc.completion_popup_text = popupTextCB->isChecked();
610 rc.completion_cursor_text = cursorTextCB->isChecked();
611 rc.completion_popup_after_complete =
612 popupAfterCompleteCB->isChecked();
613 rc.completion_minlength = minlengthSB->value();
617 void PrefCompletion::updateRC(LyXRC const & rc)
619 inlineDelaySB->setValue(rc.completion_inline_delay);
620 inlineMathCB->setChecked(rc.completion_inline_math);
621 inlineTextCB->setChecked(rc.completion_inline_text);
622 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
623 popupDelaySB->setValue(rc.completion_popup_delay);
624 popupMathCB->setChecked(rc.completion_popup_math);
625 autocorrectionCB->setChecked(rc.autocorrection_math);
626 popupTextCB->setChecked(rc.completion_popup_text);
627 cursorTextCB->setChecked(rc.completion_cursor_text);
628 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
630 minlengthSB->setValue(rc.completion_minlength);
635 /////////////////////////////////////////////////////////////////////
639 /////////////////////////////////////////////////////////////////////
641 PrefLatex::PrefLatex(GuiPreferences * form)
642 : PrefModule(catOutput, N_("LaTeX"), form)
646 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
647 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
648 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
649 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
650 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
651 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
652 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
654 connect(latexChecktexED, SIGNAL(textChanged(QString)),
655 this, SIGNAL(changed()));
656 connect(latexBibtexCO, SIGNAL(activated(int)),
657 this, SIGNAL(changed()));
658 connect(latexBibtexED, SIGNAL(textChanged(QString)),
659 this, SIGNAL(changed()));
660 connect(latexJBibtexCO, SIGNAL(activated(int)),
661 this, SIGNAL(changed()));
662 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
663 this, SIGNAL(changed()));
664 connect(latexIndexCO, SIGNAL(activated(int)),
665 this, SIGNAL(changed()));
666 connect(latexIndexED, SIGNAL(textChanged(QString)),
667 this, SIGNAL(changed()));
668 connect(latexJIndexED, SIGNAL(textChanged(QString)),
669 this, SIGNAL(changed()));
670 connect(latexAutoresetCB, SIGNAL(clicked()),
671 this, SIGNAL(changed()));
672 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
673 this, SIGNAL(changed()));
674 connect(latexNomenclED, SIGNAL(textChanged(QString)),
675 this, SIGNAL(changed()));
677 #if defined(__CYGWIN__) || defined(_WIN32)
678 pathCB->setVisible(true);
679 connect(pathCB, SIGNAL(clicked()),
680 this, SIGNAL(changed()));
682 pathCB->setVisible(false);
687 void PrefLatex::on_latexBibtexCO_activated(int n)
689 QString const bibtex = latexBibtexCO->itemData(n).toString();
690 if (bibtex.isEmpty()) {
691 latexBibtexED->clear();
692 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
695 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
696 it != bibtex_alternatives.end(); ++it) {
697 QString const bib = toqstr(*it);
698 int ind = bib.indexOf(" ");
699 QString sel_command = bib.left(ind);
700 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
701 if (bibtex == sel_command) {
703 latexBibtexED->clear();
705 latexBibtexED->setText(sel_options.trimmed());
708 latexBibtexOptionsLA->setText(qt_("&Options:"));
712 void PrefLatex::on_latexJBibtexCO_activated(int n)
714 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
715 if (jbibtex.isEmpty()) {
716 latexJBibtexED->clear();
717 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
720 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
721 it != jbibtex_alternatives.end(); ++it) {
722 QString const bib = toqstr(*it);
723 int ind = bib.indexOf(" ");
724 QString sel_command = bib.left(ind);
725 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
726 if (jbibtex == sel_command) {
728 latexJBibtexED->clear();
730 latexJBibtexED->setText(sel_options.trimmed());
733 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
737 void PrefLatex::on_latexIndexCO_activated(int n)
739 QString const index = latexIndexCO->itemData(n).toString();
740 if (index.isEmpty()) {
741 latexIndexED->clear();
742 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
745 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
746 it != index_alternatives.end(); ++it) {
747 QString const idx = toqstr(*it);
748 int ind = idx.indexOf(" ");
749 QString sel_command = idx.left(ind);
750 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
751 if (index == sel_command) {
753 latexIndexED->clear();
755 latexIndexED->setText(sel_options.trimmed());
758 latexIndexOptionsLA->setText(qt_("Op&tions:"));
762 void PrefLatex::applyRC(LyXRC & rc) const
764 // If bibtex is not empty, bibopt contains the options, otherwise
765 // it is a customized bibtex command with options.
766 QString const bibtex = latexBibtexCO->itemData(
767 latexBibtexCO->currentIndex()).toString();
768 QString const bibopt = latexBibtexED->text();
769 if (bibtex.isEmpty())
770 rc.bibtex_command = fromqstr(bibopt);
771 else if (bibopt.isEmpty())
772 rc.bibtex_command = fromqstr(bibtex);
774 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
776 // If jbibtex is not empty, jbibopt contains the options, otherwise
777 // it is a customized bibtex command with options.
778 QString const jbibtex = latexJBibtexCO->itemData(
779 latexJBibtexCO->currentIndex()).toString();
780 QString const jbibopt = latexJBibtexED->text();
781 if (jbibtex.isEmpty())
782 rc.jbibtex_command = fromqstr(jbibopt);
783 else if (jbibopt.isEmpty())
784 rc.jbibtex_command = fromqstr(jbibtex);
786 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
788 // If index is not empty, idxopt contains the options, otherwise
789 // it is a customized index command with options.
790 QString const index = latexIndexCO->itemData(
791 latexIndexCO->currentIndex()).toString();
792 QString const idxopt = latexIndexED->text();
794 rc.index_command = fromqstr(idxopt);
795 else if (idxopt.isEmpty())
796 rc.index_command = fromqstr(index);
798 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
800 rc.chktex_command = fromqstr(latexChecktexED->text());
801 rc.jindex_command = fromqstr(latexJIndexED->text());
802 rc.nomencl_command = fromqstr(latexNomenclED->text());
803 rc.auto_reset_options = latexAutoresetCB->isChecked();
804 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
805 #if defined(__CYGWIN__) || defined(_WIN32)
806 rc.windows_style_tex_paths = pathCB->isChecked();
811 void PrefLatex::updateRC(LyXRC const & rc)
813 latexBibtexCO->clear();
815 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
816 latexBibtexCO->addItem(qt_("Custom"), QString());
817 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
818 it != rc.bibtex_alternatives.end(); ++it) {
819 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
820 latexBibtexCO->addItem(command, command);
823 bibtex_alternatives = rc.bibtex_alternatives;
825 QString const bib = toqstr(rc.bibtex_command);
826 int ind = bib.indexOf(" ");
827 QString sel_command = bib.left(ind);
828 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
830 int pos = latexBibtexCO->findData(sel_command);
832 latexBibtexCO->setCurrentIndex(pos);
833 latexBibtexED->setText(sel_options.trimmed());
834 latexBibtexOptionsLA->setText(qt_("&Options:"));
836 latexBibtexED->setText(toqstr(rc.bibtex_command));
837 latexBibtexCO->setCurrentIndex(0);
838 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
841 latexJBibtexCO->clear();
843 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
844 latexJBibtexCO->addItem(qt_("Custom"), QString());
845 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
846 it != rc.jbibtex_alternatives.end(); ++it) {
847 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
848 latexJBibtexCO->addItem(command, command);
851 jbibtex_alternatives = rc.jbibtex_alternatives;
853 QString const jbib = toqstr(rc.jbibtex_command);
854 ind = jbib.indexOf(" ");
855 sel_command = jbib.left(ind);
856 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
858 pos = latexJBibtexCO->findData(sel_command);
860 latexJBibtexCO->setCurrentIndex(pos);
861 latexJBibtexED->setText(sel_options.trimmed());
862 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
864 latexJBibtexED->setText(toqstr(rc.bibtex_command));
865 latexJBibtexCO->setCurrentIndex(0);
866 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
869 latexIndexCO->clear();
871 latexIndexCO->addItem(qt_("Custom"), QString());
872 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
873 it != rc.index_alternatives.end(); ++it) {
874 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
875 latexIndexCO->addItem(command, command);
878 index_alternatives = rc.index_alternatives;
880 QString const idx = toqstr(rc.index_command);
881 ind = idx.indexOf(" ");
882 sel_command = idx.left(ind);
883 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
885 pos = latexIndexCO->findData(sel_command);
887 latexIndexCO->setCurrentIndex(pos);
888 latexIndexED->setText(sel_options.trimmed());
889 latexIndexOptionsLA->setText(qt_("Op&tions:"));
891 latexIndexED->setText(toqstr(rc.index_command));
892 latexIndexCO->setCurrentIndex(0);
893 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
896 latexChecktexED->setText(toqstr(rc.chktex_command));
897 latexJIndexED->setText(toqstr(rc.jindex_command));
898 latexNomenclED->setText(toqstr(rc.nomencl_command));
899 latexAutoresetCB->setChecked(rc.auto_reset_options);
900 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
901 #if defined(__CYGWIN__) || defined(_WIN32)
902 pathCB->setChecked(rc.windows_style_tex_paths);
907 /////////////////////////////////////////////////////////////////////
911 /////////////////////////////////////////////////////////////////////
913 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
914 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
918 #if QT_VERSION < 0x050e00
919 connect(screenRomanCO, SIGNAL(activated(QString)),
920 this, SLOT(selectRoman(QString)));
921 connect(screenSansCO, SIGNAL(activated(QString)),
922 this, SLOT(selectSans(QString)));
923 connect(screenTypewriterCO, SIGNAL(activated(QString)),
924 this, SLOT(selectTypewriter(QString)));
926 connect(screenRomanCO, SIGNAL(textActivated(QString)),
927 this, SLOT(selectRoman(QString)));
928 connect(screenSansCO, SIGNAL(textActivated(QString)),
929 this, SLOT(selectSans(QString)));
930 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
931 this, SLOT(selectTypewriter(QString)));
934 #if QT_VERSION >= 0x060000
935 const QStringList families(QFontDatabase::families());
937 QFontDatabase fontdb;
938 const QStringList families(fontdb.families());
940 for (auto const & family : families) {
941 screenRomanCO->addItem(family);
942 screenSansCO->addItem(family);
943 screenTypewriterCO->addItem(family);
945 #if QT_VERSION < 0x050e00
946 connect(screenRomanCO, SIGNAL(activated(QString)),
947 this, SIGNAL(changed()));
948 connect(screenSansCO, SIGNAL(activated(QString)),
949 this, SIGNAL(changed()));
950 connect(screenTypewriterCO, SIGNAL(activated(QString)),
951 this, SIGNAL(changed()));
953 connect(screenRomanCO, SIGNAL(textActivated(QString)),
954 this, SIGNAL(changed()));
955 connect(screenSansCO, SIGNAL(textActivated(QString)),
956 this, SIGNAL(changed()));
957 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
958 this, SIGNAL(changed()));
960 connect(screenZoomSB, SIGNAL(valueChanged(int)),
961 this, SIGNAL(changed()));
962 connect(screenTinyED, SIGNAL(textChanged(QString)),
963 this, SIGNAL(changed()));
964 connect(screenSmallestED, SIGNAL(textChanged(QString)),
965 this, SIGNAL(changed()));
966 connect(screenSmallerED, SIGNAL(textChanged(QString)),
967 this, SIGNAL(changed()));
968 connect(screenSmallED, SIGNAL(textChanged(QString)),
969 this, SIGNAL(changed()));
970 connect(screenNormalED, SIGNAL(textChanged(QString)),
971 this, SIGNAL(changed()));
972 connect(screenLargeED, SIGNAL(textChanged(QString)),
973 this, SIGNAL(changed()));
974 connect(screenLargerED, SIGNAL(textChanged(QString)),
975 this, SIGNAL(changed()));
976 connect(screenLargestED, SIGNAL(textChanged(QString)),
977 this, SIGNAL(changed()));
978 connect(screenHugeED, SIGNAL(textChanged(QString)),
979 this, SIGNAL(changed()));
980 connect(screenHugerED, SIGNAL(textChanged(QString)),
981 this, SIGNAL(changed()));
983 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
984 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
985 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
986 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
987 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
988 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
989 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
990 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
991 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
992 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
996 void PrefScreenFonts::applyRC(LyXRC & rc) const
998 LyXRC const oldrc = rc;
1000 parseFontName(screenRomanCO->currentText(),
1001 rc.roman_font_name, rc.roman_font_foundry);
1002 parseFontName(screenSansCO->currentText(),
1003 rc.sans_font_name, rc.sans_font_foundry);
1004 parseFontName(screenTypewriterCO->currentText(),
1005 rc.typewriter_font_name, rc.typewriter_font_foundry);
1007 rc.defaultZoom = screenZoomSB->value();
1008 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
1009 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
1010 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
1011 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
1012 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
1013 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
1014 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
1015 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
1016 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
1017 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
1021 void PrefScreenFonts::updateRC(LyXRC const & rc)
1023 setComboxFont(screenRomanCO, rc.roman_font_name,
1024 rc.roman_font_foundry);
1025 setComboxFont(screenSansCO, rc.sans_font_name,
1026 rc.sans_font_foundry);
1027 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1028 rc.typewriter_font_foundry);
1030 selectRoman(screenRomanCO->currentText());
1031 selectSans(screenSansCO->currentText());
1032 selectTypewriter(screenTypewriterCO->currentText());
1034 screenZoomSB->setValue(rc.defaultZoom);
1035 updateScreenFontSizes(rc);
1039 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1041 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1042 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1043 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1044 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1045 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1046 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1047 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1048 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1049 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1050 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1054 void PrefScreenFonts::selectRoman(const QString & name)
1056 screenRomanFE->set(QFont(name), name);
1060 void PrefScreenFonts::selectSans(const QString & name)
1062 screenSansFE->set(QFont(name), name);
1066 void PrefScreenFonts::selectTypewriter(const QString & name)
1068 screenTypewriterFE->set(QFont(name), name);
1072 /////////////////////////////////////////////////////////////////////
1076 /////////////////////////////////////////////////////////////////////
1079 PrefColors::PrefColors(GuiPreferences * form)
1080 : PrefModule(catLookAndFeel, N_("Colors"), form)
1084 // FIXME: all of this initialization should be put into the controller.
1085 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1086 // for some discussion of why that is not trivial.
1087 QPixmap icon(32, 32);
1088 for (int i = 0; i < Color_ignore; ++i) {
1089 ColorCode lc = static_cast<ColorCode>(i);
1090 if (lc == Color_none
1091 || lc == Color_black
1092 || lc == Color_white
1094 || lc == Color_brown
1096 || lc == Color_darkgray
1098 || lc == Color_green
1099 || lc == Color_lightgray
1101 || lc == Color_magenta
1102 || lc == Color_olive
1103 || lc == Color_orange
1105 || lc == Color_purple
1108 || lc == Color_violet
1109 || lc == Color_yellow
1110 || lc == Color_inherit
1111 || lc == Color_ignore)
1113 lcolors_.push_back(lc);
1115 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1116 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1117 vector<ColorCode>::const_iterator const end = lcolors_.end();
1118 for (; cit != end; ++cit) {
1119 (void) new QListWidgetItem(QIcon(icon),
1120 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1122 curcolors_.resize(lcolors_.size());
1123 newcolors_.resize(lcolors_.size());
1124 // End initialization
1126 connect(colorChangePB, SIGNAL(clicked()),
1127 this, SLOT(changeColor()));
1128 connect(colorResetPB, SIGNAL(clicked()),
1129 this, SLOT(resetColor()));
1130 connect(colorResetAllPB, SIGNAL(clicked()),
1131 this, SLOT(resetAllColor()));
1132 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1133 this, SLOT(changeLyxObjectsSelection()));
1134 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1135 this, SLOT(changeColor()));
1136 connect(syscolorsCB, SIGNAL(toggled(bool)),
1137 this, SIGNAL(changed()));
1138 connect(syscolorsCB, SIGNAL(toggled(bool)),
1139 this, SLOT(changeSysColor()));
1143 void PrefColors::applyRC(LyXRC & rc) const
1147 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1148 if (curcolors_[i] != newcolors_[i])
1149 form_->setColor(lcolors_[i], newcolors_[i]);
1150 rc.use_system_colors = syscolorsCB->isChecked();
1152 if (oldrc.use_system_colors != rc.use_system_colors)
1153 guiApp->colorCache().clear();
1157 void PrefColors::updateRC(LyXRC const & rc)
1159 for (size_type i = 0; i < lcolors_.size(); ++i) {
1160 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1161 QPixmap coloritem(32, 32);
1162 coloritem.fill(color);
1163 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1164 newcolors_[i] = curcolors_[i] = color.name();
1166 syscolorsCB->setChecked(rc.use_system_colors);
1167 changeLyxObjectsSelection();
1169 setDisabledResets();
1173 void PrefColors::changeColor()
1175 int const row = lyxObjectsLW->currentRow();
1181 QString const color = newcolors_[size_t(row)];
1182 QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1184 if (setColor(row, c, color)) {
1185 setDisabledResets();
1192 void PrefColors::resetColor()
1194 int const row = lyxObjectsLW->currentRow();
1200 QString const color = newcolors_[size_t(row)];
1201 QColor const c = getDefaultColorByRow(row);
1203 if (setColor(row, c, color)) {
1204 setDisabledResets();
1211 void PrefColors::resetAllColor()
1213 bool isChanged = false;
1215 colorResetAllPB->setDisabled(true);
1217 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1218 QString const color = newcolors_[size_t(irow)];
1219 QColor const c = getDefaultColorByRow(irow);
1221 if (setColor(irow, c, color))
1226 setDisabledResets();
1233 bool PrefColors::setColor(int const row, QColor const & new_color,
1234 QString const & old_color)
1236 if (new_color.isValid() && new_color.name() != old_color) {
1237 newcolors_[size_t(row)] = new_color.name();
1238 QPixmap coloritem(32, 32);
1239 coloritem.fill(new_color);
1240 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1247 void PrefColors::setDisabledResets()
1249 int const row = lyxObjectsLW->currentRow();
1250 // set disable reset buttons ...
1252 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1254 colorResetAllPB->setDisabled(true);
1256 // ... in between process qt events to give quicker visual feedback to the user ...
1257 guiApp->processEvents();
1259 // ... set disable Reset All button
1260 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1261 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1262 colorResetAllPB->setDisabled(false);
1263 // the break condition might hide performance issues
1264 // if a non-default color is at the top of the list
1271 bool PrefColors::isDefaultColor(int const row, QString const & color)
1273 return color == getDefaultColorByRow(row).name();
1277 QColor PrefColors::getDefaultColorByRow(int const row)
1279 ColorSet const defaultcolor;
1280 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1281 guiApp->colorCache().isDarkMode()).c_str();
1285 void PrefColors::changeSysColor()
1287 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1288 // skip colors that are taken from system palette
1289 bool const disable = syscolorsCB->isChecked()
1290 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1292 QListWidgetItem * const item = lyxObjectsLW->item(row);
1293 Qt::ItemFlags const flags = item->flags();
1296 item->setFlags(flags & ~Qt::ItemIsEnabled);
1298 item->setFlags(flags | Qt::ItemIsEnabled);
1303 void PrefColors::changeLyxObjectsSelection()
1305 int currentRow = lyxObjectsLW->currentRow();
1306 colorChangePB->setDisabled(currentRow < 0);
1309 colorResetPB->setDisabled(true);
1311 colorResetPB->setDisabled(
1312 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1316 /////////////////////////////////////////////////////////////////////
1320 /////////////////////////////////////////////////////////////////////
1322 PrefDisplay::PrefDisplay(GuiPreferences * form)
1323 : PrefModule(catLookAndFeel, N_("Display"), form)
1326 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1327 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1328 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1329 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1330 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1334 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1336 previewSizeSB->setEnabled(index != 0);
1340 void PrefDisplay::applyRC(LyXRC & rc) const
1342 switch (instantPreviewCO->currentIndex()) {
1344 rc.preview = LyXRC::PREVIEW_OFF;
1347 rc.preview = LyXRC::PREVIEW_NO_MATH;
1350 rc.preview = LyXRC::PREVIEW_ON;
1354 rc.display_graphics = displayGraphicsCB->isChecked();
1355 rc.preview_scale_factor = previewSizeSB->value();
1356 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1357 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1359 // FIXME!! The graphics cache no longer has a changeDisplay method.
1361 if (old_value != rc.display_graphics) {
1362 graphics::GCache & gc = graphics::GCache::get();
1369 void PrefDisplay::updateRC(LyXRC const & rc)
1371 switch (rc.preview) {
1372 case LyXRC::PREVIEW_OFF:
1373 instantPreviewCO->setCurrentIndex(0);
1375 case LyXRC::PREVIEW_NO_MATH :
1376 instantPreviewCO->setCurrentIndex(1);
1378 case LyXRC::PREVIEW_ON :
1379 instantPreviewCO->setCurrentIndex(2);
1383 displayGraphicsCB->setChecked(rc.display_graphics);
1384 previewSizeSB->setValue(rc.preview_scale_factor);
1385 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1386 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1387 previewSizeSB->setEnabled(
1389 && rc.preview != LyXRC::PREVIEW_OFF);
1393 /////////////////////////////////////////////////////////////////////
1397 /////////////////////////////////////////////////////////////////////
1399 PrefPaths::PrefPaths(GuiPreferences * form)
1400 : PrefModule(QString(), N_("Paths"), form)
1404 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1405 connect(workingDirED, SIGNAL(textChanged(QString)),
1406 this, SIGNAL(changed()));
1408 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1409 connect(templateDirED, SIGNAL(textChanged(QString)),
1410 this, SIGNAL(changed()));
1412 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1413 connect(exampleDirED, SIGNAL(textChanged(QString)),
1414 this, SIGNAL(changed()));
1416 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1417 connect(backupDirED, SIGNAL(textChanged(QString)),
1418 this, SIGNAL(changed()));
1420 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1421 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1422 this, SIGNAL(changed()));
1424 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1425 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1426 this, SIGNAL(changed()));
1428 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1429 connect(tempDirED, SIGNAL(textChanged(QString)),
1430 this, SIGNAL(changed()));
1432 #if defined(USE_HUNSPELL)
1433 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1434 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1435 this, SIGNAL(changed()));
1437 hunspellDirPB->setEnabled(false);
1438 hunspellDirED->setEnabled(false);
1441 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1442 this, SIGNAL(changed()));
1444 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1445 this, SIGNAL(changed()));
1447 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1448 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1452 void PrefPaths::applyRC(LyXRC & rc) const
1454 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1455 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1456 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1457 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1458 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1459 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1460 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1461 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1462 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1463 // FIXME: should be a checkbox only
1464 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1468 void PrefPaths::updateRC(LyXRC const & rc)
1470 workingDirED->setText(toqstr(external_path(rc.document_path)));
1471 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1472 templateDirED->setText(toqstr(external_path(rc.template_path)));
1473 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1474 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1475 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1476 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1477 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1478 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1479 // FIXME: should be a checkbox only
1480 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1484 void PrefPaths::selectExampledir()
1486 QString file = browseDir(internalPath(exampleDirED->text()),
1487 qt_("Select directory for example files"));
1488 if (!file.isEmpty())
1489 exampleDirED->setText(file);
1493 void PrefPaths::selectTemplatedir()
1495 QString file = browseDir(internalPath(templateDirED->text()),
1496 qt_("Select a document templates directory"));
1497 if (!file.isEmpty())
1498 templateDirED->setText(file);
1502 void PrefPaths::selectTempdir()
1504 QString file = browseDir(internalPath(tempDirED->text()),
1505 qt_("Select a temporary directory"));
1506 if (!file.isEmpty())
1507 tempDirED->setText(file);
1511 void PrefPaths::selectBackupdir()
1513 QString file = browseDir(internalPath(backupDirED->text()),
1514 qt_("Select a backups directory"));
1515 if (!file.isEmpty())
1516 backupDirED->setText(file);
1520 void PrefPaths::selectWorkingdir()
1522 QString file = browseDir(internalPath(workingDirED->text()),
1523 qt_("Select a document directory"));
1524 if (!file.isEmpty())
1525 workingDirED->setText(file);
1529 void PrefPaths::selectThesaurusdir()
1531 QString file = browseDir(internalPath(thesaurusDirED->text()),
1532 qt_("Set the path to the thesaurus dictionaries"));
1533 if (!file.isEmpty())
1534 thesaurusDirED->setText(file);
1538 void PrefPaths::selectHunspelldir()
1540 QString file = browseDir(internalPath(hunspellDirED->text()),
1541 qt_("Set the path to the Hunspell dictionaries"));
1542 if (!file.isEmpty())
1543 hunspellDirED->setText(file);
1547 void PrefPaths::selectLyxPipe()
1549 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1550 qt_("Give a filename for the LyX server pipe"));
1551 if (!file.isEmpty())
1552 lyxserverDirED->setText(file);
1556 /////////////////////////////////////////////////////////////////////
1560 /////////////////////////////////////////////////////////////////////
1562 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1563 : PrefModule(catLanguage, N_("Spellchecker"), form)
1567 // FIXME: this check should test the target platform (darwin)
1568 #if defined(USE_MACOSX_PACKAGING)
1569 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1570 #define CONNECT_APPLESPELL
1572 #undef CONNECT_APPLESPELL
1574 #if defined(USE_ASPELL)
1575 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1577 #if defined(USE_ENCHANT)
1578 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1580 #if defined(USE_HUNSPELL)
1581 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1584 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1585 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1586 this, SIGNAL(changed()));
1587 connect(altLanguageED, SIGNAL(textChanged(QString)),
1588 this, SIGNAL(changed()));
1589 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1590 this, SIGNAL(changed()));
1591 connect(compoundWordCB, SIGNAL(clicked()),
1592 this, SIGNAL(changed()));
1593 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1594 this, SIGNAL(changed()));
1595 connect(spellcheckNotesCB, SIGNAL(clicked()),
1596 this, SIGNAL(changed()));
1598 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1599 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1601 spellcheckerCB->setEnabled(false);
1602 altLanguageED->setEnabled(false);
1603 escapeCharactersED->setEnabled(false);
1604 compoundWordCB->setEnabled(false);
1605 spellcheckContinuouslyCB->setEnabled(false);
1606 spellcheckNotesCB->setEnabled(false);
1611 void PrefSpellchecker::applyRC(LyXRC & rc) const
1613 string const speller = fromqstr(spellcheckerCB->
1614 itemData(spellcheckerCB->currentIndex()).toString());
1615 if (!speller.empty())
1616 rc.spellchecker = speller;
1617 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1618 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1619 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1620 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1621 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1625 void PrefSpellchecker::updateRC(LyXRC const & rc)
1627 spellcheckerCB->setCurrentIndex(
1628 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1629 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1630 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1631 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1632 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1633 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1637 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1639 QString spellchecker = spellcheckerCB->itemData(index).toString();
1641 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1646 /////////////////////////////////////////////////////////////////////
1650 /////////////////////////////////////////////////////////////////////
1653 PrefConverters::PrefConverters(GuiPreferences * form)
1654 : PrefModule(catFiles, N_("Converters"), form)
1658 connect(converterNewPB, SIGNAL(clicked()),
1659 this, SLOT(updateConverter()));
1660 connect(converterRemovePB, SIGNAL(clicked()),
1661 this, SLOT(removeConverter()));
1662 connect(converterModifyPB, SIGNAL(clicked()),
1663 this, SLOT(updateConverter()));
1664 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1665 this, SLOT(switchConverter()));
1666 #if QT_VERSION < 0x050e00
1667 connect(converterFromCO, SIGNAL(activated(QString)),
1668 this, SLOT(changeConverter()));
1669 connect(converterToCO, SIGNAL(activated(QString)),
1670 this, SLOT(changeConverter()));
1672 connect(converterFromCO, SIGNAL(textActivated(QString)),
1673 this, SLOT(changeConverter()));
1674 connect(converterToCO, SIGNAL(textActivated(QString)),
1675 this, SLOT(changeConverter()));
1677 connect(converterED, SIGNAL(textEdited(QString)),
1678 this, SLOT(changeConverter()));
1679 connect(converterFlagED, SIGNAL(textEdited(QString)),
1680 this, SLOT(changeConverter()));
1681 connect(converterNewPB, SIGNAL(clicked()),
1682 this, SIGNAL(changed()));
1683 connect(converterRemovePB, SIGNAL(clicked()),
1684 this, SIGNAL(changed()));
1685 connect(converterModifyPB, SIGNAL(clicked()),
1686 this, SIGNAL(changed()));
1687 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1688 this, SIGNAL(changed()));
1689 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1690 this, SIGNAL(changed()));
1692 converterED->setValidator(new NoNewLineValidator(converterED));
1693 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1694 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1695 //converterDefGB->setFocusProxy(convertersLW);
1699 void PrefConverters::applyRC(LyXRC & rc) const
1701 rc.use_converter_cache = cacheCB->isChecked();
1702 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1703 rc.use_converter_needauth = needauthCB->isChecked();
1704 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1708 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1709 cb->blockSignals(true);
1710 cb->setChecked(checked);
1711 cb->blockSignals(false);
1715 void PrefConverters::updateRC(LyXRC const & rc)
1717 cacheCB->setChecked(rc.use_converter_cache);
1718 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1719 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1721 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1726 void PrefConverters::updateGui()
1728 QString const pattern("%1 -> %2");
1729 form_->formats().sort();
1730 form_->converters().update(form_->formats());
1731 // save current selection
1734 .arg(converterFromCO->currentText())
1735 .arg(converterToCO->currentText());
1737 converterFromCO->clear();
1738 converterToCO->clear();
1740 for (Format const & f : form_->formats()) {
1741 QString const name = toqstr(translateIfPossible(f.prettyname()));
1742 converterFromCO->addItem(name);
1743 converterToCO->addItem(name);
1746 // currentRowChanged(int) is also triggered when updating the listwidget
1747 // block signals to avoid unnecessary calls to switchConverter()
1748 convertersLW->blockSignals(true);
1749 convertersLW->clear();
1751 for (Converter const & c : form_->converters()) {
1752 QString const name =
1754 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1755 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1756 int type = form_->converters().getNumber(c.From()->name(),
1758 new QListWidgetItem(name, convertersLW, type);
1760 convertersLW->sortItems(Qt::AscendingOrder);
1761 convertersLW->blockSignals(false);
1763 // restore selection
1764 if (current != pattern.arg(QString()).arg(QString())) {
1765 QList<QListWidgetItem *> const item =
1766 convertersLW->findItems(current, Qt::MatchExactly);
1767 if (!item.isEmpty())
1768 convertersLW->setCurrentItem(item.at(0));
1771 // select first element if restoring failed
1772 if (convertersLW->currentRow() == -1)
1773 convertersLW->setCurrentRow(0);
1779 void PrefConverters::switchConverter()
1781 int const cnr = convertersLW->currentItem()->type();
1782 Converter const & c(form_->converters().get(cnr));
1783 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1784 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1785 converterED->setText(toqstr(c.command()));
1786 converterFlagED->setText(toqstr(c.flags()));
1792 void PrefConverters::changeConverter()
1798 void PrefConverters::updateButtons()
1800 if (form_->formats().empty())
1802 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1803 Format const & to = form_->formats().get(converterToCO->currentIndex());
1804 int const sel = form_->converters().getNumber(from.name(), to.name());
1805 bool const known = sel >= 0;
1806 bool const valid = !(converterED->text().isEmpty()
1807 || from.name() == to.name());
1812 if (convertersLW->count() > 0) {
1813 int const cnr = convertersLW->currentItem()->type();
1814 Converter const & c = form_->converters().get(cnr);
1815 old_command = c.command();
1816 old_flag = c.flags();
1819 string const new_command = fromqstr(converterED->text());
1820 string const new_flag = fromqstr(converterFlagED->text());
1822 bool modified = (old_command != new_command || old_flag != new_flag);
1824 converterModifyPB->setEnabled(valid && known && modified);
1825 converterNewPB->setEnabled(valid && !known);
1826 converterRemovePB->setEnabled(known);
1828 maxAgeLE->setEnabled(cacheCB->isChecked());
1829 maxAgeLA->setEnabled(cacheCB->isChecked());
1834 // specify unique from/to or it doesn't appear. This is really bad UI
1835 // this is why we can use the same function for both new and modify
1836 void PrefConverters::updateConverter()
1838 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1839 Format const & to = form_->formats().get(converterToCO->currentIndex());
1840 string const flags = fromqstr(converterFlagED->text());
1841 string const command = fromqstr(converterED->text());
1843 Converter const * old =
1844 form_->converters().getConverter(from.name(), to.name());
1845 form_->converters().add(from.name(), to.name(), command, flags);
1848 form_->converters().updateLast(form_->formats());
1852 // Remove all files created by this converter from the cache, since
1853 // the modified converter might create different files.
1854 ConverterCache::get().remove_all(from.name(), to.name());
1858 void PrefConverters::removeConverter()
1860 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1861 Format const & to = form_->formats().get(converterToCO->currentIndex());
1862 form_->converters().erase(from.name(), to.name());
1866 // Remove all files created by this converter from the cache, since
1867 // a possible new converter might create different files.
1868 ConverterCache::get().remove_all(from.name(), to.name());
1872 void PrefConverters::on_cacheCB_stateChanged(int state)
1874 maxAgeLE->setEnabled(state == Qt::Checked);
1875 maxAgeLA->setEnabled(state == Qt::Checked);
1880 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1882 needauthCB->setEnabled(!checked);
1886 void PrefConverters::on_needauthCB_toggled(bool checked)
1893 int ret = frontend::Alert::prompt(
1894 _("SECURITY WARNING!"), _("Unchecking this option has the effect that potentially harmful converters would be run without asking your permission first. This is UNSAFE and NOT recommended, unless you know what you are doing. Are you sure you would like to proceed ? The recommended and safe answer is NO!"),
1895 0, 0, _("&No"), _("&Yes"));
1899 setCheckboxBlockSignals(needauthCB, true);
1903 /////////////////////////////////////////////////////////////////////
1907 /////////////////////////////////////////////////////////////////////
1909 class FormatValidator : public QValidator
1912 FormatValidator(QWidget *, Formats const & f);
1913 void fixup(QString & input) const override;
1914 QValidator::State validate(QString & input, int & pos) const override;
1916 virtual QString toString(Format const & format) const = 0;
1918 Formats const & formats_;
1922 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1923 : QValidator(parent), formats_(f)
1928 void FormatValidator::fixup(QString & input) const
1930 Formats::const_iterator cit = formats_.begin();
1931 Formats::const_iterator end = formats_.end();
1932 for (; cit != end; ++cit) {
1933 QString const name = toString(*cit);
1934 if (distance(formats_.begin(), cit) == nr()) {
1942 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1944 Formats::const_iterator cit = formats_.begin();
1945 Formats::const_iterator end = formats_.end();
1946 bool unknown = true;
1947 for (; unknown && cit != end; ++cit) {
1948 QString const name = toString(*cit);
1949 if (distance(formats_.begin(), cit) != nr())
1950 unknown = name != input;
1953 if (unknown && !input.isEmpty())
1954 return QValidator::Acceptable;
1956 return QValidator::Intermediate;
1960 int FormatValidator::nr() const
1962 QComboBox * p = qobject_cast<QComboBox *>(parent());
1963 return p->itemData(p->currentIndex()).toInt();
1967 /////////////////////////////////////////////////////////////////////
1969 // FormatNameValidator
1971 /////////////////////////////////////////////////////////////////////
1973 class FormatNameValidator : public FormatValidator
1976 FormatNameValidator(QWidget * parent, Formats const & f)
1977 : FormatValidator(parent, f)
1980 QString toString(Format const & format) const override
1982 return toqstr(format.name());
1987 /////////////////////////////////////////////////////////////////////
1989 // FormatPrettynameValidator
1991 /////////////////////////////////////////////////////////////////////
1993 class FormatPrettynameValidator : public FormatValidator
1996 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1997 : FormatValidator(parent, f)
2000 QString toString(Format const & format) const override
2002 return toqstr(translateIfPossible(format.prettyname()));
2007 /////////////////////////////////////////////////////////////////////
2011 /////////////////////////////////////////////////////////////////////
2013 PrefFileformats::PrefFileformats(GuiPreferences * form)
2014 : PrefModule(catFiles, N_("File Formats"), form)
2018 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2019 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2020 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2021 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2022 editorED->setValidator(new NoNewLineValidator(editorED));
2023 viewerED->setValidator(new NoNewLineValidator(viewerED));
2024 copierED->setValidator(new NoNewLineValidator(copierED));
2026 connect(documentCB, SIGNAL(clicked()),
2027 this, SLOT(setFlags()));
2028 connect(vectorCB, SIGNAL(clicked()),
2029 this, SLOT(setFlags()));
2030 connect(exportMenuCB, SIGNAL(clicked()),
2031 this, SLOT(setFlags()));
2032 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2033 this, SLOT(updatePrettyname()));
2034 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2035 this, SIGNAL(changed()));
2036 #if QT_VERSION < 0x050e00
2037 connect(defaultFormatCB, SIGNAL(activated(QString)),
2038 this, SIGNAL(changed()));
2039 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2040 this, SIGNAL(changed()));
2041 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2042 this, SIGNAL(changed()));
2044 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2045 this, SIGNAL(changed()));
2046 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2047 this, SIGNAL(changed()));
2048 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2049 this, SIGNAL(changed()));
2051 connect(viewerCO, SIGNAL(activated(int)),
2052 this, SIGNAL(changed()));
2053 connect(editorCO, SIGNAL(activated(int)),
2054 this, SIGNAL(changed()));
2060 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2062 if (shortcut.empty())
2065 string l10n_format =
2066 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2067 return split(l10n_format, '|');
2073 void PrefFileformats::applyRC(LyXRC & rc) const
2075 QString const default_format = defaultFormatCB->itemData(
2076 defaultFormatCB->currentIndex()).toString();
2077 rc.default_view_format = fromqstr(default_format);
2078 QString const default_otf_format = defaultOTFFormatCB->itemData(
2079 defaultOTFFormatCB->currentIndex()).toString();
2080 rc.default_otf_view_format = fromqstr(default_otf_format);
2081 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2082 defaultPlatexFormatCB->currentIndex()).toString();
2083 rc.default_platex_view_format = fromqstr(default_platex_format);
2087 void PrefFileformats::updateRC(LyXRC const & rc)
2089 viewer_alternatives = rc.viewer_alternatives;
2090 editor_alternatives = rc.editor_alternatives;
2091 bool const init = defaultFormatCB->currentText().isEmpty();
2095 defaultFormatCB->findData(toqstr(rc.default_view_format));
2096 defaultFormatCB->setCurrentIndex(pos);
2097 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2098 defaultOTFFormatCB->setCurrentIndex(pos);
2099 defaultOTFFormatCB->setCurrentIndex(pos);
2100 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2101 defaultPlatexFormatCB->setCurrentIndex(pos);
2102 defaultPlatexFormatCB->setCurrentIndex(pos);
2107 void PrefFileformats::updateView()
2109 QString const current = formatsCB->currentText();
2110 QString const current_def = defaultFormatCB->currentText();
2111 QString const current_def_otf = defaultOTFFormatCB->currentText();
2112 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2114 // update comboboxes with formats
2115 formatsCB->blockSignals(true);
2116 defaultFormatCB->blockSignals(true);
2117 defaultOTFFormatCB->blockSignals(true);
2118 defaultPlatexFormatCB->blockSignals(true);
2120 defaultFormatCB->clear();
2121 defaultOTFFormatCB->clear();
2122 defaultPlatexFormatCB->clear();
2123 form_->formats().sort();
2124 for (Format const & f : form_->formats()) {
2125 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2126 formatsCB->addItem(prettyname,
2127 QVariant(form_->formats().getNumber(f.name())));
2128 if (f.viewer().empty())
2130 if (form_->converters().isReachable("xhtml", f.name())
2131 || form_->converters().isReachable("dviluatex", f.name())
2132 || form_->converters().isReachable("luatex", f.name())
2133 || form_->converters().isReachable("xetex", f.name())) {
2134 defaultFormatCB->addItem(prettyname,
2135 QVariant(toqstr(f.name())));
2136 defaultOTFFormatCB->addItem(prettyname,
2137 QVariant(toqstr(f.name())));
2139 if (form_->converters().isReachable("latex", f.name())
2140 || form_->converters().isReachable("pdflatex", f.name()))
2141 defaultFormatCB->addItem(prettyname,
2142 QVariant(toqstr(f.name())));
2143 if (form_->converters().isReachable("platex", f.name()))
2144 defaultPlatexFormatCB->addItem(prettyname,
2145 QVariant(toqstr(f.name())));
2149 // restore selections
2150 int item = formatsCB->findText(current, Qt::MatchExactly);
2151 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2152 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2153 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2154 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2155 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2156 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2157 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2158 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2159 formatsCB->blockSignals(false);
2160 defaultFormatCB->blockSignals(false);
2161 defaultOTFFormatCB->blockSignals(false);
2162 defaultPlatexFormatCB->blockSignals(false);
2166 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2168 if (form_->formats().empty())
2170 int const nr = formatsCB->itemData(i).toInt();
2171 Format const f = form_->formats().get(nr);
2173 formatED->setText(toqstr(f.name()));
2174 copierED->setText(toqstr(form_->movers().command(f.name())));
2175 extensionsED->setText(toqstr(f.extensions()));
2176 mimeED->setText(toqstr(f.mime()));
2177 shortcutED->setText(
2178 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2179 documentCB->setChecked((f.documentFormat()));
2180 vectorCB->setChecked((f.vectorFormat()));
2181 exportMenuCB->setChecked((f.inExportMenu()));
2182 exportMenuCB->setEnabled((f.documentFormat()));
2188 void PrefFileformats::setFlags()
2190 int flags = Format::none;
2191 if (documentCB->isChecked())
2192 flags |= Format::document;
2193 if (vectorCB->isChecked())
2194 flags |= Format::vector;
2195 if (exportMenuCB->isChecked())
2196 flags |= Format::export_menu;
2197 currentFormat().setFlags(flags);
2198 exportMenuCB->setEnabled(documentCB->isChecked());
2203 void PrefFileformats::on_copierED_textEdited(const QString & s)
2205 string const fmt = fromqstr(formatED->text());
2206 form_->movers().set(fmt, fromqstr(s));
2211 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2213 currentFormat().setExtensions(fromqstr(s));
2218 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2220 currentFormat().setViewer(fromqstr(s));
2225 void PrefFileformats::on_editorED_textEdited(const QString & s)
2227 currentFormat().setEditor(fromqstr(s));
2232 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2234 currentFormat().setMime(fromqstr(s));
2239 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2241 string const new_shortcut = fromqstr(s);
2242 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2243 currentFormat().shortcut()))
2245 currentFormat().setShortcut(new_shortcut);
2250 void PrefFileformats::on_formatED_editingFinished()
2252 string const newname = fromqstr(formatED->displayText());
2253 string const oldname = currentFormat().name();
2254 if (newname == oldname)
2256 if (form_->converters().formatIsUsed(oldname)) {
2257 Alert::error(_("Format in use"),
2258 _("You cannot change a format's short name "
2259 "if the format is used by a converter. "
2260 "Please remove the converter first."));
2265 currentFormat().setName(newname);
2270 void PrefFileformats::on_formatED_textChanged(const QString &)
2272 QString t = formatED->text();
2274 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2275 setValid(formatLA, valid);
2279 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2281 QString t = formatsCB->currentText();
2283 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2284 setValid(formatsLA, valid);
2288 void PrefFileformats::updatePrettyname()
2290 QString const newname = formatsCB->currentText();
2291 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2294 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2302 void updateComboBox(LyXRC::Alternatives const & alts,
2303 string const & fmt, QComboBox * combo)
2305 LyXRC::Alternatives::const_iterator it =
2307 if (it != alts.end()) {
2308 LyXRC::CommandSet const & cmds = it->second;
2309 LyXRC::CommandSet::const_iterator sit =
2311 LyXRC::CommandSet::const_iterator const sen =
2313 for (; sit != sen; ++sit) {
2314 QString const qcmd = toqstr(*sit);
2315 combo->addItem(qcmd, qcmd);
2322 void PrefFileformats::updateViewers()
2324 Format const f = currentFormat();
2325 viewerCO->blockSignals(true);
2327 viewerCO->addItem(qt_("None"), QString());
2328 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2329 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2330 viewerCO->blockSignals(false);
2332 int pos = viewerCO->findData(toqstr(f.viewer()));
2335 viewerED->setEnabled(false);
2336 viewerCO->setCurrentIndex(pos);
2338 viewerED->setEnabled(true);
2339 viewerED->setText(toqstr(f.viewer()));
2340 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2345 void PrefFileformats::updateEditors()
2347 Format const f = currentFormat();
2348 editorCO->blockSignals(true);
2350 editorCO->addItem(qt_("None"), QString());
2351 updateComboBox(editor_alternatives, f.name(), editorCO);
2352 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2353 editorCO->blockSignals(false);
2355 int pos = editorCO->findData(toqstr(f.editor()));
2358 editorED->setEnabled(false);
2359 editorCO->setCurrentIndex(pos);
2361 editorED->setEnabled(true);
2362 editorED->setText(toqstr(f.editor()));
2363 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2368 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2370 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2371 viewerED->setEnabled(custom);
2373 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2377 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2379 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2380 editorED->setEnabled(custom);
2382 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2386 Format & PrefFileformats::currentFormat()
2388 int const i = formatsCB->currentIndex();
2389 int const nr = formatsCB->itemData(i).toInt();
2390 return form_->formats().get(nr);
2394 void PrefFileformats::on_formatNewPB_clicked()
2396 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2398 formatsCB->setCurrentIndex(0);
2399 formatsCB->setFocus(Qt::OtherFocusReason);
2403 void PrefFileformats::on_formatRemovePB_clicked()
2405 int const i = formatsCB->currentIndex();
2406 int const nr = formatsCB->itemData(i).toInt();
2407 string const current_text = form_->formats().get(nr).name();
2408 if (form_->converters().formatIsUsed(current_text)) {
2409 Alert::error(_("Format in use"),
2410 _("Cannot remove a Format used by a Converter. "
2411 "Remove the converter first."));
2415 form_->formats().erase(current_text);
2418 on_formatsCB_editTextChanged(formatsCB->currentText());
2423 /////////////////////////////////////////////////////////////////////
2427 /////////////////////////////////////////////////////////////////////
2429 PrefLanguage::PrefLanguage(GuiPreferences * form)
2430 : PrefModule(catLanguage, N_("Language"), form)
2434 connect(visualCursorRB, SIGNAL(clicked()),
2435 this, SIGNAL(changed()));
2436 connect(logicalCursorRB, SIGNAL(clicked()),
2437 this, SIGNAL(changed()));
2438 connect(markForeignCB, SIGNAL(clicked()),
2439 this, SIGNAL(changed()));
2440 connect(respectOSkbdCB, SIGNAL(clicked()),
2441 this, SIGNAL(changed()));
2442 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2443 this, SIGNAL(changed()));
2444 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2445 this, SIGNAL(changed()));
2446 connect(languagePackageCO, SIGNAL(activated(int)),
2447 this, SIGNAL(changed()));
2448 connect(languagePackageED, SIGNAL(textChanged(QString)),
2449 this, SIGNAL(changed()));
2450 connect(globalCB, SIGNAL(clicked()),
2451 this, SIGNAL(changed()));
2452 connect(startCommandED, SIGNAL(textChanged(QString)),
2453 this, SIGNAL(changed()));
2454 connect(endCommandED, SIGNAL(textChanged(QString)),
2455 this, SIGNAL(changed()));
2456 connect(uiLanguageCO, SIGNAL(activated(int)),
2457 this, SIGNAL(changed()));
2458 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2459 this, SIGNAL(changed()));
2460 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2461 this, SIGNAL(changed()));
2462 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2463 this, SIGNAL(changed()));
2465 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2466 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2467 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2469 #if QT_VERSION < 0x060000
2470 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2472 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2474 defaultDecimalSepED->setMaxLength(1);
2476 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2477 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2479 QAbstractItemModel * language_model = guiApp->languageModel();
2480 language_model->sort(0);
2481 uiLanguageCO->blockSignals(true);
2482 uiLanguageCO->clear();
2483 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2484 for (int i = 0; i != language_model->rowCount(); ++i) {
2485 QModelIndex index = language_model->index(i, 0);
2486 // Filter the list based on the available translation and add
2487 // each language code only once
2488 string const name = fromqstr(index.data(Qt::UserRole).toString());
2489 Language const * lang = languages.getLanguage(name);
2492 // never remove the currently selected language
2493 if (name != form->rc().gui_language
2494 && name != lyxrc.gui_language
2495 && (!Messages::available(lang->code())
2496 || !lang->hasGuiSupport()))
2498 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2499 index.data(Qt::UserRole).toString());
2501 uiLanguageCO->blockSignals(false);
2503 // FIXME: restore this when it works (see discussion in #6450).
2504 respectOSkbdCB->hide();
2508 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2510 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2511 qt_("The change of user interface language will be fully "
2512 "effective only after a restart."));
2516 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2519 languagePackageED->setText(save_langpack_);
2520 else if (!languagePackageED->text().isEmpty()) {
2521 save_langpack_ = languagePackageED->text();
2522 languagePackageED->clear();
2524 languagePackageED->setEnabled(i == 2);
2528 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2530 defaultDecimalSepED->setEnabled(i == 1);
2534 void PrefLanguage::applyRC(LyXRC & rc) const
2536 rc.visual_cursor = visualCursorRB->isChecked();
2537 rc.mark_foreign_language = markForeignCB->isChecked();
2538 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2539 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2540 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2541 int const p = languagePackageCO->currentIndex();
2543 rc.language_package_selection = LyXRC::LP_AUTO;
2545 rc.language_package_selection = LyXRC::LP_BABEL;
2547 rc.language_package_selection = LyXRC::LP_CUSTOM;
2549 rc.language_package_selection = LyXRC::LP_NONE;
2550 rc.language_custom_package = fromqstr(languagePackageED->text());
2551 rc.language_global_options = globalCB->isChecked();
2552 rc.language_command_begin = fromqstr(startCommandED->text());
2553 rc.language_command_end = fromqstr(endCommandED->text());
2554 rc.gui_language = fromqstr(
2555 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2556 if (defaultDecimalSepCO->currentIndex() == 0)
2557 rc.default_decimal_sep = "locale";
2559 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2560 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2564 void PrefLanguage::updateRC(LyXRC const & rc)
2566 if (rc.visual_cursor)
2567 visualCursorRB->setChecked(true);
2569 logicalCursorRB->setChecked(true);
2570 markForeignCB->setChecked(rc.mark_foreign_language);
2571 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2572 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2573 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2574 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2575 if (languagePackageCO->currentIndex() == 2) {
2576 languagePackageED->setText(toqstr(rc.language_custom_package));
2577 languagePackageED->setEnabled(true);
2579 languagePackageED->clear();
2580 save_langpack_ = toqstr(rc.language_custom_package);
2581 languagePackageED->setEnabled(false);
2583 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2584 globalCB->setChecked(rc.language_global_options);
2585 startCommandED->setText(toqstr(rc.language_command_begin));
2586 endCommandED->setText(toqstr(rc.language_command_end));
2587 if (rc.default_decimal_sep == "locale") {
2588 defaultDecimalSepCO->setCurrentIndex(0);
2589 defaultDecimalSepED->clear();
2591 defaultDecimalSepCO->setCurrentIndex(1);
2592 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2594 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2595 defaultLengthUnitCO->setCurrentIndex(pos);
2597 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2598 uiLanguageCO->blockSignals(true);
2599 uiLanguageCO->setCurrentIndex(pos);
2600 uiLanguageCO->blockSignals(false);
2604 /////////////////////////////////////////////////////////////////////
2606 // PrefUserInterface
2608 /////////////////////////////////////////////////////////////////////
2610 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2611 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2615 connect(uiFilePB, SIGNAL(clicked()),
2616 this, SLOT(selectUi()));
2617 connect(uiFileED, SIGNAL(textChanged(QString)),
2618 this, SIGNAL(changed()));
2619 connect(iconSetCO, SIGNAL(activated(int)),
2620 this, SIGNAL(changed()));
2621 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2622 this, SIGNAL(changed()));
2623 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2624 this, SIGNAL(changed()));
2625 connect(tooltipCB, SIGNAL(toggled(bool)),
2626 this, SIGNAL(changed()));
2627 lastfilesSB->setMaximum(maxlastfiles);
2629 iconSetCO->addItem(qt_("Default"), QString());
2630 iconSetCO->addItem(qt_("Classic"), "classic");
2631 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2633 #if QT_VERSION >= 0x040600
2634 if (guiApp->platformName() != "qt4x11"
2635 && guiApp->platformName() != "xcb"
2636 && !guiApp->platformName().contains("wayland"))
2638 useSystemThemeIconsCB->hide();
2642 void PrefUserInterface::applyRC(LyXRC & rc) const
2644 rc.icon_set = fromqstr(iconSetCO->itemData(
2645 iconSetCO->currentIndex()).toString());
2647 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2648 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2649 rc.num_lastfiles = lastfilesSB->value();
2650 rc.use_tooltip = tooltipCB->isChecked();
2654 void PrefUserInterface::updateRC(LyXRC const & rc)
2656 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2659 iconSetCO->setCurrentIndex(iconset);
2660 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2661 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2662 lastfilesSB->setValue(rc.num_lastfiles);
2663 tooltipCB->setChecked(rc.use_tooltip);
2667 void PrefUserInterface::selectUi()
2669 QString file = form_->browseUI(internalPath(uiFileED->text()));
2670 if (!file.isEmpty())
2671 uiFileED->setText(file);
2675 /////////////////////////////////////////////////////////////////////
2677 // PrefDocumentHandling
2679 /////////////////////////////////////////////////////////////////////
2681 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2682 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2686 connect(autoSaveCB, SIGNAL(toggled(bool)),
2687 autoSaveSB, SLOT(setEnabled(bool)));
2688 connect(autoSaveCB, SIGNAL(toggled(bool)),
2689 TextLabel1, SLOT(setEnabled(bool)));
2690 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2691 this, SIGNAL(changed()));
2692 connect(singleInstanceCB, SIGNAL(clicked()),
2693 this, SIGNAL(changed()));
2694 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2695 this, SIGNAL(changed()));
2696 connect(closeLastViewCO, SIGNAL(activated(int)),
2697 this, SIGNAL(changed()));
2698 connect(restoreCursorCB, SIGNAL(clicked()),
2699 this, SIGNAL(changed()));
2700 connect(loadSessionCB, SIGNAL(clicked()),
2701 this, SIGNAL(changed()));
2702 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2703 this, SIGNAL(changed()));
2704 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2705 this, SIGNAL(changed()));
2706 connect(autoSaveCB, SIGNAL(clicked()),
2707 this, SIGNAL(changed()));
2708 connect(backupCB, SIGNAL(clicked()),
2709 this, SIGNAL(changed()));
2710 connect(saveCompressedCB, SIGNAL(clicked()),
2711 this, SIGNAL(changed()));
2712 connect(saveOriginCB, SIGNAL(clicked()),
2713 this, SIGNAL(changed()));
2717 void PrefDocHandling::applyRC(LyXRC & rc) const
2719 rc.use_lastfilepos = restoreCursorCB->isChecked();
2720 rc.load_session = loadSessionCB->isChecked();
2721 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2722 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2723 rc.make_backup = backupCB->isChecked();
2724 rc.save_compressed = saveCompressedCB->isChecked();
2725 rc.save_origin = saveOriginCB->isChecked();
2726 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2727 rc.single_instance = singleInstanceCB->isChecked();
2728 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2730 switch (closeLastViewCO->currentIndex()) {
2732 rc.close_buffer_with_last_view = "yes";
2735 rc.close_buffer_with_last_view = "no";
2738 rc.close_buffer_with_last_view = "ask";
2746 void PrefDocHandling::updateRC(LyXRC const & rc)
2748 restoreCursorCB->setChecked(rc.use_lastfilepos);
2749 loadSessionCB->setChecked(rc.load_session);
2750 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2751 // convert to minutes
2752 bool autosave = rc.autosave > 0;
2753 int mins = rc.autosave / 60;
2756 autoSaveSB->setValue(mins);
2757 autoSaveCB->setChecked(autosave);
2758 autoSaveSB->setEnabled(autosave);
2759 backupCB->setChecked(rc.make_backup);
2760 saveCompressedCB->setChecked(rc.save_compressed);
2761 saveOriginCB->setChecked(rc.save_origin);
2762 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2763 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2764 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2765 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2766 if (rc.close_buffer_with_last_view == "yes")
2767 closeLastViewCO->setCurrentIndex(0);
2768 else if (rc.close_buffer_with_last_view == "no")
2769 closeLastViewCO->setCurrentIndex(1);
2770 else if (rc.close_buffer_with_last_view == "ask")
2771 closeLastViewCO->setCurrentIndex(2);
2775 void PrefDocHandling::on_clearSessionPB_clicked()
2777 guiApp->clearSession();
2782 /////////////////////////////////////////////////////////////////////
2786 /////////////////////////////////////////////////////////////////////
2788 PrefEdit::PrefEdit(GuiPreferences * form)
2789 : PrefModule(catEditing, N_("Control"), form)
2793 connect(cursorFollowsCB, SIGNAL(clicked()),
2794 this, SIGNAL(changed()));
2795 connect(scrollBelowCB, SIGNAL(clicked()),
2796 this, SIGNAL(changed()));
2797 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2798 this, SIGNAL(changed()));
2799 connect(copyCTMarkupCB, SIGNAL(clicked()),
2800 this, SIGNAL(changed()));
2801 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2802 this, SIGNAL(changed()));
2803 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2804 this, SIGNAL(changed()));
2805 connect(macroEditStyleCO, SIGNAL(activated(int)),
2806 this, SIGNAL(changed()));
2807 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2808 this, SIGNAL(changed()));
2809 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2810 this, SIGNAL(changed()));
2811 connect(fullscreenWidthSB, SIGNAL(valueChanged(int)),
2812 this, SIGNAL(changed()));
2813 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2814 this, SIGNAL(changed()));
2815 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2816 this, SIGNAL(changed()));
2817 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2818 this, SIGNAL(changed()));
2819 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2820 this, SIGNAL(changed()));
2821 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2822 this, SIGNAL(changed()));
2826 void PrefEdit::on_fullscreenLimitCB_toggled(bool const state)
2828 fullscreenWidthSB->setEnabled(state);
2829 fullscreenWidthLA->setEnabled(state);
2834 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2836 citationSearchLE->setEnabled(state);
2837 citationSearchLA->setEnabled(state);
2842 void PrefEdit::applyRC(LyXRC & rc) const
2844 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2845 rc.scroll_below_document = scrollBelowCB->isChecked();
2846 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2847 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2848 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2849 rc.group_layouts = groupEnvironmentsCB->isChecked();
2850 switch (macroEditStyleCO->currentIndex()) {
2851 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2852 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2853 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2855 rc.cursor_width = cursorWidthSB->value();
2856 rc.citation_search = citationSearchCB->isChecked();
2857 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2858 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2859 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2860 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2861 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2862 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2863 rc.full_screen_width = fullscreenWidthSB->value();
2864 rc.full_screen_limit = fullscreenLimitCB->isChecked();
2868 void PrefEdit::updateRC(LyXRC const & rc)
2870 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2871 scrollBelowCB->setChecked(rc.scroll_below_document);
2872 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2873 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2874 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2875 groupEnvironmentsCB->setChecked(rc.group_layouts);
2876 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2877 cursorWidthSB->setValue(rc.cursor_width);
2878 citationSearchCB->setChecked(rc.citation_search);
2879 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2880 citationSearchLE->setEnabled(rc.citation_search);
2881 citationSearchLA->setEnabled(rc.citation_search);
2882 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2883 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2884 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2885 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2886 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2887 fullscreenWidthSB->setValue(rc.full_screen_width);
2888 fullscreenLimitCB->setChecked(rc.full_screen_limit);
2889 fullscreenWidthSB->setEnabled(rc.full_screen_limit);
2890 fullscreenWidthLA->setEnabled(rc.full_screen_limit);
2894 /////////////////////////////////////////////////////////////////////
2898 /////////////////////////////////////////////////////////////////////
2901 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2903 Ui::shortcutUi::setupUi(this);
2904 QDialog::setModal(true);
2905 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2909 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2910 : PrefModule(catEditing, N_("Shortcuts"), form),
2911 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2912 systemItem_(nullptr)
2916 shortcutsTW->setColumnCount(2);
2917 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2918 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2919 shortcutsTW->setSortingEnabled(true);
2920 // Multi-selection can be annoying.
2921 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2923 connect(bindFilePB, SIGNAL(clicked()),
2924 this, SLOT(selectBind()));
2925 connect(bindFileED, SIGNAL(textChanged(QString)),
2926 this, SIGNAL(changed()));
2928 shortcut_ = new GuiShortcutDialog(this);
2929 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2930 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2931 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2933 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2934 this, SIGNAL(changed()));
2935 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2936 shortcut_, SLOT(reject()));
2937 connect(shortcut_->clearPB, SIGNAL(clicked()),
2938 this, SLOT(shortcutClearPressed()));
2939 connect(shortcut_->removePB, SIGNAL(clicked()),
2940 this, SLOT(shortcutRemovePressed()));
2941 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2942 this, SLOT(shortcutOkPressed()));
2943 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2944 this, SLOT(shortcutCancelPressed()));
2948 void PrefShortcuts::applyRC(LyXRC & rc) const
2950 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2951 // write user_bind and user_unbind to .lyx/bind/user.bind
2952 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2953 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2954 lyxerr << "LyX could not create the user bind directory '"
2955 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2958 if (!bind_dir.isDirWritable()) {
2959 lyxerr << "LyX could not write to the user bind directory '"
2960 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2963 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2964 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2965 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2966 // immediately apply the keybindings. Why this is not done before?
2967 // The good thing is that the menus are updated automatically.
2968 theTopLevelKeymap().clear();
2969 theTopLevelKeymap().read("site");
2970 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2971 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2975 void PrefShortcuts::updateRC(LyXRC const & rc)
2977 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2979 system_bind_.clear();
2981 user_unbind_.clear();
2982 system_bind_.read("site");
2983 system_bind_.read(rc.bind_file);
2984 // \unbind in user.bind is added to user_unbind_
2985 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2986 updateShortcutsTW();
2990 void PrefShortcuts::updateShortcutsTW()
2992 shortcutsTW->clear();
2994 editItem_ = new QTreeWidgetItem(shortcutsTW);
2995 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2996 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
2998 mathItem_ = new QTreeWidgetItem(shortcutsTW);
2999 mathItem_->setText(0, qt_("Mathematical Symbols"));
3000 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3002 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3003 bufferItem_->setText(0, qt_("Document and Window"));
3004 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3006 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3007 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3008 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3010 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3011 systemItem_->setText(0, qt_("System and Miscellaneous"));
3012 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3014 // listBindings(unbound=true) lists all bound and unbound lfuns
3015 // Items in this list is tagged by its source.
3016 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3018 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3020 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3021 KeyMap::UserUnbind);
3022 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3023 user_bindinglist.end());
3024 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3025 user_unbindinglist.end());
3027 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3028 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3029 for (; it != it_end; ++it)
3030 insertShortcutItem(it->request, it->sequence, it->tag);
3032 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3033 on_shortcutsTW_itemSelectionChanged();
3034 on_searchLE_textEdited();
3035 shortcutsTW->resizeColumnToContents(0);
3040 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3042 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3047 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3049 // Hide rebound system settings that are empty
3050 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3054 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3056 item->setData(0, Qt::UserRole, QVariant(tag));
3060 case KeyMap::System:
3062 case KeyMap::UserBind:
3065 case KeyMap::UserUnbind:
3066 font.setStrikeOut(true);
3068 // this item is not displayed now.
3069 case KeyMap::UserExtraUnbind:
3070 font.setStrikeOut(true);
3073 item->setHidden(isAlwaysHidden(*item));
3074 item->setFont(1, font);
3078 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3079 KeySequence const & seq, KeyMap::ItemType tag)
3081 FuncCode const action = lfun.action();
3082 string const action_name = lyxaction.getActionName(action);
3083 QString const lfun_name = toqstr(from_utf8(action_name)
3084 + ' ' + lfun.argument());
3085 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3087 QTreeWidgetItem * newItem = nullptr;
3088 // for unbind items, try to find an existing item in the system bind list
3089 if (tag == KeyMap::UserUnbind) {
3090 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3091 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3092 for (auto const & item : items) {
3093 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3098 // if not found, this unbind item is KeyMap::UserExtraUnbind
3099 // Such an item is not displayed to avoid confusion (what is
3100 // unmatched removed?).
3106 switch(lyxaction.getActionType(action)) {
3107 case LyXAction::Hidden:
3109 case LyXAction::Edit:
3110 newItem = new QTreeWidgetItem(editItem_);
3112 case LyXAction::Math:
3113 newItem = new QTreeWidgetItem(mathItem_);
3115 case LyXAction::Buffer:
3116 newItem = new QTreeWidgetItem(bufferItem_);
3118 case LyXAction::Layout:
3119 newItem = new QTreeWidgetItem(layoutItem_);
3121 case LyXAction::System:
3122 newItem = new QTreeWidgetItem(systemItem_);
3125 // this should not happen
3126 newItem = new QTreeWidgetItem(shortcutsTW);
3128 newItem->setText(0, lfun_name);
3129 newItem->setText(1, shortcut);
3132 // record BindFile representation to recover KeySequence when needed.
3133 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3134 setItemType(newItem, tag);
3139 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3141 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3142 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3143 modifyPB->setEnabled(!items.isEmpty());
3144 if (items.isEmpty())
3147 if (itemType(*items[0]) == KeyMap::UserUnbind)
3148 removePB->setText(qt_("Res&tore"));
3150 removePB->setText(qt_("Remo&ve"));
3154 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3160 void PrefShortcuts::modifyShortcut()
3162 QTreeWidgetItem * item = shortcutsTW->currentItem();
3163 if (item->flags() & Qt::ItemIsSelectable) {
3164 shortcut_->lfunLE->setText(item->text(0));
3165 save_lfun_ = item->text(0).trimmed();
3166 shortcut_->shortcutWG->setText(item->text(1));
3168 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3169 shortcut_->shortcutWG->setKeySequence(seq);
3170 shortcut_->shortcutWG->setFocus();
3176 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3178 // list of items that match lfun
3179 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3180 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3181 for (auto const & item : items) {
3182 if (isAlwaysHidden(*item)) {
3183 setItemType(item, KeyMap::System);
3185 shortcutsTW->setCurrentItem(item);
3192 void PrefShortcuts::removeShortcut()
3194 // it seems that only one item can be selected, but I am
3195 // removing all selected items anyway.
3196 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3197 for (auto & item : items) {
3198 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3199 string lfun = fromqstr(item->text(0));
3200 FuncRequest const func = lyxaction.lookupFunc(lfun);
3202 switch (itemType(*item)) {
3203 case KeyMap::System: {
3204 // for system bind, we do not touch the item
3205 // but add an user unbind item
3206 user_unbind_.bind(shortcut, func);
3207 setItemType(item, KeyMap::UserUnbind);
3208 removePB->setText(qt_("Res&tore"));
3211 case KeyMap::UserBind: {
3212 // for user_bind, we remove this bind
3213 QTreeWidgetItem * parent = item->parent();
3214 int itemIdx = parent->indexOfChild(item);
3215 parent->takeChild(itemIdx);
3217 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3219 shortcutsTW->scrollToItem(parent);
3220 user_bind_.unbind(shortcut, func);
3221 // If this user binding hid an empty system binding, unhide the
3222 // latter and select it.
3223 unhideEmpty(item->text(0), true);
3226 case KeyMap::UserUnbind: {
3227 // for user_unbind, we remove the unbind, and the item
3228 // become KeyMap::System again.
3230 seq.parse(shortcut);
3231 // Ask the user to replace current binding
3232 if (!validateNewShortcut(func, seq, QString()))
3234 user_unbind_.unbind(shortcut, func);
3235 setItemType(item, KeyMap::System);
3236 removePB->setText(qt_("Remo&ve"));
3239 case KeyMap::UserExtraUnbind: {
3240 // for user unbind that is not in system bind file,
3241 // remove this unbind file
3242 QTreeWidgetItem * parent = item->parent();
3243 parent->takeChild(parent->indexOfChild(item));
3244 user_unbind_.unbind(shortcut, func);
3251 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3253 for (auto item : items) {
3254 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3255 string lfun = fromqstr(item->text(0));
3256 FuncRequest const func = lyxaction.lookupFunc(lfun);
3258 switch (itemType(*item)) {
3259 case KeyMap::System:
3260 // for system bind, we do not touch the item
3261 // but add an user unbind item
3262 user_unbind_.bind(shortcut, func);
3263 setItemType(item, KeyMap::UserUnbind);
3266 case KeyMap::UserBind: {
3267 // for user_bind, we remove this bind
3268 QTreeWidgetItem * parent = item->parent();
3269 int itemIdx = parent->indexOfChild(item);
3270 parent->takeChild(itemIdx);
3271 user_bind_.unbind(shortcut, func);
3272 unhideEmpty(item->text(0), false);
3282 void PrefShortcuts::selectBind()
3284 QString file = form_->browsebind(internalPath(bindFileED->text()));
3285 if (!file.isEmpty()) {
3286 bindFileED->setText(file);
3287 system_bind_ = KeyMap();
3288 system_bind_.read(fromqstr(file));
3289 updateShortcutsTW();
3294 void PrefShortcuts::on_modifyPB_pressed()
3300 void PrefShortcuts::on_newPB_pressed()
3302 shortcut_->lfunLE->clear();
3303 shortcut_->shortcutWG->reset();
3304 save_lfun_ = QString();
3309 void PrefShortcuts::on_removePB_pressed()
3316 void PrefShortcuts::on_searchLE_textEdited()
3318 if (searchLE->text().isEmpty()) {
3319 // show all hidden items
3320 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3322 (*it)->setHidden(isAlwaysHidden(**it));
3323 // close all categories
3324 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3325 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3328 // search both columns
3329 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3330 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3331 matched += shortcutsTW->findItems(searchLE->text(),
3332 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3334 // hide everyone (to avoid searching in matched QList repeatedly
3335 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3337 (*it++)->setHidden(true);
3338 // show matched items
3339 for (auto & item : matched)
3340 if (!isAlwaysHidden(*item)) {
3341 item->setHidden(false);
3343 item->parent()->setExpanded(true);
3348 docstring makeCmdString(FuncRequest const & f)
3350 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3351 if (!f.argument().empty())
3352 actionStr += " " + f.argument();
3357 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3359 FuncRequest res = user_bind_.getBinding(k);
3360 if (res.action() != LFUN_UNKNOWN_ACTION)
3362 res = system_bind_.getBinding(k);
3363 // Check if it is unbound. Note: user_unbind_ can only unbind one
3364 // FuncRequest per key sequence.
3365 if (user_unbind_.getBinding(k) == res)
3366 return FuncRequest::unknown;
3371 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3372 KeySequence const & k,
3373 QString const & lfun_to_modify)
3375 if (func.action() == LFUN_UNKNOWN_ACTION) {
3376 Alert::error(_("Failed to create shortcut"),
3377 _("Unknown or invalid LyX function"));
3381 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3382 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3383 // and how it is used in GuiPrefs::shortcutOkPressed.
3384 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3385 Alert::error(_("Failed to create shortcut"),
3386 _("This LyX function is hidden and cannot be bound."));
3390 if (k.length() == 0) {
3391 Alert::error(_("Failed to create shortcut"),
3392 _("Invalid or empty key sequence"));
3396 FuncRequest oldBinding = currentBinding(k);
3397 if (oldBinding == func)
3398 // nothing to change
3401 // make sure this key isn't already bound---and, if so, prompt user
3402 // (exclude the lfun the user already wants to modify)
3403 docstring const action_string = makeCmdString(oldBinding);
3404 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3405 && lfun_to_modify != toqstr(action_string)) {
3406 docstring const new_action_string = makeCmdString(func);
3407 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3409 "Are you sure you want to unbind the "
3410 "current shortcut and bind it to %3$s?"),
3411 k.print(KeySequence::ForGui), action_string,
3413 int ret = Alert::prompt(_("Redefine shortcut?"),
3414 text, 0, 1, _("&Redefine"), _("&Cancel"));
3417 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3418 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3419 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3420 deactivateShortcuts(items);
3426 void PrefShortcuts::shortcutOkPressed()
3428 QString const new_lfun = shortcut_->lfunLE->text();
3429 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3430 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3432 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3433 // "modify", or is empty if they clicked "new" (which I do not really like)
3434 if (!validateNewShortcut(func, k, save_lfun_))
3437 if (!save_lfun_.isEmpty()) {
3438 // real modification of the lfun's shortcut,
3439 // so remove the previous one
3440 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3441 deactivateShortcuts(to_modify);
3444 shortcut_->accept();
3446 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3448 user_bind_.bind(&k, func);
3449 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3451 item->parent()->setExpanded(true);
3452 shortcutsTW->setCurrentItem(item);
3453 shortcutsTW->scrollToItem(item);
3455 Alert::error(_("Failed to create shortcut"),
3456 _("Can not insert shortcut to the list"));
3462 void PrefShortcuts::shortcutCancelPressed()
3464 shortcut_->shortcutWG->reset();
3468 void PrefShortcuts::shortcutClearPressed()
3470 shortcut_->shortcutWG->reset();
3474 void PrefShortcuts::shortcutRemovePressed()
3476 shortcut_->shortcutWG->removeFromSequence();
3480 /////////////////////////////////////////////////////////////////////
3484 /////////////////////////////////////////////////////////////////////
3486 PrefIdentity::PrefIdentity(GuiPreferences * form)
3487 : PrefModule(QString(), N_("Identity"), form)
3491 connect(nameED, SIGNAL(textChanged(QString)),
3492 this, SIGNAL(changed()));
3493 connect(emailED, SIGNAL(textChanged(QString)),
3494 this, SIGNAL(changed()));
3495 connect(initialsED, SIGNAL(textChanged(QString)),
3496 this, SIGNAL(changed()));
3498 nameED->setValidator(new NoNewLineValidator(nameED));
3499 emailED->setValidator(new NoNewLineValidator(emailED));
3500 initialsED->setValidator(new NoNewLineValidator(initialsED));
3504 void PrefIdentity::applyRC(LyXRC & rc) const
3506 rc.user_name = fromqstr(nameED->text());
3507 rc.user_email = fromqstr(emailED->text());
3508 rc.user_initials = fromqstr(initialsED->text());
3512 void PrefIdentity::updateRC(LyXRC const & rc)
3514 nameED->setText(toqstr(rc.user_name));
3515 emailED->setText(toqstr(rc.user_email));
3516 initialsED->setText(toqstr(rc.user_initials));
3521 /////////////////////////////////////////////////////////////////////
3525 /////////////////////////////////////////////////////////////////////
3527 GuiPreferences::GuiPreferences(GuiView & lv)
3528 : GuiDialog(lv, "prefs", qt_("Preferences"))
3532 QDialog::setModal(false);
3534 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3535 this, SLOT(slotButtonBox(QAbstractButton *)));
3537 addModule(new PrefUserInterface(this));
3538 addModule(new PrefDocHandling(this));
3539 addModule(new PrefEdit(this));
3540 addModule(new PrefShortcuts(this));
3541 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3542 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3543 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3544 addModule(screenfonts);
3545 addModule(new PrefColors(this));
3546 addModule(new PrefDisplay(this));
3547 addModule(new PrefInput(this));
3548 addModule(new PrefCompletion(this));
3550 addModule(new PrefPaths(this));
3552 addModule(new PrefIdentity(this));
3554 addModule(new PrefLanguage(this));
3555 addModule(new PrefSpellchecker(this));
3557 PrefOutput * output = new PrefOutput(this);
3559 addModule(new PrefLatex(this));
3561 PrefConverters * converters = new PrefConverters(this);
3562 PrefFileformats * formats = new PrefFileformats(this);
3563 connect(formats, SIGNAL(formatsChanged()),
3564 converters, SLOT(updateGui()));
3565 addModule(converters);
3568 prefsPS->setCurrentPanel("User Interface");
3569 // FIXME: hack to work around resizing bug in Qt >= 4.2
3570 // bug verified with Qt 4.2.{0-3} (JSpitzm)
3571 #if QT_VERSION >= 0x040200
3572 prefsPS->updateGeometry();
3575 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3576 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3577 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3578 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3579 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3581 guilyxfiles_ = new GuiLyXFiles(lv);
3582 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3583 this, SLOT(slotFileSelected(QString)));
3587 void GuiPreferences::addModule(PrefModule * module)
3589 LASSERT(module, return);
3590 if (module->category().isEmpty())
3591 prefsPS->addPanel(module, module->title());
3593 prefsPS->addPanel(module, module->title(), module->category());
3594 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3595 modules_.push_back(module);
3599 void GuiPreferences::change_adaptor()
3605 void GuiPreferences::applyRC(LyXRC & rc) const
3607 size_t end = modules_.size();
3608 for (size_t i = 0; i != end; ++i)
3609 modules_[i]->applyRC(rc);
3613 void GuiPreferences::updateRC(LyXRC const & rc)
3615 size_t const end = modules_.size();
3616 for (size_t i = 0; i != end; ++i)
3617 modules_[i]->updateRC(rc);
3621 void GuiPreferences::applyView()
3627 bool GuiPreferences::initialiseParams(string const &)
3630 formats_ = theFormats();
3631 converters_ = theConverters();
3632 converters_.update(formats_);
3633 movers_ = theMovers();
3637 // Make sure that the bc is in the INITIAL state
3638 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3645 void GuiPreferences::dispatchParams()
3648 rc_.write(ss, true);
3649 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3650 // issue prefsApplied signal. This will update the
3651 // localized screen font sizes.
3653 // FIXME: these need lfuns
3655 Author const & author =
3656 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3657 from_utf8(rc_.user_initials));
3658 theBufferList().recordCurrentAuthor(author);
3660 theFormats() = formats_;
3662 theConverters() = converters_;
3663 theConverters().update(formats_);
3664 theConverters().buildGraph();
3665 theBufferList().invalidateConverterCache();
3667 theMovers() = movers_;
3669 for (string const & color : colors_)
3670 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3674 if (!tempSaveCB->isChecked())
3675 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3679 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3681 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3685 void GuiPreferences::slotFileSelected(QString const file)
3691 QString GuiPreferences::browseLibFile(QString const & dir,
3692 QString const & name, QString const & ext)
3696 guilyxfiles_->passParams(fromqstr(dir));
3697 guilyxfiles_->selectItem(name);
3698 guilyxfiles_->exec();
3700 QString const result = uifile_;
3702 // remove the extension if it is the default one
3703 QString noextresult;
3704 if (getExtension(result) == ext)
3705 noextresult = removeExtension(result);
3707 noextresult = result;
3709 // remove the directory, if it is the default one
3710 QString const file = onlyFileName(noextresult);
3711 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3718 QString GuiPreferences::browsebind(QString const & file)
3720 return browseLibFile("bind", file, "bind");
3724 QString GuiPreferences::browseUI(QString const & file)
3726 return browseLibFile("ui", file, "ui");
3730 QString GuiPreferences::browsekbmap(QString const & file)
3732 return browseLibFile("kbd", file, "kmap");
3736 QString GuiPreferences::browse(QString const & file,
3737 QString const & title) const
3739 return browseFile(file, title, QStringList(), true);
3743 } // namespace frontend
3746 #include "moc_GuiPrefs.cpp"