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()));
1331 connect(ctUseBackingstoreCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1335 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1337 previewSizeSB->setEnabled(index != 0);
1341 void PrefDisplay::applyRC(LyXRC & rc) const
1343 switch (instantPreviewCO->currentIndex()) {
1345 rc.preview = LyXRC::PREVIEW_OFF;
1348 rc.preview = LyXRC::PREVIEW_NO_MATH;
1351 rc.preview = LyXRC::PREVIEW_ON;
1355 rc.display_graphics = displayGraphicsCB->isChecked();
1356 rc.preview_scale_factor = previewSizeSB->value();
1357 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1358 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1359 rc.draw_strategy = ctUseBackingstoreCB->isChecked()
1360 ? LyXRC::DS_BACKINGSTORE : LyXRC::DS_PARTIAL;
1362 // FIXME!! The graphics cache no longer has a changeDisplay method.
1364 if (old_value != rc.display_graphics) {
1365 graphics::GCache & gc = graphics::GCache::get();
1372 void PrefDisplay::updateRC(LyXRC const & rc)
1374 switch (rc.preview) {
1375 case LyXRC::PREVIEW_OFF:
1376 instantPreviewCO->setCurrentIndex(0);
1378 case LyXRC::PREVIEW_NO_MATH :
1379 instantPreviewCO->setCurrentIndex(1);
1381 case LyXRC::PREVIEW_ON :
1382 instantPreviewCO->setCurrentIndex(2);
1386 displayGraphicsCB->setChecked(rc.display_graphics);
1387 previewSizeSB->setValue(rc.preview_scale_factor);
1388 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1389 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1390 ctUseBackingstoreCB->setChecked(rc.draw_strategy == LyXRC::DS_BACKINGSTORE);
1391 ctUseBackingstoreCB->setHidden(guiApp->needsBackingStore());
1392 previewSizeSB->setEnabled(
1394 && rc.preview != LyXRC::PREVIEW_OFF);
1398 /////////////////////////////////////////////////////////////////////
1402 /////////////////////////////////////////////////////////////////////
1404 PrefPaths::PrefPaths(GuiPreferences * form)
1405 : PrefModule(QString(), N_("Paths"), form)
1409 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1410 connect(workingDirED, SIGNAL(textChanged(QString)),
1411 this, SIGNAL(changed()));
1413 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1414 connect(templateDirED, SIGNAL(textChanged(QString)),
1415 this, SIGNAL(changed()));
1417 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1418 connect(exampleDirED, SIGNAL(textChanged(QString)),
1419 this, SIGNAL(changed()));
1421 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1422 connect(backupDirED, SIGNAL(textChanged(QString)),
1423 this, SIGNAL(changed()));
1425 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1426 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1427 this, SIGNAL(changed()));
1429 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1430 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1431 this, SIGNAL(changed()));
1433 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1434 connect(tempDirED, SIGNAL(textChanged(QString)),
1435 this, SIGNAL(changed()));
1437 #if defined(USE_HUNSPELL)
1438 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1439 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1440 this, SIGNAL(changed()));
1442 hunspellDirPB->setEnabled(false);
1443 hunspellDirED->setEnabled(false);
1446 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1447 this, SIGNAL(changed()));
1449 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1450 this, SIGNAL(changed()));
1452 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1453 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1457 void PrefPaths::applyRC(LyXRC & rc) const
1459 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1460 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1461 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1462 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1463 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1464 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1465 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1466 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1467 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1468 // FIXME: should be a checkbox only
1469 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1473 void PrefPaths::updateRC(LyXRC const & rc)
1475 workingDirED->setText(toqstr(external_path(rc.document_path)));
1476 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1477 templateDirED->setText(toqstr(external_path(rc.template_path)));
1478 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1479 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1480 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1481 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1482 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1483 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1484 // FIXME: should be a checkbox only
1485 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1489 void PrefPaths::selectExampledir()
1491 QString file = browseDir(internalPath(exampleDirED->text()),
1492 qt_("Select directory for example files"));
1493 if (!file.isEmpty())
1494 exampleDirED->setText(file);
1498 void PrefPaths::selectTemplatedir()
1500 QString file = browseDir(internalPath(templateDirED->text()),
1501 qt_("Select a document templates directory"));
1502 if (!file.isEmpty())
1503 templateDirED->setText(file);
1507 void PrefPaths::selectTempdir()
1509 QString file = browseDir(internalPath(tempDirED->text()),
1510 qt_("Select a temporary directory"));
1511 if (!file.isEmpty())
1512 tempDirED->setText(file);
1516 void PrefPaths::selectBackupdir()
1518 QString file = browseDir(internalPath(backupDirED->text()),
1519 qt_("Select a backups directory"));
1520 if (!file.isEmpty())
1521 backupDirED->setText(file);
1525 void PrefPaths::selectWorkingdir()
1527 QString file = browseDir(internalPath(workingDirED->text()),
1528 qt_("Select a document directory"));
1529 if (!file.isEmpty())
1530 workingDirED->setText(file);
1534 void PrefPaths::selectThesaurusdir()
1536 QString file = browseDir(internalPath(thesaurusDirED->text()),
1537 qt_("Set the path to the thesaurus dictionaries"));
1538 if (!file.isEmpty())
1539 thesaurusDirED->setText(file);
1543 void PrefPaths::selectHunspelldir()
1545 QString file = browseDir(internalPath(hunspellDirED->text()),
1546 qt_("Set the path to the Hunspell dictionaries"));
1547 if (!file.isEmpty())
1548 hunspellDirED->setText(file);
1552 void PrefPaths::selectLyxPipe()
1554 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1555 qt_("Give a filename for the LyX server pipe"));
1556 if (!file.isEmpty())
1557 lyxserverDirED->setText(file);
1561 /////////////////////////////////////////////////////////////////////
1565 /////////////////////////////////////////////////////////////////////
1567 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1568 : PrefModule(catLanguage, N_("Spellchecker"), form)
1572 // FIXME: this check should test the target platform (darwin)
1573 #if defined(USE_MACOSX_PACKAGING)
1574 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1575 #define CONNECT_APPLESPELL
1577 #undef CONNECT_APPLESPELL
1579 #if defined(USE_ASPELL)
1580 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1582 #if defined(USE_ENCHANT)
1583 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1585 #if defined(USE_HUNSPELL)
1586 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1589 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1590 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1591 this, SIGNAL(changed()));
1592 connect(altLanguageED, SIGNAL(textChanged(QString)),
1593 this, SIGNAL(changed()));
1594 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1595 this, SIGNAL(changed()));
1596 connect(compoundWordCB, SIGNAL(clicked()),
1597 this, SIGNAL(changed()));
1598 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1599 this, SIGNAL(changed()));
1600 connect(spellcheckNotesCB, SIGNAL(clicked()),
1601 this, SIGNAL(changed()));
1603 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1604 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1606 spellcheckerCB->setEnabled(false);
1607 altLanguageED->setEnabled(false);
1608 escapeCharactersED->setEnabled(false);
1609 compoundWordCB->setEnabled(false);
1610 spellcheckContinuouslyCB->setEnabled(false);
1611 spellcheckNotesCB->setEnabled(false);
1616 void PrefSpellchecker::applyRC(LyXRC & rc) const
1618 string const speller = fromqstr(spellcheckerCB->
1619 itemData(spellcheckerCB->currentIndex()).toString());
1620 if (!speller.empty())
1621 rc.spellchecker = speller;
1622 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1623 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1624 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1625 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1626 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1630 void PrefSpellchecker::updateRC(LyXRC const & rc)
1632 spellcheckerCB->setCurrentIndex(
1633 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1634 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1635 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1636 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1637 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1638 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1642 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1644 QString spellchecker = spellcheckerCB->itemData(index).toString();
1646 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1651 /////////////////////////////////////////////////////////////////////
1655 /////////////////////////////////////////////////////////////////////
1658 PrefConverters::PrefConverters(GuiPreferences * form)
1659 : PrefModule(catFiles, N_("Converters"), form)
1663 connect(converterNewPB, SIGNAL(clicked()),
1664 this, SLOT(updateConverter()));
1665 connect(converterRemovePB, SIGNAL(clicked()),
1666 this, SLOT(removeConverter()));
1667 connect(converterModifyPB, SIGNAL(clicked()),
1668 this, SLOT(updateConverter()));
1669 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1670 this, SLOT(switchConverter()));
1671 #if QT_VERSION < 0x050e00
1672 connect(converterFromCO, SIGNAL(activated(QString)),
1673 this, SLOT(changeConverter()));
1674 connect(converterToCO, SIGNAL(activated(QString)),
1675 this, SLOT(changeConverter()));
1677 connect(converterFromCO, SIGNAL(textActivated(QString)),
1678 this, SLOT(changeConverter()));
1679 connect(converterToCO, SIGNAL(textActivated(QString)),
1680 this, SLOT(changeConverter()));
1682 connect(converterED, SIGNAL(textEdited(QString)),
1683 this, SLOT(changeConverter()));
1684 connect(converterFlagED, SIGNAL(textEdited(QString)),
1685 this, SLOT(changeConverter()));
1686 connect(converterNewPB, SIGNAL(clicked()),
1687 this, SIGNAL(changed()));
1688 connect(converterRemovePB, SIGNAL(clicked()),
1689 this, SIGNAL(changed()));
1690 connect(converterModifyPB, SIGNAL(clicked()),
1691 this, SIGNAL(changed()));
1692 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1693 this, SIGNAL(changed()));
1694 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1695 this, SIGNAL(changed()));
1697 converterED->setValidator(new NoNewLineValidator(converterED));
1698 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1699 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1700 //converterDefGB->setFocusProxy(convertersLW);
1704 void PrefConverters::applyRC(LyXRC & rc) const
1706 rc.use_converter_cache = cacheCB->isChecked();
1707 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1708 rc.use_converter_needauth = needauthCB->isChecked();
1709 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1713 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1714 cb->blockSignals(true);
1715 cb->setChecked(checked);
1716 cb->blockSignals(false);
1720 void PrefConverters::updateRC(LyXRC const & rc)
1722 cacheCB->setChecked(rc.use_converter_cache);
1723 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1724 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1726 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1731 void PrefConverters::updateGui()
1733 QString const pattern("%1 -> %2");
1734 form_->formats().sort();
1735 form_->converters().update(form_->formats());
1736 // save current selection
1739 .arg(converterFromCO->currentText())
1740 .arg(converterToCO->currentText());
1742 converterFromCO->clear();
1743 converterToCO->clear();
1745 for (Format const & f : form_->formats()) {
1746 QString const name = toqstr(translateIfPossible(f.prettyname()));
1747 converterFromCO->addItem(name);
1748 converterToCO->addItem(name);
1751 // currentRowChanged(int) is also triggered when updating the listwidget
1752 // block signals to avoid unnecessary calls to switchConverter()
1753 convertersLW->blockSignals(true);
1754 convertersLW->clear();
1756 for (Converter const & c : form_->converters()) {
1757 QString const name =
1759 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1760 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1761 int type = form_->converters().getNumber(c.From()->name(),
1763 new QListWidgetItem(name, convertersLW, type);
1765 convertersLW->sortItems(Qt::AscendingOrder);
1766 convertersLW->blockSignals(false);
1768 // restore selection
1769 if (current != pattern.arg(QString()).arg(QString())) {
1770 QList<QListWidgetItem *> const item =
1771 convertersLW->findItems(current, Qt::MatchExactly);
1772 if (!item.isEmpty())
1773 convertersLW->setCurrentItem(item.at(0));
1776 // select first element if restoring failed
1777 if (convertersLW->currentRow() == -1)
1778 convertersLW->setCurrentRow(0);
1784 void PrefConverters::switchConverter()
1786 int const cnr = convertersLW->currentItem()->type();
1787 Converter const & c(form_->converters().get(cnr));
1788 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1789 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1790 converterED->setText(toqstr(c.command()));
1791 converterFlagED->setText(toqstr(c.flags()));
1797 void PrefConverters::changeConverter()
1803 void PrefConverters::updateButtons()
1805 if (form_->formats().empty())
1807 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1808 Format const & to = form_->formats().get(converterToCO->currentIndex());
1809 int const sel = form_->converters().getNumber(from.name(), to.name());
1810 bool const known = sel >= 0;
1811 bool const valid = !(converterED->text().isEmpty()
1812 || from.name() == to.name());
1817 if (convertersLW->count() > 0) {
1818 int const cnr = convertersLW->currentItem()->type();
1819 Converter const & c = form_->converters().get(cnr);
1820 old_command = c.command();
1821 old_flag = c.flags();
1824 string const new_command = fromqstr(converterED->text());
1825 string const new_flag = fromqstr(converterFlagED->text());
1827 bool modified = (old_command != new_command || old_flag != new_flag);
1829 converterModifyPB->setEnabled(valid && known && modified);
1830 converterNewPB->setEnabled(valid && !known);
1831 converterRemovePB->setEnabled(known);
1833 maxAgeLE->setEnabled(cacheCB->isChecked());
1834 maxAgeLA->setEnabled(cacheCB->isChecked());
1839 // specify unique from/to or it doesn't appear. This is really bad UI
1840 // this is why we can use the same function for both new and modify
1841 void PrefConverters::updateConverter()
1843 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1844 Format const & to = form_->formats().get(converterToCO->currentIndex());
1845 string const flags = fromqstr(converterFlagED->text());
1846 string const command = fromqstr(converterED->text());
1848 Converter const * old =
1849 form_->converters().getConverter(from.name(), to.name());
1850 form_->converters().add(from.name(), to.name(), command, flags);
1853 form_->converters().updateLast(form_->formats());
1857 // Remove all files created by this converter from the cache, since
1858 // the modified converter might create different files.
1859 ConverterCache::get().remove_all(from.name(), to.name());
1863 void PrefConverters::removeConverter()
1865 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1866 Format const & to = form_->formats().get(converterToCO->currentIndex());
1867 form_->converters().erase(from.name(), to.name());
1871 // Remove all files created by this converter from the cache, since
1872 // a possible new converter might create different files.
1873 ConverterCache::get().remove_all(from.name(), to.name());
1877 void PrefConverters::on_cacheCB_stateChanged(int state)
1879 maxAgeLE->setEnabled(state == Qt::Checked);
1880 maxAgeLA->setEnabled(state == Qt::Checked);
1885 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1887 needauthCB->setEnabled(!checked);
1891 void PrefConverters::on_needauthCB_toggled(bool checked)
1898 int ret = frontend::Alert::prompt(
1899 _("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!"),
1900 0, 0, _("&No"), _("&Yes"));
1904 setCheckboxBlockSignals(needauthCB, true);
1908 /////////////////////////////////////////////////////////////////////
1912 /////////////////////////////////////////////////////////////////////
1914 class FormatValidator : public QValidator
1917 FormatValidator(QWidget *, Formats const & f);
1918 void fixup(QString & input) const override;
1919 QValidator::State validate(QString & input, int & pos) const override;
1921 virtual QString toString(Format const & format) const = 0;
1923 Formats const & formats_;
1927 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1928 : QValidator(parent), formats_(f)
1933 void FormatValidator::fixup(QString & input) const
1935 Formats::const_iterator cit = formats_.begin();
1936 Formats::const_iterator end = formats_.end();
1937 for (; cit != end; ++cit) {
1938 QString const name = toString(*cit);
1939 if (distance(formats_.begin(), cit) == nr()) {
1947 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1949 Formats::const_iterator cit = formats_.begin();
1950 Formats::const_iterator end = formats_.end();
1951 bool unknown = true;
1952 for (; unknown && cit != end; ++cit) {
1953 QString const name = toString(*cit);
1954 if (distance(formats_.begin(), cit) != nr())
1955 unknown = name != input;
1958 if (unknown && !input.isEmpty())
1959 return QValidator::Acceptable;
1961 return QValidator::Intermediate;
1965 int FormatValidator::nr() const
1967 QComboBox * p = qobject_cast<QComboBox *>(parent());
1968 return p->itemData(p->currentIndex()).toInt();
1972 /////////////////////////////////////////////////////////////////////
1974 // FormatNameValidator
1976 /////////////////////////////////////////////////////////////////////
1978 class FormatNameValidator : public FormatValidator
1981 FormatNameValidator(QWidget * parent, Formats const & f)
1982 : FormatValidator(parent, f)
1985 QString toString(Format const & format) const override
1987 return toqstr(format.name());
1992 /////////////////////////////////////////////////////////////////////
1994 // FormatPrettynameValidator
1996 /////////////////////////////////////////////////////////////////////
1998 class FormatPrettynameValidator : public FormatValidator
2001 FormatPrettynameValidator(QWidget * parent, Formats const & f)
2002 : FormatValidator(parent, f)
2005 QString toString(Format const & format) const override
2007 return toqstr(translateIfPossible(format.prettyname()));
2012 /////////////////////////////////////////////////////////////////////
2016 /////////////////////////////////////////////////////////////////////
2018 PrefFileformats::PrefFileformats(GuiPreferences * form)
2019 : PrefModule(catFiles, N_("File Formats"), form)
2023 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2024 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2025 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2026 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2027 editorED->setValidator(new NoNewLineValidator(editorED));
2028 viewerED->setValidator(new NoNewLineValidator(viewerED));
2029 copierED->setValidator(new NoNewLineValidator(copierED));
2031 connect(documentCB, SIGNAL(clicked()),
2032 this, SLOT(setFlags()));
2033 connect(vectorCB, SIGNAL(clicked()),
2034 this, SLOT(setFlags()));
2035 connect(exportMenuCB, SIGNAL(clicked()),
2036 this, SLOT(setFlags()));
2037 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2038 this, SLOT(updatePrettyname()));
2039 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2040 this, SIGNAL(changed()));
2041 #if QT_VERSION < 0x050e00
2042 connect(defaultFormatCB, SIGNAL(activated(QString)),
2043 this, SIGNAL(changed()));
2044 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2045 this, SIGNAL(changed()));
2046 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2047 this, SIGNAL(changed()));
2049 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2050 this, SIGNAL(changed()));
2051 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2052 this, SIGNAL(changed()));
2053 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2054 this, SIGNAL(changed()));
2056 connect(viewerCO, SIGNAL(activated(int)),
2057 this, SIGNAL(changed()));
2058 connect(editorCO, SIGNAL(activated(int)),
2059 this, SIGNAL(changed()));
2065 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2067 if (shortcut.empty())
2070 string l10n_format =
2071 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2072 return split(l10n_format, '|');
2078 void PrefFileformats::applyRC(LyXRC & rc) const
2080 QString const default_format = defaultFormatCB->itemData(
2081 defaultFormatCB->currentIndex()).toString();
2082 rc.default_view_format = fromqstr(default_format);
2083 QString const default_otf_format = defaultOTFFormatCB->itemData(
2084 defaultOTFFormatCB->currentIndex()).toString();
2085 rc.default_otf_view_format = fromqstr(default_otf_format);
2086 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2087 defaultPlatexFormatCB->currentIndex()).toString();
2088 rc.default_platex_view_format = fromqstr(default_platex_format);
2092 void PrefFileformats::updateRC(LyXRC const & rc)
2094 viewer_alternatives = rc.viewer_alternatives;
2095 editor_alternatives = rc.editor_alternatives;
2096 bool const init = defaultFormatCB->currentText().isEmpty();
2100 defaultFormatCB->findData(toqstr(rc.default_view_format));
2101 defaultFormatCB->setCurrentIndex(pos);
2102 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2103 defaultOTFFormatCB->setCurrentIndex(pos);
2104 defaultOTFFormatCB->setCurrentIndex(pos);
2105 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2106 defaultPlatexFormatCB->setCurrentIndex(pos);
2107 defaultPlatexFormatCB->setCurrentIndex(pos);
2112 void PrefFileformats::updateView()
2114 QString const current = formatsCB->currentText();
2115 QString const current_def = defaultFormatCB->currentText();
2116 QString const current_def_otf = defaultOTFFormatCB->currentText();
2117 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2119 // update comboboxes with formats
2120 formatsCB->blockSignals(true);
2121 defaultFormatCB->blockSignals(true);
2122 defaultOTFFormatCB->blockSignals(true);
2123 defaultPlatexFormatCB->blockSignals(true);
2125 defaultFormatCB->clear();
2126 defaultOTFFormatCB->clear();
2127 defaultPlatexFormatCB->clear();
2128 form_->formats().sort();
2129 for (Format const & f : form_->formats()) {
2130 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2131 formatsCB->addItem(prettyname,
2132 QVariant(form_->formats().getNumber(f.name())));
2133 if (f.viewer().empty())
2135 if (form_->converters().isReachable("xhtml", f.name())
2136 || form_->converters().isReachable("dviluatex", f.name())
2137 || form_->converters().isReachable("luatex", f.name())
2138 || form_->converters().isReachable("xetex", f.name())) {
2139 defaultFormatCB->addItem(prettyname,
2140 QVariant(toqstr(f.name())));
2141 defaultOTFFormatCB->addItem(prettyname,
2142 QVariant(toqstr(f.name())));
2144 if (form_->converters().isReachable("latex", f.name())
2145 || form_->converters().isReachable("pdflatex", f.name()))
2146 defaultFormatCB->addItem(prettyname,
2147 QVariant(toqstr(f.name())));
2148 if (form_->converters().isReachable("platex", f.name()))
2149 defaultPlatexFormatCB->addItem(prettyname,
2150 QVariant(toqstr(f.name())));
2154 // restore selections
2155 int item = formatsCB->findText(current, Qt::MatchExactly);
2156 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2157 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2158 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2159 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2160 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2161 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2162 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2163 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2164 formatsCB->blockSignals(false);
2165 defaultFormatCB->blockSignals(false);
2166 defaultOTFFormatCB->blockSignals(false);
2167 defaultPlatexFormatCB->blockSignals(false);
2171 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2173 if (form_->formats().empty())
2175 int const nr = formatsCB->itemData(i).toInt();
2176 Format const f = form_->formats().get(nr);
2178 formatED->setText(toqstr(f.name()));
2179 copierED->setText(toqstr(form_->movers().command(f.name())));
2180 extensionsED->setText(toqstr(f.extensions()));
2181 mimeED->setText(toqstr(f.mime()));
2182 shortcutED->setText(
2183 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2184 documentCB->setChecked((f.documentFormat()));
2185 vectorCB->setChecked((f.vectorFormat()));
2186 exportMenuCB->setChecked((f.inExportMenu()));
2187 exportMenuCB->setEnabled((f.documentFormat()));
2193 void PrefFileformats::setFlags()
2195 int flags = Format::none;
2196 if (documentCB->isChecked())
2197 flags |= Format::document;
2198 if (vectorCB->isChecked())
2199 flags |= Format::vector;
2200 if (exportMenuCB->isChecked())
2201 flags |= Format::export_menu;
2202 currentFormat().setFlags(flags);
2203 exportMenuCB->setEnabled(documentCB->isChecked());
2208 void PrefFileformats::on_copierED_textEdited(const QString & s)
2210 string const fmt = fromqstr(formatED->text());
2211 form_->movers().set(fmt, fromqstr(s));
2216 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2218 currentFormat().setExtensions(fromqstr(s));
2223 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2225 currentFormat().setViewer(fromqstr(s));
2230 void PrefFileformats::on_editorED_textEdited(const QString & s)
2232 currentFormat().setEditor(fromqstr(s));
2237 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2239 currentFormat().setMime(fromqstr(s));
2244 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2246 string const new_shortcut = fromqstr(s);
2247 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2248 currentFormat().shortcut()))
2250 currentFormat().setShortcut(new_shortcut);
2255 void PrefFileformats::on_formatED_editingFinished()
2257 string const newname = fromqstr(formatED->displayText());
2258 string const oldname = currentFormat().name();
2259 if (newname == oldname)
2261 if (form_->converters().formatIsUsed(oldname)) {
2262 Alert::error(_("Format in use"),
2263 _("You cannot change a format's short name "
2264 "if the format is used by a converter. "
2265 "Please remove the converter first."));
2270 currentFormat().setName(newname);
2275 void PrefFileformats::on_formatED_textChanged(const QString &)
2277 QString t = formatED->text();
2279 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2280 setValid(formatLA, valid);
2284 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2286 QString t = formatsCB->currentText();
2288 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2289 setValid(formatsLA, valid);
2293 void PrefFileformats::updatePrettyname()
2295 QString const newname = formatsCB->currentText();
2296 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2299 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2307 void updateComboBox(LyXRC::Alternatives const & alts,
2308 string const & fmt, QComboBox * combo)
2310 LyXRC::Alternatives::const_iterator it =
2312 if (it != alts.end()) {
2313 LyXRC::CommandSet const & cmds = it->second;
2314 LyXRC::CommandSet::const_iterator sit =
2316 LyXRC::CommandSet::const_iterator const sen =
2318 for (; sit != sen; ++sit) {
2319 QString const qcmd = toqstr(*sit);
2320 combo->addItem(qcmd, qcmd);
2327 void PrefFileformats::updateViewers()
2329 Format const f = currentFormat();
2330 viewerCO->blockSignals(true);
2332 viewerCO->addItem(qt_("None"), QString());
2333 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2334 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2335 viewerCO->blockSignals(false);
2337 int pos = viewerCO->findData(toqstr(f.viewer()));
2340 viewerED->setEnabled(false);
2341 viewerCO->setCurrentIndex(pos);
2343 viewerED->setEnabled(true);
2344 viewerED->setText(toqstr(f.viewer()));
2345 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2350 void PrefFileformats::updateEditors()
2352 Format const f = currentFormat();
2353 editorCO->blockSignals(true);
2355 editorCO->addItem(qt_("None"), QString());
2356 updateComboBox(editor_alternatives, f.name(), editorCO);
2357 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2358 editorCO->blockSignals(false);
2360 int pos = editorCO->findData(toqstr(f.editor()));
2363 editorED->setEnabled(false);
2364 editorCO->setCurrentIndex(pos);
2366 editorED->setEnabled(true);
2367 editorED->setText(toqstr(f.editor()));
2368 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2373 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2375 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2376 viewerED->setEnabled(custom);
2378 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2382 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2384 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2385 editorED->setEnabled(custom);
2387 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2391 Format & PrefFileformats::currentFormat()
2393 int const i = formatsCB->currentIndex();
2394 int const nr = formatsCB->itemData(i).toInt();
2395 return form_->formats().get(nr);
2399 void PrefFileformats::on_formatNewPB_clicked()
2401 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2403 formatsCB->setCurrentIndex(0);
2404 formatsCB->setFocus(Qt::OtherFocusReason);
2408 void PrefFileformats::on_formatRemovePB_clicked()
2410 int const i = formatsCB->currentIndex();
2411 int const nr = formatsCB->itemData(i).toInt();
2412 string const current_text = form_->formats().get(nr).name();
2413 if (form_->converters().formatIsUsed(current_text)) {
2414 Alert::error(_("Format in use"),
2415 _("Cannot remove a Format used by a Converter. "
2416 "Remove the converter first."));
2420 form_->formats().erase(current_text);
2423 on_formatsCB_editTextChanged(formatsCB->currentText());
2428 /////////////////////////////////////////////////////////////////////
2432 /////////////////////////////////////////////////////////////////////
2434 PrefLanguage::PrefLanguage(GuiPreferences * form)
2435 : PrefModule(catLanguage, N_("Language"), form)
2439 connect(visualCursorRB, SIGNAL(clicked()),
2440 this, SIGNAL(changed()));
2441 connect(logicalCursorRB, SIGNAL(clicked()),
2442 this, SIGNAL(changed()));
2443 connect(markForeignCB, SIGNAL(clicked()),
2444 this, SIGNAL(changed()));
2445 connect(respectOSkbdCB, SIGNAL(clicked()),
2446 this, SIGNAL(changed()));
2447 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2448 this, SIGNAL(changed()));
2449 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2450 this, SIGNAL(changed()));
2451 connect(languagePackageCO, SIGNAL(activated(int)),
2452 this, SIGNAL(changed()));
2453 connect(languagePackageED, SIGNAL(textChanged(QString)),
2454 this, SIGNAL(changed()));
2455 connect(globalCB, SIGNAL(clicked()),
2456 this, SIGNAL(changed()));
2457 connect(startCommandED, SIGNAL(textChanged(QString)),
2458 this, SIGNAL(changed()));
2459 connect(endCommandED, SIGNAL(textChanged(QString)),
2460 this, SIGNAL(changed()));
2461 connect(uiLanguageCO, SIGNAL(activated(int)),
2462 this, SIGNAL(changed()));
2463 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2464 this, SIGNAL(changed()));
2465 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2466 this, SIGNAL(changed()));
2467 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2468 this, SIGNAL(changed()));
2470 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2471 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2472 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2474 #if QT_VERSION < 0x060000
2475 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2477 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2479 defaultDecimalSepED->setMaxLength(1);
2481 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2482 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2484 QAbstractItemModel * language_model = guiApp->languageModel();
2485 language_model->sort(0);
2486 uiLanguageCO->blockSignals(true);
2487 uiLanguageCO->clear();
2488 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2489 for (int i = 0; i != language_model->rowCount(); ++i) {
2490 QModelIndex index = language_model->index(i, 0);
2491 // Filter the list based on the available translation and add
2492 // each language code only once
2493 string const name = fromqstr(index.data(Qt::UserRole).toString());
2494 Language const * lang = languages.getLanguage(name);
2497 // never remove the currently selected language
2498 if (name != form->rc().gui_language
2499 && name != lyxrc.gui_language
2500 && (!Messages::available(lang->code())
2501 || !lang->hasGuiSupport()))
2503 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2504 index.data(Qt::UserRole).toString());
2506 uiLanguageCO->blockSignals(false);
2508 // FIXME: restore this when it works (see discussion in #6450).
2509 respectOSkbdCB->hide();
2513 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2515 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2516 qt_("The change of user interface language will be fully "
2517 "effective only after a restart."));
2521 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2524 languagePackageED->setText(save_langpack_);
2525 else if (!languagePackageED->text().isEmpty()) {
2526 save_langpack_ = languagePackageED->text();
2527 languagePackageED->clear();
2529 languagePackageED->setEnabled(i == 2);
2533 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2535 defaultDecimalSepED->setEnabled(i == 1);
2539 void PrefLanguage::applyRC(LyXRC & rc) const
2541 rc.visual_cursor = visualCursorRB->isChecked();
2542 rc.mark_foreign_language = markForeignCB->isChecked();
2543 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2544 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2545 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2546 int const p = languagePackageCO->currentIndex();
2548 rc.language_package_selection = LyXRC::LP_AUTO;
2550 rc.language_package_selection = LyXRC::LP_BABEL;
2552 rc.language_package_selection = LyXRC::LP_CUSTOM;
2554 rc.language_package_selection = LyXRC::LP_NONE;
2555 rc.language_custom_package = fromqstr(languagePackageED->text());
2556 rc.language_global_options = globalCB->isChecked();
2557 rc.language_command_begin = fromqstr(startCommandED->text());
2558 rc.language_command_end = fromqstr(endCommandED->text());
2559 rc.gui_language = fromqstr(
2560 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2561 if (defaultDecimalSepCO->currentIndex() == 0)
2562 rc.default_decimal_sep = "locale";
2564 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2565 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2569 void PrefLanguage::updateRC(LyXRC const & rc)
2571 if (rc.visual_cursor)
2572 visualCursorRB->setChecked(true);
2574 logicalCursorRB->setChecked(true);
2575 markForeignCB->setChecked(rc.mark_foreign_language);
2576 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2577 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2578 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2579 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2580 if (languagePackageCO->currentIndex() == 2) {
2581 languagePackageED->setText(toqstr(rc.language_custom_package));
2582 languagePackageED->setEnabled(true);
2584 languagePackageED->clear();
2585 save_langpack_ = toqstr(rc.language_custom_package);
2586 languagePackageED->setEnabled(false);
2588 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2589 globalCB->setChecked(rc.language_global_options);
2590 startCommandED->setText(toqstr(rc.language_command_begin));
2591 endCommandED->setText(toqstr(rc.language_command_end));
2592 if (rc.default_decimal_sep == "locale") {
2593 defaultDecimalSepCO->setCurrentIndex(0);
2594 defaultDecimalSepED->clear();
2596 defaultDecimalSepCO->setCurrentIndex(1);
2597 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2599 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2600 defaultLengthUnitCO->setCurrentIndex(pos);
2602 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2603 uiLanguageCO->blockSignals(true);
2604 uiLanguageCO->setCurrentIndex(pos);
2605 uiLanguageCO->blockSignals(false);
2609 /////////////////////////////////////////////////////////////////////
2611 // PrefUserInterface
2613 /////////////////////////////////////////////////////////////////////
2615 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2616 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2620 connect(uiFilePB, SIGNAL(clicked()),
2621 this, SLOT(selectUi()));
2622 connect(uiFileED, SIGNAL(textChanged(QString)),
2623 this, SIGNAL(changed()));
2624 connect(iconSetCO, SIGNAL(activated(int)),
2625 this, SIGNAL(changed()));
2626 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2627 this, SIGNAL(changed()));
2628 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2629 this, SIGNAL(changed()));
2630 connect(tooltipCB, SIGNAL(toggled(bool)),
2631 this, SIGNAL(changed()));
2632 lastfilesSB->setMaximum(maxlastfiles);
2634 iconSetCO->addItem(qt_("Default"), QString());
2635 iconSetCO->addItem(qt_("Classic"), "classic");
2636 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2638 #if QT_VERSION >= 0x040600
2639 if (guiApp->platformName() != "qt4x11"
2640 && guiApp->platformName() != "xcb"
2641 && !guiApp->platformName().contains("wayland"))
2643 useSystemThemeIconsCB->hide();
2647 void PrefUserInterface::applyRC(LyXRC & rc) const
2649 rc.icon_set = fromqstr(iconSetCO->itemData(
2650 iconSetCO->currentIndex()).toString());
2652 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2653 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2654 rc.num_lastfiles = lastfilesSB->value();
2655 rc.use_tooltip = tooltipCB->isChecked();
2659 void PrefUserInterface::updateRC(LyXRC const & rc)
2661 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2664 iconSetCO->setCurrentIndex(iconset);
2665 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2666 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2667 lastfilesSB->setValue(rc.num_lastfiles);
2668 tooltipCB->setChecked(rc.use_tooltip);
2672 void PrefUserInterface::selectUi()
2674 QString file = form_->browseUI(internalPath(uiFileED->text()));
2675 if (!file.isEmpty())
2676 uiFileED->setText(file);
2680 /////////////////////////////////////////////////////////////////////
2682 // PrefDocumentHandling
2684 /////////////////////////////////////////////////////////////////////
2686 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2687 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2691 connect(autoSaveCB, SIGNAL(toggled(bool)),
2692 autoSaveSB, SLOT(setEnabled(bool)));
2693 connect(autoSaveCB, SIGNAL(toggled(bool)),
2694 TextLabel1, SLOT(setEnabled(bool)));
2695 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2696 this, SIGNAL(changed()));
2697 connect(singleInstanceCB, SIGNAL(clicked()),
2698 this, SIGNAL(changed()));
2699 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2700 this, SIGNAL(changed()));
2701 connect(closeLastViewCO, SIGNAL(activated(int)),
2702 this, SIGNAL(changed()));
2703 connect(restoreCursorCB, SIGNAL(clicked()),
2704 this, SIGNAL(changed()));
2705 connect(loadSessionCB, SIGNAL(clicked()),
2706 this, SIGNAL(changed()));
2707 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2708 this, SIGNAL(changed()));
2709 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2710 this, SIGNAL(changed()));
2711 connect(autoSaveCB, SIGNAL(clicked()),
2712 this, SIGNAL(changed()));
2713 connect(backupCB, SIGNAL(clicked()),
2714 this, SIGNAL(changed()));
2715 connect(saveCompressedCB, SIGNAL(clicked()),
2716 this, SIGNAL(changed()));
2717 connect(saveOriginCB, SIGNAL(clicked()),
2718 this, SIGNAL(changed()));
2722 void PrefDocHandling::applyRC(LyXRC & rc) const
2724 rc.use_lastfilepos = restoreCursorCB->isChecked();
2725 rc.load_session = loadSessionCB->isChecked();
2726 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2727 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2728 rc.make_backup = backupCB->isChecked();
2729 rc.save_compressed = saveCompressedCB->isChecked();
2730 rc.save_origin = saveOriginCB->isChecked();
2731 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2732 rc.single_instance = singleInstanceCB->isChecked();
2733 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2735 switch (closeLastViewCO->currentIndex()) {
2737 rc.close_buffer_with_last_view = "yes";
2740 rc.close_buffer_with_last_view = "no";
2743 rc.close_buffer_with_last_view = "ask";
2751 void PrefDocHandling::updateRC(LyXRC const & rc)
2753 restoreCursorCB->setChecked(rc.use_lastfilepos);
2754 loadSessionCB->setChecked(rc.load_session);
2755 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2756 // convert to minutes
2757 bool autosave = rc.autosave > 0;
2758 int mins = rc.autosave / 60;
2761 autoSaveSB->setValue(mins);
2762 autoSaveCB->setChecked(autosave);
2763 autoSaveSB->setEnabled(autosave);
2764 backupCB->setChecked(rc.make_backup);
2765 saveCompressedCB->setChecked(rc.save_compressed);
2766 saveOriginCB->setChecked(rc.save_origin);
2767 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2768 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2769 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2770 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2771 if (rc.close_buffer_with_last_view == "yes")
2772 closeLastViewCO->setCurrentIndex(0);
2773 else if (rc.close_buffer_with_last_view == "no")
2774 closeLastViewCO->setCurrentIndex(1);
2775 else if (rc.close_buffer_with_last_view == "ask")
2776 closeLastViewCO->setCurrentIndex(2);
2780 void PrefDocHandling::on_clearSessionPB_clicked()
2782 guiApp->clearSession();
2787 /////////////////////////////////////////////////////////////////////
2791 /////////////////////////////////////////////////////////////////////
2793 PrefEdit::PrefEdit(GuiPreferences * form)
2794 : PrefModule(catEditing, N_("Control"), form)
2798 connect(cursorFollowsCB, SIGNAL(clicked()),
2799 this, SIGNAL(changed()));
2800 connect(scrollBelowCB, SIGNAL(clicked()),
2801 this, SIGNAL(changed()));
2802 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2803 this, SIGNAL(changed()));
2804 connect(copyCTMarkupCB, SIGNAL(clicked()),
2805 this, SIGNAL(changed()));
2806 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2807 this, SIGNAL(changed()));
2808 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2809 this, SIGNAL(changed()));
2810 connect(macroEditStyleCO, SIGNAL(activated(int)),
2811 this, SIGNAL(changed()));
2812 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2813 this, SIGNAL(changed()));
2814 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2815 this, SIGNAL(changed()));
2816 connect(fullscreenWidthSB, SIGNAL(valueChanged(int)),
2817 this, SIGNAL(changed()));
2818 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2819 this, SIGNAL(changed()));
2820 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2821 this, SIGNAL(changed()));
2822 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2823 this, SIGNAL(changed()));
2824 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2825 this, SIGNAL(changed()));
2826 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2827 this, SIGNAL(changed()));
2831 void PrefEdit::on_fullscreenLimitCB_toggled(bool const state)
2833 fullscreenWidthSB->setEnabled(state);
2834 fullscreenWidthLA->setEnabled(state);
2839 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2841 citationSearchLE->setEnabled(state);
2842 citationSearchLA->setEnabled(state);
2847 void PrefEdit::applyRC(LyXRC & rc) const
2849 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2850 rc.scroll_below_document = scrollBelowCB->isChecked();
2851 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2852 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2853 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2854 rc.group_layouts = groupEnvironmentsCB->isChecked();
2855 switch (macroEditStyleCO->currentIndex()) {
2856 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2857 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2858 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2860 rc.cursor_width = cursorWidthSB->value();
2861 rc.citation_search = citationSearchCB->isChecked();
2862 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2863 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2864 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2865 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2866 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2867 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2868 rc.full_screen_width = fullscreenWidthSB->value();
2869 rc.full_screen_limit = fullscreenLimitCB->isChecked();
2873 void PrefEdit::updateRC(LyXRC const & rc)
2875 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2876 scrollBelowCB->setChecked(rc.scroll_below_document);
2877 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2878 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2879 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2880 groupEnvironmentsCB->setChecked(rc.group_layouts);
2881 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2882 cursorWidthSB->setValue(rc.cursor_width);
2883 citationSearchCB->setChecked(rc.citation_search);
2884 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2885 citationSearchLE->setEnabled(rc.citation_search);
2886 citationSearchLA->setEnabled(rc.citation_search);
2887 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2888 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2889 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2890 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2891 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2892 fullscreenWidthSB->setValue(rc.full_screen_width);
2893 fullscreenLimitCB->setChecked(rc.full_screen_limit);
2894 fullscreenWidthSB->setEnabled(rc.full_screen_limit);
2895 fullscreenWidthLA->setEnabled(rc.full_screen_limit);
2899 /////////////////////////////////////////////////////////////////////
2903 /////////////////////////////////////////////////////////////////////
2906 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2908 Ui::shortcutUi::setupUi(this);
2909 QDialog::setModal(true);
2910 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2914 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2915 : PrefModule(catEditing, N_("Shortcuts"), form),
2916 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2917 systemItem_(nullptr)
2921 shortcutsTW->setColumnCount(2);
2922 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2923 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2924 shortcutsTW->setSortingEnabled(true);
2925 // Multi-selection can be annoying.
2926 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2928 connect(bindFilePB, SIGNAL(clicked()),
2929 this, SLOT(selectBind()));
2930 connect(bindFileED, SIGNAL(textChanged(QString)),
2931 this, SIGNAL(changed()));
2933 shortcut_ = new GuiShortcutDialog(this);
2934 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2935 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2936 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2938 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2939 this, SIGNAL(changed()));
2940 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2941 shortcut_, SLOT(reject()));
2942 connect(shortcut_->clearPB, SIGNAL(clicked()),
2943 this, SLOT(shortcutClearPressed()));
2944 connect(shortcut_->removePB, SIGNAL(clicked()),
2945 this, SLOT(shortcutRemovePressed()));
2946 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2947 this, SLOT(shortcutOkPressed()));
2948 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2949 this, SLOT(shortcutCancelPressed()));
2953 void PrefShortcuts::applyRC(LyXRC & rc) const
2955 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2956 // write user_bind and user_unbind to .lyx/bind/user.bind
2957 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2958 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2959 lyxerr << "LyX could not create the user bind directory '"
2960 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2963 if (!bind_dir.isDirWritable()) {
2964 lyxerr << "LyX could not write to the user bind directory '"
2965 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2968 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2969 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2970 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2971 // immediately apply the keybindings. Why this is not done before?
2972 // The good thing is that the menus are updated automatically.
2973 theTopLevelKeymap().clear();
2974 theTopLevelKeymap().read("site");
2975 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2976 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2980 void PrefShortcuts::updateRC(LyXRC const & rc)
2982 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2984 system_bind_.clear();
2986 user_unbind_.clear();
2987 system_bind_.read("site");
2988 system_bind_.read(rc.bind_file);
2989 // \unbind in user.bind is added to user_unbind_
2990 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2991 updateShortcutsTW();
2995 void PrefShortcuts::updateShortcutsTW()
2997 shortcutsTW->clear();
2999 editItem_ = new QTreeWidgetItem(shortcutsTW);
3000 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
3001 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
3003 mathItem_ = new QTreeWidgetItem(shortcutsTW);
3004 mathItem_->setText(0, qt_("Mathematical Symbols"));
3005 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3007 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3008 bufferItem_->setText(0, qt_("Document and Window"));
3009 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3011 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3012 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3013 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3015 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3016 systemItem_->setText(0, qt_("System and Miscellaneous"));
3017 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3019 // listBindings(unbound=true) lists all bound and unbound lfuns
3020 // Items in this list is tagged by its source.
3021 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3023 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3025 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3026 KeyMap::UserUnbind);
3027 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3028 user_bindinglist.end());
3029 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3030 user_unbindinglist.end());
3032 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3033 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3034 for (; it != it_end; ++it)
3035 insertShortcutItem(it->request, it->sequence, it->tag);
3037 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3038 on_shortcutsTW_itemSelectionChanged();
3039 on_searchLE_textEdited();
3040 shortcutsTW->resizeColumnToContents(0);
3045 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3047 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3052 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3054 // Hide rebound system settings that are empty
3055 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3059 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3061 item->setData(0, Qt::UserRole, QVariant(tag));
3065 case KeyMap::System:
3067 case KeyMap::UserBind:
3070 case KeyMap::UserUnbind:
3071 font.setStrikeOut(true);
3073 // this item is not displayed now.
3074 case KeyMap::UserExtraUnbind:
3075 font.setStrikeOut(true);
3078 item->setHidden(isAlwaysHidden(*item));
3079 item->setFont(1, font);
3083 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3084 KeySequence const & seq, KeyMap::ItemType tag)
3086 FuncCode const action = lfun.action();
3087 string const action_name = lyxaction.getActionName(action);
3088 QString const lfun_name = toqstr(from_utf8(action_name)
3089 + ' ' + lfun.argument());
3090 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3092 QTreeWidgetItem * newItem = nullptr;
3093 // for unbind items, try to find an existing item in the system bind list
3094 if (tag == KeyMap::UserUnbind) {
3095 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(lfun_name,
3096 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3097 for (auto const & item : items) {
3098 if (item->text(1) == shortcut) {
3103 // if not found, this unbind item is KeyMap::UserExtraUnbind
3104 // Such an item is not displayed to avoid confusion (what is
3105 // unmatched removed?).
3111 switch(lyxaction.getActionType(action)) {
3112 case LyXAction::Hidden:
3114 case LyXAction::Edit:
3115 newItem = new QTreeWidgetItem(editItem_);
3117 case LyXAction::Math:
3118 newItem = new QTreeWidgetItem(mathItem_);
3120 case LyXAction::Buffer:
3121 newItem = new QTreeWidgetItem(bufferItem_);
3123 case LyXAction::Layout:
3124 newItem = new QTreeWidgetItem(layoutItem_);
3126 case LyXAction::System:
3127 newItem = new QTreeWidgetItem(systemItem_);
3130 // this should not happen
3131 newItem = new QTreeWidgetItem(shortcutsTW);
3135 newItem->setText(0, lfun_name);
3136 newItem->setText(1, shortcut);
3137 // record BindFile representation to recover KeySequence when needed.
3138 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3139 setItemType(newItem, tag);
3144 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3146 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3147 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3148 modifyPB->setEnabled(!items.isEmpty());
3149 if (items.isEmpty())
3152 if (itemType(*items[0]) == KeyMap::UserUnbind)
3153 removePB->setText(qt_("Res&tore"));
3155 removePB->setText(qt_("Remo&ve"));
3159 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3165 void PrefShortcuts::modifyShortcut()
3167 QTreeWidgetItem * item = shortcutsTW->currentItem();
3168 if (item->flags() & Qt::ItemIsSelectable) {
3169 shortcut_->lfunLE->setText(item->text(0));
3170 save_lfun_ = item->text(0).trimmed();
3171 shortcut_->shortcutWG->setText(item->text(1));
3173 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3174 shortcut_->shortcutWG->setKeySequence(seq);
3175 shortcut_->shortcutWG->setFocus();
3181 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3183 // list of items that match lfun
3184 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3185 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3186 for (auto const & item : items) {
3187 if (isAlwaysHidden(*item)) {
3188 setItemType(item, KeyMap::System);
3190 shortcutsTW->setCurrentItem(item);
3197 void PrefShortcuts::removeShortcut()
3199 // it seems that only one item can be selected, but I am
3200 // removing all selected items anyway.
3201 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3202 for (auto & item : items) {
3203 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3204 string lfun = fromqstr(item->text(0));
3205 FuncRequest const func = lyxaction.lookupFunc(lfun);
3207 switch (itemType(*item)) {
3208 case KeyMap::System: {
3209 // for system bind, we do not touch the item
3210 // but add an user unbind item
3211 user_unbind_.bind(shortcut, func);
3212 setItemType(item, KeyMap::UserUnbind);
3213 removePB->setText(qt_("Res&tore"));
3216 case KeyMap::UserBind: {
3217 // for user_bind, we remove this bind
3218 QTreeWidgetItem * parent = item->parent();
3219 int itemIdx = parent->indexOfChild(item);
3220 parent->takeChild(itemIdx);
3222 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3224 shortcutsTW->scrollToItem(parent);
3225 user_bind_.unbind(shortcut, func);
3226 // If this user binding hid an empty system binding, unhide the
3227 // latter and select it.
3228 unhideEmpty(item->text(0), true);
3231 case KeyMap::UserUnbind: {
3232 // for user_unbind, we remove the unbind, and the item
3233 // become KeyMap::System again.
3235 seq.parse(shortcut);
3236 // Ask the user to replace current binding
3237 if (!validateNewShortcut(func, seq, QString()))
3239 user_unbind_.unbind(shortcut, func);
3240 setItemType(item, KeyMap::System);
3241 removePB->setText(qt_("Remo&ve"));
3244 case KeyMap::UserExtraUnbind: {
3245 // for user unbind that is not in system bind file,
3246 // remove this unbind file
3247 QTreeWidgetItem * parent = item->parent();
3248 parent->takeChild(parent->indexOfChild(item));
3249 user_unbind_.unbind(shortcut, func);
3256 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3258 for (auto item : items) {
3259 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3260 string lfun = fromqstr(item->text(0));
3261 FuncRequest const func = lyxaction.lookupFunc(lfun);
3263 switch (itemType(*item)) {
3264 case KeyMap::System:
3265 // for system bind, we do not touch the item
3266 // but add an user unbind item
3267 user_unbind_.bind(shortcut, func);
3268 setItemType(item, KeyMap::UserUnbind);
3271 case KeyMap::UserBind: {
3272 // for user_bind, we remove this bind
3273 QTreeWidgetItem * parent = item->parent();
3274 int itemIdx = parent->indexOfChild(item);
3275 parent->takeChild(itemIdx);
3276 user_bind_.unbind(shortcut, func);
3277 unhideEmpty(item->text(0), false);
3287 void PrefShortcuts::selectBind()
3289 QString file = form_->browsebind(internalPath(bindFileED->text()));
3290 if (!file.isEmpty()) {
3291 bindFileED->setText(file);
3292 system_bind_ = KeyMap();
3293 system_bind_.read(fromqstr(file));
3294 updateShortcutsTW();
3299 void PrefShortcuts::on_modifyPB_pressed()
3305 void PrefShortcuts::on_newPB_pressed()
3307 shortcut_->lfunLE->clear();
3308 shortcut_->shortcutWG->reset();
3309 save_lfun_ = QString();
3314 void PrefShortcuts::on_removePB_pressed()
3321 void PrefShortcuts::on_searchLE_textEdited()
3323 if (searchLE->text().isEmpty()) {
3324 // show all hidden items
3325 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3327 (*it)->setHidden(isAlwaysHidden(**it));
3328 // close all categories
3329 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3330 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3333 // search both columns
3334 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3335 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3336 matched += shortcutsTW->findItems(searchLE->text(),
3337 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3339 // hide everyone (to avoid searching in matched QList repeatedly
3340 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3342 (*it++)->setHidden(true);
3343 // show matched items
3344 for (auto & item : matched)
3345 if (!isAlwaysHidden(*item)) {
3346 item->setHidden(false);
3348 item->parent()->setExpanded(true);
3353 docstring makeCmdString(FuncRequest const & f)
3355 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3356 if (!f.argument().empty())
3357 actionStr += " " + f.argument();
3362 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3364 FuncRequest res = user_bind_.getBinding(k);
3365 if (res.action() != LFUN_UNKNOWN_ACTION)
3367 res = system_bind_.getBinding(k);
3368 // Check if it is unbound. Note: user_unbind_ can only unbind one
3369 // FuncRequest per key sequence.
3370 if (user_unbind_.getBinding(k) == res)
3371 return FuncRequest::unknown;
3376 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3377 KeySequence const & k,
3378 QString const & lfun_to_modify)
3380 if (func.action() == LFUN_UNKNOWN_ACTION) {
3381 Alert::error(_("Failed to create shortcut"),
3382 _("Unknown or invalid LyX function"));
3386 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3387 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3388 // and how it is used in GuiPrefs::shortcutOkPressed.
3389 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3390 Alert::error(_("Failed to create shortcut"),
3391 _("This LyX function is hidden and cannot be bound."));
3395 if (k.length() == 0) {
3396 Alert::error(_("Failed to create shortcut"),
3397 _("Invalid or empty key sequence"));
3401 FuncRequest oldBinding = currentBinding(k);
3402 if (oldBinding == func)
3403 // nothing to change
3406 // make sure this key isn't already bound---and, if so, prompt user
3407 // (exclude the lfun the user already wants to modify)
3408 docstring const action_string = makeCmdString(oldBinding);
3409 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3410 && lfun_to_modify != toqstr(action_string)) {
3411 docstring const new_action_string = makeCmdString(func);
3412 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3414 "Are you sure you want to unbind the "
3415 "current shortcut and bind it to %3$s?"),
3416 k.print(KeySequence::ForGui), action_string,
3418 int ret = Alert::prompt(_("Redefine shortcut?"),
3419 text, 0, 1, _("&Redefine"), _("&Cancel"));
3422 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3423 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3424 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3425 deactivateShortcuts(items);
3431 void PrefShortcuts::shortcutOkPressed()
3433 QString const new_lfun = shortcut_->lfunLE->text();
3434 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3435 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3437 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3438 // "modify", or is empty if they clicked "new" (which I do not really like)
3439 if (!validateNewShortcut(func, k, save_lfun_))
3442 if (!save_lfun_.isEmpty()) {
3443 // real modification of the lfun's shortcut,
3444 // so remove the previous one
3445 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3446 deactivateShortcuts(to_modify);
3449 shortcut_->accept();
3451 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3453 user_bind_.bind(&k, func);
3454 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3456 item->parent()->setExpanded(true);
3457 shortcutsTW->setCurrentItem(item);
3458 shortcutsTW->scrollToItem(item);
3460 Alert::error(_("Failed to create shortcut"),
3461 _("Can not insert shortcut to the list"));
3467 void PrefShortcuts::shortcutCancelPressed()
3469 shortcut_->shortcutWG->reset();
3473 void PrefShortcuts::shortcutClearPressed()
3475 shortcut_->shortcutWG->reset();
3479 void PrefShortcuts::shortcutRemovePressed()
3481 shortcut_->shortcutWG->removeFromSequence();
3485 /////////////////////////////////////////////////////////////////////
3489 /////////////////////////////////////////////////////////////////////
3491 PrefIdentity::PrefIdentity(GuiPreferences * form)
3492 : PrefModule(QString(), N_("Identity"), form)
3496 connect(nameED, SIGNAL(textChanged(QString)),
3497 this, SIGNAL(changed()));
3498 connect(emailED, SIGNAL(textChanged(QString)),
3499 this, SIGNAL(changed()));
3500 connect(initialsED, SIGNAL(textChanged(QString)),
3501 this, SIGNAL(changed()));
3503 nameED->setValidator(new NoNewLineValidator(nameED));
3504 emailED->setValidator(new NoNewLineValidator(emailED));
3505 initialsED->setValidator(new NoNewLineValidator(initialsED));
3509 void PrefIdentity::applyRC(LyXRC & rc) const
3511 rc.user_name = fromqstr(nameED->text());
3512 rc.user_email = fromqstr(emailED->text());
3513 rc.user_initials = fromqstr(initialsED->text());
3517 void PrefIdentity::updateRC(LyXRC const & rc)
3519 nameED->setText(toqstr(rc.user_name));
3520 emailED->setText(toqstr(rc.user_email));
3521 initialsED->setText(toqstr(rc.user_initials));
3526 /////////////////////////////////////////////////////////////////////
3530 /////////////////////////////////////////////////////////////////////
3532 GuiPreferences::GuiPreferences(GuiView & lv)
3533 : GuiDialog(lv, "prefs", qt_("Preferences"))
3537 QDialog::setModal(false);
3539 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3540 this, SLOT(slotButtonBox(QAbstractButton *)));
3542 addModule(new PrefUserInterface(this));
3543 addModule(new PrefDocHandling(this));
3544 addModule(new PrefEdit(this));
3545 addModule(new PrefShortcuts(this));
3546 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3547 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3548 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3549 addModule(screenfonts);
3550 addModule(new PrefColors(this));
3551 addModule(new PrefDisplay(this));
3552 addModule(new PrefInput(this));
3553 addModule(new PrefCompletion(this));
3555 addModule(new PrefPaths(this));
3557 addModule(new PrefIdentity(this));
3559 addModule(new PrefLanguage(this));
3560 addModule(new PrefSpellchecker(this));
3562 PrefOutput * output = new PrefOutput(this);
3564 addModule(new PrefLatex(this));
3566 PrefConverters * converters = new PrefConverters(this);
3567 PrefFileformats * formats = new PrefFileformats(this);
3568 connect(formats, SIGNAL(formatsChanged()),
3569 converters, SLOT(updateGui()));
3570 addModule(converters);
3573 prefsPS->setCurrentPanel("User Interface");
3574 // FIXME: hack to work around resizing bug in Qt >= 4.2
3575 // bug verified with Qt 4.2.{0-3} (JSpitzm)
3576 #if QT_VERSION >= 0x040200
3577 prefsPS->updateGeometry();
3580 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3581 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3582 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3583 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3584 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3586 guilyxfiles_ = new GuiLyXFiles(lv);
3587 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3588 this, SLOT(slotFileSelected(QString)));
3592 void GuiPreferences::addModule(PrefModule * module)
3594 LASSERT(module, return);
3595 if (module->category().isEmpty())
3596 prefsPS->addPanel(module, module->title());
3598 prefsPS->addPanel(module, module->title(), module->category());
3599 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3600 modules_.push_back(module);
3604 void GuiPreferences::change_adaptor()
3610 void GuiPreferences::applyRC(LyXRC & rc) const
3612 size_t end = modules_.size();
3613 for (size_t i = 0; i != end; ++i)
3614 modules_[i]->applyRC(rc);
3618 void GuiPreferences::updateRC(LyXRC const & rc)
3620 size_t const end = modules_.size();
3621 for (size_t i = 0; i != end; ++i)
3622 modules_[i]->updateRC(rc);
3626 void GuiPreferences::applyView()
3632 bool GuiPreferences::initialiseParams(string const &)
3635 formats_ = theFormats();
3636 converters_ = theConverters();
3637 converters_.update(formats_);
3638 movers_ = theMovers();
3642 // Make sure that the bc is in the INITIAL state
3643 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3650 void GuiPreferences::dispatchParams()
3653 rc_.write(ss, true);
3654 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3655 // issue prefsApplied signal. This will update the
3656 // localized screen font sizes.
3658 // FIXME: these need lfuns
3660 Author const & author =
3661 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3662 from_utf8(rc_.user_initials));
3663 theBufferList().recordCurrentAuthor(author);
3665 theFormats() = formats_;
3667 theConverters() = converters_;
3668 theConverters().update(formats_);
3669 theConverters().buildGraph();
3670 theBufferList().invalidateConverterCache();
3672 theMovers() = movers_;
3674 for (string const & color : colors_)
3675 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3679 if (!tempSaveCB->isChecked())
3680 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3684 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3686 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3690 void GuiPreferences::slotFileSelected(QString const file)
3696 QString GuiPreferences::browseLibFile(QString const & dir,
3697 QString const & name, QString const & ext)
3701 guilyxfiles_->passParams(fromqstr(dir));
3702 guilyxfiles_->selectItem(name);
3703 guilyxfiles_->exec();
3705 QString const result = uifile_;
3707 // remove the extension if it is the default one
3708 QString noextresult;
3709 if (getExtension(result) == ext)
3710 noextresult = removeExtension(result);
3712 noextresult = result;
3714 // remove the directory, if it is the default one
3715 QString const file = onlyFileName(noextresult);
3716 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3723 QString GuiPreferences::browsebind(QString const & file)
3725 return browseLibFile("bind", file, "bind");
3729 QString GuiPreferences::browseUI(QString const & file)
3731 return browseLibFile("ui", file, "ui");
3735 QString GuiPreferences::browsekbmap(QString const & file)
3737 return browseLibFile("kbd", file, "kmap");
3741 QString GuiPreferences::browse(QString const & file,
3742 QString const & title) const
3744 return browseFile(file, title, QStringList(), true);
3748 } // namespace frontend
3751 #include "moc_GuiPrefs.cpp"