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 QFontDatabase fontdb;
935 QStringList families(fontdb.families());
936 for (auto const & family : families) {
937 screenRomanCO->addItem(family);
938 screenSansCO->addItem(family);
939 screenTypewriterCO->addItem(family);
941 #if QT_VERSION < 0x050e00
942 connect(screenRomanCO, SIGNAL(activated(QString)),
943 this, SIGNAL(changed()));
944 connect(screenSansCO, SIGNAL(activated(QString)),
945 this, SIGNAL(changed()));
946 connect(screenTypewriterCO, SIGNAL(activated(QString)),
947 this, SIGNAL(changed()));
949 connect(screenRomanCO, SIGNAL(textActivated(QString)),
950 this, SIGNAL(changed()));
951 connect(screenSansCO, SIGNAL(textActivated(QString)),
952 this, SIGNAL(changed()));
953 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
954 this, SIGNAL(changed()));
956 connect(screenZoomSB, SIGNAL(valueChanged(int)),
957 this, SIGNAL(changed()));
958 connect(screenTinyED, SIGNAL(textChanged(QString)),
959 this, SIGNAL(changed()));
960 connect(screenSmallestED, SIGNAL(textChanged(QString)),
961 this, SIGNAL(changed()));
962 connect(screenSmallerED, SIGNAL(textChanged(QString)),
963 this, SIGNAL(changed()));
964 connect(screenSmallED, SIGNAL(textChanged(QString)),
965 this, SIGNAL(changed()));
966 connect(screenNormalED, SIGNAL(textChanged(QString)),
967 this, SIGNAL(changed()));
968 connect(screenLargeED, SIGNAL(textChanged(QString)),
969 this, SIGNAL(changed()));
970 connect(screenLargerED, SIGNAL(textChanged(QString)),
971 this, SIGNAL(changed()));
972 connect(screenLargestED, SIGNAL(textChanged(QString)),
973 this, SIGNAL(changed()));
974 connect(screenHugeED, SIGNAL(textChanged(QString)),
975 this, SIGNAL(changed()));
976 connect(screenHugerED, SIGNAL(textChanged(QString)),
977 this, SIGNAL(changed()));
979 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
980 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
981 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
982 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
983 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
984 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
985 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
986 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
987 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
988 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
992 void PrefScreenFonts::applyRC(LyXRC & rc) const
994 LyXRC const oldrc = rc;
996 parseFontName(screenRomanCO->currentText(),
997 rc.roman_font_name, rc.roman_font_foundry);
998 parseFontName(screenSansCO->currentText(),
999 rc.sans_font_name, rc.sans_font_foundry);
1000 parseFontName(screenTypewriterCO->currentText(),
1001 rc.typewriter_font_name, rc.typewriter_font_foundry);
1003 rc.defaultZoom = screenZoomSB->value();
1004 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
1005 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
1006 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
1007 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
1008 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
1009 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
1010 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
1011 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
1012 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
1013 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
1017 void PrefScreenFonts::updateRC(LyXRC const & rc)
1019 setComboxFont(screenRomanCO, rc.roman_font_name,
1020 rc.roman_font_foundry);
1021 setComboxFont(screenSansCO, rc.sans_font_name,
1022 rc.sans_font_foundry);
1023 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1024 rc.typewriter_font_foundry);
1026 selectRoman(screenRomanCO->currentText());
1027 selectSans(screenSansCO->currentText());
1028 selectTypewriter(screenTypewriterCO->currentText());
1030 screenZoomSB->setValue(rc.defaultZoom);
1031 updateScreenFontSizes(rc);
1035 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1037 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1038 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1039 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1040 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1041 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1042 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1043 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1044 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1045 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1046 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1050 void PrefScreenFonts::selectRoman(const QString & name)
1052 screenRomanFE->set(QFont(name), name);
1056 void PrefScreenFonts::selectSans(const QString & name)
1058 screenSansFE->set(QFont(name), name);
1062 void PrefScreenFonts::selectTypewriter(const QString & name)
1064 screenTypewriterFE->set(QFont(name), name);
1068 /////////////////////////////////////////////////////////////////////
1072 /////////////////////////////////////////////////////////////////////
1075 PrefColors::PrefColors(GuiPreferences * form)
1076 : PrefModule(catLookAndFeel, N_("Colors"), form)
1080 // FIXME: all of this initialization should be put into the controller.
1081 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1082 // for some discussion of why that is not trivial.
1083 QPixmap icon(32, 32);
1084 for (int i = 0; i < Color_ignore; ++i) {
1085 ColorCode lc = static_cast<ColorCode>(i);
1086 if (lc == Color_none
1087 || lc == Color_black
1088 || lc == Color_white
1090 || lc == Color_brown
1092 || lc == Color_darkgray
1094 || lc == Color_green
1095 || lc == Color_lightgray
1097 || lc == Color_magenta
1098 || lc == Color_olive
1099 || lc == Color_orange
1101 || lc == Color_purple
1104 || lc == Color_violet
1105 || lc == Color_yellow
1106 || lc == Color_inherit
1107 || lc == Color_ignore)
1109 lcolors_.push_back(lc);
1111 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1112 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1113 vector<ColorCode>::const_iterator const end = lcolors_.end();
1114 for (; cit != end; ++cit) {
1115 (void) new QListWidgetItem(QIcon(icon),
1116 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1118 curcolors_.resize(lcolors_.size());
1119 newcolors_.resize(lcolors_.size());
1120 // End initialization
1122 connect(colorChangePB, SIGNAL(clicked()),
1123 this, SLOT(changeColor()));
1124 connect(colorResetPB, SIGNAL(clicked()),
1125 this, SLOT(resetColor()));
1126 connect(colorResetAllPB, SIGNAL(clicked()),
1127 this, SLOT(resetAllColor()));
1128 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1129 this, SLOT(changeLyxObjectsSelection()));
1130 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1131 this, SLOT(changeColor()));
1132 connect(syscolorsCB, SIGNAL(toggled(bool)),
1133 this, SIGNAL(changed()));
1134 connect(syscolorsCB, SIGNAL(toggled(bool)),
1135 this, SLOT(changeSysColor()));
1139 void PrefColors::applyRC(LyXRC & rc) const
1143 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1144 if (curcolors_[i] != newcolors_[i])
1145 form_->setColor(lcolors_[i], newcolors_[i]);
1146 rc.use_system_colors = syscolorsCB->isChecked();
1148 if (oldrc.use_system_colors != rc.use_system_colors)
1149 guiApp->colorCache().clear();
1153 void PrefColors::updateRC(LyXRC const & rc)
1155 for (size_type i = 0; i < lcolors_.size(); ++i) {
1156 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1157 QPixmap coloritem(32, 32);
1158 coloritem.fill(color);
1159 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1160 newcolors_[i] = curcolors_[i] = color.name();
1162 syscolorsCB->setChecked(rc.use_system_colors);
1163 changeLyxObjectsSelection();
1165 setDisabledResets();
1169 void PrefColors::changeColor()
1171 int const row = lyxObjectsLW->currentRow();
1177 QString const color = newcolors_[size_t(row)];
1178 QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1180 if (setColor(row, c, color)) {
1181 setDisabledResets();
1188 void PrefColors::resetColor()
1190 int const row = lyxObjectsLW->currentRow();
1196 QString const color = newcolors_[size_t(row)];
1197 QColor const c = getDefaultColorByRow(row);
1199 if (setColor(row, c, color)) {
1200 setDisabledResets();
1207 void PrefColors::resetAllColor()
1209 bool isChanged = false;
1211 colorResetAllPB->setDisabled(true);
1213 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1214 QString const color = newcolors_[size_t(irow)];
1215 QColor const c = getDefaultColorByRow(irow);
1217 if (setColor(irow, c, color))
1222 setDisabledResets();
1229 bool PrefColors::setColor(int const row, QColor const & new_color,
1230 QString const & old_color)
1232 if (new_color.isValid() && new_color.name() != old_color) {
1233 newcolors_[size_t(row)] = new_color.name();
1234 QPixmap coloritem(32, 32);
1235 coloritem.fill(new_color);
1236 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1243 void PrefColors::setDisabledResets()
1245 int const row = lyxObjectsLW->currentRow();
1246 // set disable reset buttons ...
1248 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1250 colorResetAllPB->setDisabled(true);
1252 // ... in between process qt events to give quicker visual feedback to the user ...
1253 guiApp->processEvents();
1255 // ... set disable Reset All button
1256 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1257 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1258 colorResetAllPB->setDisabled(false);
1259 // the break condition might hide performance issues
1260 // if a non-default color is at the top of the list
1267 bool PrefColors::isDefaultColor(int const row, QString const & color)
1269 return color == getDefaultColorByRow(row).name();
1273 QColor PrefColors::getDefaultColorByRow(int const row)
1275 ColorSet const defaultcolor;
1276 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1277 guiApp->colorCache().isDarkMode()).c_str();
1281 void PrefColors::changeSysColor()
1283 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1284 // skip colors that are taken from system palette
1285 bool const disable = syscolorsCB->isChecked()
1286 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1288 QListWidgetItem * const item = lyxObjectsLW->item(row);
1289 Qt::ItemFlags const flags = item->flags();
1292 item->setFlags(flags & ~Qt::ItemIsEnabled);
1294 item->setFlags(flags | Qt::ItemIsEnabled);
1299 void PrefColors::changeLyxObjectsSelection()
1301 int currentRow = lyxObjectsLW->currentRow();
1302 colorChangePB->setDisabled(currentRow < 0);
1305 colorResetPB->setDisabled(true);
1307 colorResetPB->setDisabled(
1308 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1312 /////////////////////////////////////////////////////////////////////
1316 /////////////////////////////////////////////////////////////////////
1318 PrefDisplay::PrefDisplay(GuiPreferences * form)
1319 : PrefModule(catLookAndFeel, N_("Display"), form)
1322 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1323 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1324 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1325 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1326 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1327 connect(ctUseBackingstoreCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1331 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1333 previewSizeSB->setEnabled(index != 0);
1337 void PrefDisplay::applyRC(LyXRC & rc) const
1339 switch (instantPreviewCO->currentIndex()) {
1341 rc.preview = LyXRC::PREVIEW_OFF;
1344 rc.preview = LyXRC::PREVIEW_NO_MATH;
1347 rc.preview = LyXRC::PREVIEW_ON;
1351 rc.display_graphics = displayGraphicsCB->isChecked();
1352 rc.preview_scale_factor = previewSizeSB->value();
1353 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1354 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1355 rc.draw_strategy = ctUseBackingstoreCB->isChecked()
1356 ? LyXRC::DS_BACKINGSTORE : LyXRC::DS_PARTIAL;
1358 // FIXME!! The graphics cache no longer has a changeDisplay method.
1360 if (old_value != rc.display_graphics) {
1361 graphics::GCache & gc = graphics::GCache::get();
1368 void PrefDisplay::updateRC(LyXRC const & rc)
1370 switch (rc.preview) {
1371 case LyXRC::PREVIEW_OFF:
1372 instantPreviewCO->setCurrentIndex(0);
1374 case LyXRC::PREVIEW_NO_MATH :
1375 instantPreviewCO->setCurrentIndex(1);
1377 case LyXRC::PREVIEW_ON :
1378 instantPreviewCO->setCurrentIndex(2);
1382 displayGraphicsCB->setChecked(rc.display_graphics);
1383 previewSizeSB->setValue(rc.preview_scale_factor);
1384 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1385 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1386 ctUseBackingstoreCB->setChecked(rc.draw_strategy == LyXRC::DS_BACKINGSTORE);
1387 ctUseBackingstoreCB->setHidden(guiApp->needsBackingStore());
1388 previewSizeSB->setEnabled(
1390 && rc.preview != LyXRC::PREVIEW_OFF);
1394 /////////////////////////////////////////////////////////////////////
1398 /////////////////////////////////////////////////////////////////////
1400 PrefPaths::PrefPaths(GuiPreferences * form)
1401 : PrefModule(QString(), N_("Paths"), form)
1405 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1406 connect(workingDirED, SIGNAL(textChanged(QString)),
1407 this, SIGNAL(changed()));
1409 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1410 connect(templateDirED, SIGNAL(textChanged(QString)),
1411 this, SIGNAL(changed()));
1413 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1414 connect(exampleDirED, SIGNAL(textChanged(QString)),
1415 this, SIGNAL(changed()));
1417 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1418 connect(backupDirED, SIGNAL(textChanged(QString)),
1419 this, SIGNAL(changed()));
1421 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1422 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1423 this, SIGNAL(changed()));
1425 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1426 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1427 this, SIGNAL(changed()));
1429 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1430 connect(tempDirED, SIGNAL(textChanged(QString)),
1431 this, SIGNAL(changed()));
1433 #if defined(USE_HUNSPELL)
1434 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1435 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1436 this, SIGNAL(changed()));
1438 hunspellDirPB->setEnabled(false);
1439 hunspellDirED->setEnabled(false);
1442 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1443 this, SIGNAL(changed()));
1445 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1446 this, SIGNAL(changed()));
1448 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1449 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1453 void PrefPaths::applyRC(LyXRC & rc) const
1455 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1456 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1457 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1458 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1459 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1460 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1461 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1462 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1463 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1464 // FIXME: should be a checkbox only
1465 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1469 void PrefPaths::updateRC(LyXRC const & rc)
1471 workingDirED->setText(toqstr(external_path(rc.document_path)));
1472 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1473 templateDirED->setText(toqstr(external_path(rc.template_path)));
1474 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1475 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1476 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1477 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1478 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1479 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1480 // FIXME: should be a checkbox only
1481 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1485 void PrefPaths::selectExampledir()
1487 QString file = browseDir(internalPath(exampleDirED->text()),
1488 qt_("Select directory for example files"));
1489 if (!file.isEmpty())
1490 exampleDirED->setText(file);
1494 void PrefPaths::selectTemplatedir()
1496 QString file = browseDir(internalPath(templateDirED->text()),
1497 qt_("Select a document templates directory"));
1498 if (!file.isEmpty())
1499 templateDirED->setText(file);
1503 void PrefPaths::selectTempdir()
1505 QString file = browseDir(internalPath(tempDirED->text()),
1506 qt_("Select a temporary directory"));
1507 if (!file.isEmpty())
1508 tempDirED->setText(file);
1512 void PrefPaths::selectBackupdir()
1514 QString file = browseDir(internalPath(backupDirED->text()),
1515 qt_("Select a backups directory"));
1516 if (!file.isEmpty())
1517 backupDirED->setText(file);
1521 void PrefPaths::selectWorkingdir()
1523 QString file = browseDir(internalPath(workingDirED->text()),
1524 qt_("Select a document directory"));
1525 if (!file.isEmpty())
1526 workingDirED->setText(file);
1530 void PrefPaths::selectThesaurusdir()
1532 QString file = browseDir(internalPath(thesaurusDirED->text()),
1533 qt_("Set the path to the thesaurus dictionaries"));
1534 if (!file.isEmpty())
1535 thesaurusDirED->setText(file);
1539 void PrefPaths::selectHunspelldir()
1541 QString file = browseDir(internalPath(hunspellDirED->text()),
1542 qt_("Set the path to the Hunspell dictionaries"));
1543 if (!file.isEmpty())
1544 hunspellDirED->setText(file);
1548 void PrefPaths::selectLyxPipe()
1550 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1551 qt_("Give a filename for the LyX server pipe"));
1552 if (!file.isEmpty())
1553 lyxserverDirED->setText(file);
1557 /////////////////////////////////////////////////////////////////////
1561 /////////////////////////////////////////////////////////////////////
1563 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1564 : PrefModule(catLanguage, N_("Spellchecker"), form)
1568 // FIXME: this check should test the target platform (darwin)
1569 #if defined(USE_MACOSX_PACKAGING)
1570 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1571 #define CONNECT_APPLESPELL
1573 #undef CONNECT_APPLESPELL
1575 #if defined(USE_ASPELL)
1576 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1578 #if defined(USE_ENCHANT)
1579 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1581 #if defined(USE_HUNSPELL)
1582 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1585 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1586 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1587 this, SIGNAL(changed()));
1588 connect(altLanguageED, SIGNAL(textChanged(QString)),
1589 this, SIGNAL(changed()));
1590 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1591 this, SIGNAL(changed()));
1592 connect(compoundWordCB, SIGNAL(clicked()),
1593 this, SIGNAL(changed()));
1594 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1595 this, SIGNAL(changed()));
1596 connect(spellcheckNotesCB, SIGNAL(clicked()),
1597 this, SIGNAL(changed()));
1599 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1600 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1602 spellcheckerCB->setEnabled(false);
1603 altLanguageED->setEnabled(false);
1604 escapeCharactersED->setEnabled(false);
1605 compoundWordCB->setEnabled(false);
1606 spellcheckContinuouslyCB->setEnabled(false);
1607 spellcheckNotesCB->setEnabled(false);
1612 void PrefSpellchecker::applyRC(LyXRC & rc) const
1614 string const speller = fromqstr(spellcheckerCB->
1615 itemData(spellcheckerCB->currentIndex()).toString());
1616 if (!speller.empty())
1617 rc.spellchecker = speller;
1618 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1619 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1620 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1621 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1622 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1626 void PrefSpellchecker::updateRC(LyXRC const & rc)
1628 spellcheckerCB->setCurrentIndex(
1629 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1630 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1631 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1632 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1633 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1634 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1638 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1640 QString spellchecker = spellcheckerCB->itemData(index).toString();
1642 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1647 /////////////////////////////////////////////////////////////////////
1651 /////////////////////////////////////////////////////////////////////
1654 PrefConverters::PrefConverters(GuiPreferences * form)
1655 : PrefModule(catFiles, N_("Converters"), form)
1659 connect(converterNewPB, SIGNAL(clicked()),
1660 this, SLOT(updateConverter()));
1661 connect(converterRemovePB, SIGNAL(clicked()),
1662 this, SLOT(removeConverter()));
1663 connect(converterModifyPB, SIGNAL(clicked()),
1664 this, SLOT(updateConverter()));
1665 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1666 this, SLOT(switchConverter()));
1667 #if QT_VERSION < 0x050e00
1668 connect(converterFromCO, SIGNAL(activated(QString)),
1669 this, SLOT(changeConverter()));
1670 connect(converterToCO, SIGNAL(activated(QString)),
1671 this, SLOT(changeConverter()));
1673 connect(converterFromCO, SIGNAL(textActivated(QString)),
1674 this, SLOT(changeConverter()));
1675 connect(converterToCO, SIGNAL(textActivated(QString)),
1676 this, SLOT(changeConverter()));
1678 connect(converterED, SIGNAL(textEdited(QString)),
1679 this, SLOT(changeConverter()));
1680 connect(converterFlagED, SIGNAL(textEdited(QString)),
1681 this, SLOT(changeConverter()));
1682 connect(converterNewPB, SIGNAL(clicked()),
1683 this, SIGNAL(changed()));
1684 connect(converterRemovePB, SIGNAL(clicked()),
1685 this, SIGNAL(changed()));
1686 connect(converterModifyPB, SIGNAL(clicked()),
1687 this, SIGNAL(changed()));
1688 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1689 this, SIGNAL(changed()));
1690 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1691 this, SIGNAL(changed()));
1693 converterED->setValidator(new NoNewLineValidator(converterED));
1694 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1695 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1696 //converterDefGB->setFocusProxy(convertersLW);
1700 void PrefConverters::applyRC(LyXRC & rc) const
1702 rc.use_converter_cache = cacheCB->isChecked();
1703 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1704 rc.use_converter_needauth = needauthCB->isChecked();
1705 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1709 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1710 cb->blockSignals(true);
1711 cb->setChecked(checked);
1712 cb->blockSignals(false);
1716 void PrefConverters::updateRC(LyXRC const & rc)
1718 cacheCB->setChecked(rc.use_converter_cache);
1719 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1720 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1722 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1727 void PrefConverters::updateGui()
1729 QString const pattern("%1 -> %2");
1730 form_->formats().sort();
1731 form_->converters().update(form_->formats());
1732 // save current selection
1735 .arg(converterFromCO->currentText())
1736 .arg(converterToCO->currentText());
1738 converterFromCO->clear();
1739 converterToCO->clear();
1741 for (Format const & f : form_->formats()) {
1742 QString const name = toqstr(translateIfPossible(f.prettyname()));
1743 converterFromCO->addItem(name);
1744 converterToCO->addItem(name);
1747 // currentRowChanged(int) is also triggered when updating the listwidget
1748 // block signals to avoid unnecessary calls to switchConverter()
1749 convertersLW->blockSignals(true);
1750 convertersLW->clear();
1752 for (Converter const & c : form_->converters()) {
1753 QString const name =
1755 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1756 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1757 int type = form_->converters().getNumber(c.From()->name(),
1759 new QListWidgetItem(name, convertersLW, type);
1761 convertersLW->sortItems(Qt::AscendingOrder);
1762 convertersLW->blockSignals(false);
1764 // restore selection
1765 if (current != pattern.arg(QString()).arg(QString())) {
1766 QList<QListWidgetItem *> const item =
1767 convertersLW->findItems(current, Qt::MatchExactly);
1768 if (!item.isEmpty())
1769 convertersLW->setCurrentItem(item.at(0));
1772 // select first element if restoring failed
1773 if (convertersLW->currentRow() == -1)
1774 convertersLW->setCurrentRow(0);
1780 void PrefConverters::switchConverter()
1782 int const cnr = convertersLW->currentItem()->type();
1783 Converter const & c(form_->converters().get(cnr));
1784 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1785 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1786 converterED->setText(toqstr(c.command()));
1787 converterFlagED->setText(toqstr(c.flags()));
1793 void PrefConverters::changeConverter()
1799 void PrefConverters::updateButtons()
1801 if (form_->formats().empty())
1803 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1804 Format const & to = form_->formats().get(converterToCO->currentIndex());
1805 int const sel = form_->converters().getNumber(from.name(), to.name());
1806 bool const known = sel >= 0;
1807 bool const valid = !(converterED->text().isEmpty()
1808 || from.name() == to.name());
1813 if (convertersLW->count() > 0) {
1814 int const cnr = convertersLW->currentItem()->type();
1815 Converter const & c = form_->converters().get(cnr);
1816 old_command = c.command();
1817 old_flag = c.flags();
1820 string const new_command = fromqstr(converterED->text());
1821 string const new_flag = fromqstr(converterFlagED->text());
1823 bool modified = (old_command != new_command || old_flag != new_flag);
1825 converterModifyPB->setEnabled(valid && known && modified);
1826 converterNewPB->setEnabled(valid && !known);
1827 converterRemovePB->setEnabled(known);
1829 maxAgeLE->setEnabled(cacheCB->isChecked());
1830 maxAgeLA->setEnabled(cacheCB->isChecked());
1835 // specify unique from/to or it doesn't appear. This is really bad UI
1836 // this is why we can use the same function for both new and modify
1837 void PrefConverters::updateConverter()
1839 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1840 Format const & to = form_->formats().get(converterToCO->currentIndex());
1841 string const flags = fromqstr(converterFlagED->text());
1842 string const command = fromqstr(converterED->text());
1844 Converter const * old =
1845 form_->converters().getConverter(from.name(), to.name());
1846 form_->converters().add(from.name(), to.name(), command, flags);
1849 form_->converters().updateLast(form_->formats());
1853 // Remove all files created by this converter from the cache, since
1854 // the modified converter might create different files.
1855 ConverterCache::get().remove_all(from.name(), to.name());
1859 void PrefConverters::removeConverter()
1861 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1862 Format const & to = form_->formats().get(converterToCO->currentIndex());
1863 form_->converters().erase(from.name(), to.name());
1867 // Remove all files created by this converter from the cache, since
1868 // a possible new converter might create different files.
1869 ConverterCache::get().remove_all(from.name(), to.name());
1873 void PrefConverters::on_cacheCB_stateChanged(int state)
1875 maxAgeLE->setEnabled(state == Qt::Checked);
1876 maxAgeLA->setEnabled(state == Qt::Checked);
1881 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1883 needauthCB->setEnabled(!checked);
1887 void PrefConverters::on_needauthCB_toggled(bool checked)
1894 int ret = frontend::Alert::prompt(
1895 _("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!"),
1896 0, 0, _("&No"), _("&Yes"));
1900 setCheckboxBlockSignals(needauthCB, true);
1904 /////////////////////////////////////////////////////////////////////
1908 /////////////////////////////////////////////////////////////////////
1910 class FormatValidator : public QValidator
1913 FormatValidator(QWidget *, Formats const & f);
1914 void fixup(QString & input) const override;
1915 QValidator::State validate(QString & input, int & pos) const override;
1917 virtual QString toString(Format const & format) const = 0;
1919 Formats const & formats_;
1923 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1924 : QValidator(parent), formats_(f)
1929 void FormatValidator::fixup(QString & input) const
1931 Formats::const_iterator cit = formats_.begin();
1932 Formats::const_iterator end = formats_.end();
1933 for (; cit != end; ++cit) {
1934 QString const name = toString(*cit);
1935 if (distance(formats_.begin(), cit) == nr()) {
1943 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1945 Formats::const_iterator cit = formats_.begin();
1946 Formats::const_iterator end = formats_.end();
1947 bool unknown = true;
1948 for (; unknown && cit != end; ++cit) {
1949 QString const name = toString(*cit);
1950 if (distance(formats_.begin(), cit) != nr())
1951 unknown = name != input;
1954 if (unknown && !input.isEmpty())
1955 return QValidator::Acceptable;
1957 return QValidator::Intermediate;
1961 int FormatValidator::nr() const
1963 QComboBox * p = qobject_cast<QComboBox *>(parent());
1964 return p->itemData(p->currentIndex()).toInt();
1968 /////////////////////////////////////////////////////////////////////
1970 // FormatNameValidator
1972 /////////////////////////////////////////////////////////////////////
1974 class FormatNameValidator : public FormatValidator
1977 FormatNameValidator(QWidget * parent, Formats const & f)
1978 : FormatValidator(parent, f)
1981 QString toString(Format const & format) const override
1983 return toqstr(format.name());
1988 /////////////////////////////////////////////////////////////////////
1990 // FormatPrettynameValidator
1992 /////////////////////////////////////////////////////////////////////
1994 class FormatPrettynameValidator : public FormatValidator
1997 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1998 : FormatValidator(parent, f)
2001 QString toString(Format const & format) const override
2003 return toqstr(translateIfPossible(format.prettyname()));
2008 /////////////////////////////////////////////////////////////////////
2012 /////////////////////////////////////////////////////////////////////
2014 PrefFileformats::PrefFileformats(GuiPreferences * form)
2015 : PrefModule(catFiles, N_("File Formats"), form)
2019 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2020 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2021 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2022 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2023 editorED->setValidator(new NoNewLineValidator(editorED));
2024 viewerED->setValidator(new NoNewLineValidator(viewerED));
2025 copierED->setValidator(new NoNewLineValidator(copierED));
2027 connect(documentCB, SIGNAL(clicked()),
2028 this, SLOT(setFlags()));
2029 connect(vectorCB, SIGNAL(clicked()),
2030 this, SLOT(setFlags()));
2031 connect(exportMenuCB, SIGNAL(clicked()),
2032 this, SLOT(setFlags()));
2033 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2034 this, SLOT(updatePrettyname()));
2035 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2036 this, SIGNAL(changed()));
2037 #if QT_VERSION < 0x050e00
2038 connect(defaultFormatCB, SIGNAL(activated(QString)),
2039 this, SIGNAL(changed()));
2040 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2041 this, SIGNAL(changed()));
2042 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2043 this, SIGNAL(changed()));
2045 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2046 this, SIGNAL(changed()));
2047 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2048 this, SIGNAL(changed()));
2049 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2050 this, SIGNAL(changed()));
2052 connect(viewerCO, SIGNAL(activated(int)),
2053 this, SIGNAL(changed()));
2054 connect(editorCO, SIGNAL(activated(int)),
2055 this, SIGNAL(changed()));
2061 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2063 if (shortcut.empty())
2066 string l10n_format =
2067 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2068 return split(l10n_format, '|');
2074 void PrefFileformats::applyRC(LyXRC & rc) const
2076 QString const default_format = defaultFormatCB->itemData(
2077 defaultFormatCB->currentIndex()).toString();
2078 rc.default_view_format = fromqstr(default_format);
2079 QString const default_otf_format = defaultOTFFormatCB->itemData(
2080 defaultOTFFormatCB->currentIndex()).toString();
2081 rc.default_otf_view_format = fromqstr(default_otf_format);
2082 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2083 defaultPlatexFormatCB->currentIndex()).toString();
2084 rc.default_platex_view_format = fromqstr(default_platex_format);
2088 void PrefFileformats::updateRC(LyXRC const & rc)
2090 viewer_alternatives = rc.viewer_alternatives;
2091 editor_alternatives = rc.editor_alternatives;
2092 bool const init = defaultFormatCB->currentText().isEmpty();
2096 defaultFormatCB->findData(toqstr(rc.default_view_format));
2097 defaultFormatCB->setCurrentIndex(pos);
2098 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2099 defaultOTFFormatCB->setCurrentIndex(pos);
2100 defaultOTFFormatCB->setCurrentIndex(pos);
2101 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2102 defaultPlatexFormatCB->setCurrentIndex(pos);
2103 defaultPlatexFormatCB->setCurrentIndex(pos);
2108 void PrefFileformats::updateView()
2110 QString const current = formatsCB->currentText();
2111 QString const current_def = defaultFormatCB->currentText();
2112 QString const current_def_otf = defaultOTFFormatCB->currentText();
2113 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2115 // update comboboxes with formats
2116 formatsCB->blockSignals(true);
2117 defaultFormatCB->blockSignals(true);
2118 defaultOTFFormatCB->blockSignals(true);
2119 defaultPlatexFormatCB->blockSignals(true);
2121 defaultFormatCB->clear();
2122 defaultOTFFormatCB->clear();
2123 defaultPlatexFormatCB->clear();
2124 form_->formats().sort();
2125 for (Format const & f : form_->formats()) {
2126 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2127 formatsCB->addItem(prettyname,
2128 QVariant(form_->formats().getNumber(f.name())));
2129 if (f.viewer().empty())
2131 if (form_->converters().isReachable("xhtml", f.name())
2132 || form_->converters().isReachable("dviluatex", f.name())
2133 || form_->converters().isReachable("luatex", f.name())
2134 || form_->converters().isReachable("xetex", f.name())) {
2135 defaultFormatCB->addItem(prettyname,
2136 QVariant(toqstr(f.name())));
2137 defaultOTFFormatCB->addItem(prettyname,
2138 QVariant(toqstr(f.name())));
2140 if (form_->converters().isReachable("latex", f.name())
2141 || form_->converters().isReachable("pdflatex", f.name()))
2142 defaultFormatCB->addItem(prettyname,
2143 QVariant(toqstr(f.name())));
2144 if (form_->converters().isReachable("platex", f.name()))
2145 defaultPlatexFormatCB->addItem(prettyname,
2146 QVariant(toqstr(f.name())));
2150 // restore selections
2151 int item = formatsCB->findText(current, Qt::MatchExactly);
2152 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2153 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2154 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2155 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2156 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2157 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2158 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2159 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2160 formatsCB->blockSignals(false);
2161 defaultFormatCB->blockSignals(false);
2162 defaultOTFFormatCB->blockSignals(false);
2163 defaultPlatexFormatCB->blockSignals(false);
2167 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2169 if (form_->formats().empty())
2171 int const nr = formatsCB->itemData(i).toInt();
2172 Format const f = form_->formats().get(nr);
2174 formatED->setText(toqstr(f.name()));
2175 copierED->setText(toqstr(form_->movers().command(f.name())));
2176 extensionsED->setText(toqstr(f.extensions()));
2177 mimeED->setText(toqstr(f.mime()));
2178 shortcutED->setText(
2179 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2180 documentCB->setChecked((f.documentFormat()));
2181 vectorCB->setChecked((f.vectorFormat()));
2182 exportMenuCB->setChecked((f.inExportMenu()));
2183 exportMenuCB->setEnabled((f.documentFormat()));
2189 void PrefFileformats::setFlags()
2191 int flags = Format::none;
2192 if (documentCB->isChecked())
2193 flags |= Format::document;
2194 if (vectorCB->isChecked())
2195 flags |= Format::vector;
2196 if (exportMenuCB->isChecked())
2197 flags |= Format::export_menu;
2198 currentFormat().setFlags(flags);
2199 exportMenuCB->setEnabled(documentCB->isChecked());
2204 void PrefFileformats::on_copierED_textEdited(const QString & s)
2206 string const fmt = fromqstr(formatED->text());
2207 form_->movers().set(fmt, fromqstr(s));
2212 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2214 currentFormat().setExtensions(fromqstr(s));
2219 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2221 currentFormat().setViewer(fromqstr(s));
2226 void PrefFileformats::on_editorED_textEdited(const QString & s)
2228 currentFormat().setEditor(fromqstr(s));
2233 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2235 currentFormat().setMime(fromqstr(s));
2240 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2242 string const new_shortcut = fromqstr(s);
2243 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2244 currentFormat().shortcut()))
2246 currentFormat().setShortcut(new_shortcut);
2251 void PrefFileformats::on_formatED_editingFinished()
2253 string const newname = fromqstr(formatED->displayText());
2254 string const oldname = currentFormat().name();
2255 if (newname == oldname)
2257 if (form_->converters().formatIsUsed(oldname)) {
2258 Alert::error(_("Format in use"),
2259 _("You cannot change a format's short name "
2260 "if the format is used by a converter. "
2261 "Please remove the converter first."));
2266 currentFormat().setName(newname);
2271 void PrefFileformats::on_formatED_textChanged(const QString &)
2273 QString t = formatED->text();
2275 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2276 setValid(formatLA, valid);
2280 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2282 QString t = formatsCB->currentText();
2284 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2285 setValid(formatsLA, valid);
2289 void PrefFileformats::updatePrettyname()
2291 QString const newname = formatsCB->currentText();
2292 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2295 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2303 void updateComboBox(LyXRC::Alternatives const & alts,
2304 string const & fmt, QComboBox * combo)
2306 LyXRC::Alternatives::const_iterator it =
2308 if (it != alts.end()) {
2309 LyXRC::CommandSet const & cmds = it->second;
2310 LyXRC::CommandSet::const_iterator sit =
2312 LyXRC::CommandSet::const_iterator const sen =
2314 for (; sit != sen; ++sit) {
2315 QString const qcmd = toqstr(*sit);
2316 combo->addItem(qcmd, qcmd);
2323 void PrefFileformats::updateViewers()
2325 Format const f = currentFormat();
2326 viewerCO->blockSignals(true);
2328 viewerCO->addItem(qt_("None"), QString());
2329 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2330 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2331 viewerCO->blockSignals(false);
2333 int pos = viewerCO->findData(toqstr(f.viewer()));
2336 viewerED->setEnabled(false);
2337 viewerCO->setCurrentIndex(pos);
2339 viewerED->setEnabled(true);
2340 viewerED->setText(toqstr(f.viewer()));
2341 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2346 void PrefFileformats::updateEditors()
2348 Format const f = currentFormat();
2349 editorCO->blockSignals(true);
2351 editorCO->addItem(qt_("None"), QString());
2352 updateComboBox(editor_alternatives, f.name(), editorCO);
2353 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2354 editorCO->blockSignals(false);
2356 int pos = editorCO->findData(toqstr(f.editor()));
2359 editorED->setEnabled(false);
2360 editorCO->setCurrentIndex(pos);
2362 editorED->setEnabled(true);
2363 editorED->setText(toqstr(f.editor()));
2364 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2369 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2371 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2372 viewerED->setEnabled(custom);
2374 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2378 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2380 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2381 editorED->setEnabled(custom);
2383 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2387 Format & PrefFileformats::currentFormat()
2389 int const i = formatsCB->currentIndex();
2390 int const nr = formatsCB->itemData(i).toInt();
2391 return form_->formats().get(nr);
2395 void PrefFileformats::on_formatNewPB_clicked()
2397 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2399 formatsCB->setCurrentIndex(0);
2400 formatsCB->setFocus(Qt::OtherFocusReason);
2404 void PrefFileformats::on_formatRemovePB_clicked()
2406 int const i = formatsCB->currentIndex();
2407 int const nr = formatsCB->itemData(i).toInt();
2408 string const current_text = form_->formats().get(nr).name();
2409 if (form_->converters().formatIsUsed(current_text)) {
2410 Alert::error(_("Format in use"),
2411 _("Cannot remove a Format used by a Converter. "
2412 "Remove the converter first."));
2416 form_->formats().erase(current_text);
2419 on_formatsCB_editTextChanged(formatsCB->currentText());
2424 /////////////////////////////////////////////////////////////////////
2428 /////////////////////////////////////////////////////////////////////
2430 PrefLanguage::PrefLanguage(GuiPreferences * form)
2431 : PrefModule(catLanguage, N_("Language"), form)
2435 connect(visualCursorRB, SIGNAL(clicked()),
2436 this, SIGNAL(changed()));
2437 connect(logicalCursorRB, SIGNAL(clicked()),
2438 this, SIGNAL(changed()));
2439 connect(markForeignCB, SIGNAL(clicked()),
2440 this, SIGNAL(changed()));
2441 connect(respectOSkbdCB, SIGNAL(clicked()),
2442 this, SIGNAL(changed()));
2443 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2444 this, SIGNAL(changed()));
2445 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2446 this, SIGNAL(changed()));
2447 connect(languagePackageCO, SIGNAL(activated(int)),
2448 this, SIGNAL(changed()));
2449 connect(languagePackageED, SIGNAL(textChanged(QString)),
2450 this, SIGNAL(changed()));
2451 connect(globalCB, SIGNAL(clicked()),
2452 this, SIGNAL(changed()));
2453 connect(startCommandED, SIGNAL(textChanged(QString)),
2454 this, SIGNAL(changed()));
2455 connect(endCommandED, SIGNAL(textChanged(QString)),
2456 this, SIGNAL(changed()));
2457 connect(uiLanguageCO, SIGNAL(activated(int)),
2458 this, SIGNAL(changed()));
2459 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2460 this, SIGNAL(changed()));
2461 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2462 this, SIGNAL(changed()));
2463 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2464 this, SIGNAL(changed()));
2466 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2467 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2468 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2470 #if QT_VERSION < 0x060000
2471 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2473 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2475 defaultDecimalSepED->setMaxLength(1);
2477 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2478 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2480 QAbstractItemModel * language_model = guiApp->languageModel();
2481 language_model->sort(0);
2482 uiLanguageCO->blockSignals(true);
2483 uiLanguageCO->clear();
2484 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2485 for (int i = 0; i != language_model->rowCount(); ++i) {
2486 QModelIndex index = language_model->index(i, 0);
2487 // Filter the list based on the available translation and add
2488 // each language code only once
2489 string const name = fromqstr(index.data(Qt::UserRole).toString());
2490 Language const * lang = languages.getLanguage(name);
2493 // never remove the currently selected language
2494 if (name != form->rc().gui_language
2495 && name != lyxrc.gui_language
2496 && (!Messages::available(lang->code())
2497 || !lang->hasGuiSupport()))
2499 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2500 index.data(Qt::UserRole).toString());
2502 uiLanguageCO->blockSignals(false);
2504 // FIXME: restore this when it works (see discussion in #6450).
2505 respectOSkbdCB->hide();
2509 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2511 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2512 qt_("The change of user interface language will be fully "
2513 "effective only after a restart."));
2517 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2520 languagePackageED->setText(save_langpack_);
2521 else if (!languagePackageED->text().isEmpty()) {
2522 save_langpack_ = languagePackageED->text();
2523 languagePackageED->clear();
2525 languagePackageED->setEnabled(i == 2);
2529 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2531 defaultDecimalSepED->setEnabled(i == 1);
2535 void PrefLanguage::applyRC(LyXRC & rc) const
2537 rc.visual_cursor = visualCursorRB->isChecked();
2538 rc.mark_foreign_language = markForeignCB->isChecked();
2539 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2540 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2541 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2542 int const p = languagePackageCO->currentIndex();
2544 rc.language_package_selection = LyXRC::LP_AUTO;
2546 rc.language_package_selection = LyXRC::LP_BABEL;
2548 rc.language_package_selection = LyXRC::LP_CUSTOM;
2550 rc.language_package_selection = LyXRC::LP_NONE;
2551 rc.language_custom_package = fromqstr(languagePackageED->text());
2552 rc.language_global_options = globalCB->isChecked();
2553 rc.language_command_begin = fromqstr(startCommandED->text());
2554 rc.language_command_end = fromqstr(endCommandED->text());
2555 rc.gui_language = fromqstr(
2556 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2557 if (defaultDecimalSepCO->currentIndex() == 0)
2558 rc.default_decimal_sep = "locale";
2560 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2561 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2565 void PrefLanguage::updateRC(LyXRC const & rc)
2567 if (rc.visual_cursor)
2568 visualCursorRB->setChecked(true);
2570 logicalCursorRB->setChecked(true);
2571 markForeignCB->setChecked(rc.mark_foreign_language);
2572 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2573 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2574 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2575 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2576 if (languagePackageCO->currentIndex() == 2) {
2577 languagePackageED->setText(toqstr(rc.language_custom_package));
2578 languagePackageED->setEnabled(true);
2580 languagePackageED->clear();
2581 save_langpack_ = toqstr(rc.language_custom_package);
2582 languagePackageED->setEnabled(false);
2584 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2585 globalCB->setChecked(rc.language_global_options);
2586 startCommandED->setText(toqstr(rc.language_command_begin));
2587 endCommandED->setText(toqstr(rc.language_command_end));
2588 if (rc.default_decimal_sep == "locale") {
2589 defaultDecimalSepCO->setCurrentIndex(0);
2590 defaultDecimalSepED->clear();
2592 defaultDecimalSepCO->setCurrentIndex(1);
2593 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2595 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2596 defaultLengthUnitCO->setCurrentIndex(pos);
2598 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2599 uiLanguageCO->blockSignals(true);
2600 uiLanguageCO->setCurrentIndex(pos);
2601 uiLanguageCO->blockSignals(false);
2605 /////////////////////////////////////////////////////////////////////
2607 // PrefUserInterface
2609 /////////////////////////////////////////////////////////////////////
2611 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2612 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2616 connect(uiFilePB, SIGNAL(clicked()),
2617 this, SLOT(selectUi()));
2618 connect(uiFileED, SIGNAL(textChanged(QString)),
2619 this, SIGNAL(changed()));
2620 connect(iconSetCO, SIGNAL(activated(int)),
2621 this, SIGNAL(changed()));
2622 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2623 this, SIGNAL(changed()));
2624 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2625 this, SIGNAL(changed()));
2626 connect(tooltipCB, SIGNAL(toggled(bool)),
2627 this, SIGNAL(changed()));
2628 lastfilesSB->setMaximum(maxlastfiles);
2630 iconSetCO->addItem(qt_("Default"), QString());
2631 iconSetCO->addItem(qt_("Classic"), "classic");
2632 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2634 #if QT_VERSION >= 0x040600
2635 if (guiApp->platformName() != "qt4x11"
2636 && guiApp->platformName() != "xcb"
2637 && !guiApp->platformName().contains("wayland"))
2639 useSystemThemeIconsCB->hide();
2643 void PrefUserInterface::applyRC(LyXRC & rc) const
2645 rc.icon_set = fromqstr(iconSetCO->itemData(
2646 iconSetCO->currentIndex()).toString());
2648 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2649 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2650 rc.num_lastfiles = lastfilesSB->value();
2651 rc.use_tooltip = tooltipCB->isChecked();
2655 void PrefUserInterface::updateRC(LyXRC const & rc)
2657 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2660 iconSetCO->setCurrentIndex(iconset);
2661 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2662 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2663 lastfilesSB->setValue(rc.num_lastfiles);
2664 tooltipCB->setChecked(rc.use_tooltip);
2668 void PrefUserInterface::selectUi()
2670 QString file = form_->browseUI(internalPath(uiFileED->text()));
2671 if (!file.isEmpty())
2672 uiFileED->setText(file);
2676 /////////////////////////////////////////////////////////////////////
2678 // PrefDocumentHandling
2680 /////////////////////////////////////////////////////////////////////
2682 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2683 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2687 connect(autoSaveCB, SIGNAL(toggled(bool)),
2688 autoSaveSB, SLOT(setEnabled(bool)));
2689 connect(autoSaveCB, SIGNAL(toggled(bool)),
2690 TextLabel1, SLOT(setEnabled(bool)));
2691 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2692 this, SIGNAL(changed()));
2693 connect(singleInstanceCB, SIGNAL(clicked()),
2694 this, SIGNAL(changed()));
2695 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2696 this, SIGNAL(changed()));
2697 connect(closeLastViewCO, SIGNAL(activated(int)),
2698 this, SIGNAL(changed()));
2699 connect(restoreCursorCB, SIGNAL(clicked()),
2700 this, SIGNAL(changed()));
2701 connect(loadSessionCB, SIGNAL(clicked()),
2702 this, SIGNAL(changed()));
2703 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2704 this, SIGNAL(changed()));
2705 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2706 this, SIGNAL(changed()));
2707 connect(autoSaveCB, SIGNAL(clicked()),
2708 this, SIGNAL(changed()));
2709 connect(backupCB, SIGNAL(clicked()),
2710 this, SIGNAL(changed()));
2711 connect(saveCompressedCB, SIGNAL(clicked()),
2712 this, SIGNAL(changed()));
2713 connect(saveOriginCB, SIGNAL(clicked()),
2714 this, SIGNAL(changed()));
2718 void PrefDocHandling::applyRC(LyXRC & rc) const
2720 rc.use_lastfilepos = restoreCursorCB->isChecked();
2721 rc.load_session = loadSessionCB->isChecked();
2722 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2723 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2724 rc.make_backup = backupCB->isChecked();
2725 rc.save_compressed = saveCompressedCB->isChecked();
2726 rc.save_origin = saveOriginCB->isChecked();
2727 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2728 rc.single_instance = singleInstanceCB->isChecked();
2729 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2731 switch (closeLastViewCO->currentIndex()) {
2733 rc.close_buffer_with_last_view = "yes";
2736 rc.close_buffer_with_last_view = "no";
2739 rc.close_buffer_with_last_view = "ask";
2747 void PrefDocHandling::updateRC(LyXRC const & rc)
2749 restoreCursorCB->setChecked(rc.use_lastfilepos);
2750 loadSessionCB->setChecked(rc.load_session);
2751 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2752 // convert to minutes
2753 bool autosave = rc.autosave > 0;
2754 int mins = rc.autosave / 60;
2757 autoSaveSB->setValue(mins);
2758 autoSaveCB->setChecked(autosave);
2759 autoSaveSB->setEnabled(autosave);
2760 backupCB->setChecked(rc.make_backup);
2761 saveCompressedCB->setChecked(rc.save_compressed);
2762 saveOriginCB->setChecked(rc.save_origin);
2763 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2764 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2765 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2766 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2767 if (rc.close_buffer_with_last_view == "yes")
2768 closeLastViewCO->setCurrentIndex(0);
2769 else if (rc.close_buffer_with_last_view == "no")
2770 closeLastViewCO->setCurrentIndex(1);
2771 else if (rc.close_buffer_with_last_view == "ask")
2772 closeLastViewCO->setCurrentIndex(2);
2776 void PrefDocHandling::on_clearSessionPB_clicked()
2778 guiApp->clearSession();
2783 /////////////////////////////////////////////////////////////////////
2787 /////////////////////////////////////////////////////////////////////
2789 PrefEdit::PrefEdit(GuiPreferences * form)
2790 : PrefModule(catEditing, N_("Control"), form)
2794 connect(cursorFollowsCB, SIGNAL(clicked()),
2795 this, SIGNAL(changed()));
2796 connect(scrollBelowCB, SIGNAL(clicked()),
2797 this, SIGNAL(changed()));
2798 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2799 this, SIGNAL(changed()));
2800 connect(copyCTMarkupCB, SIGNAL(clicked()),
2801 this, SIGNAL(changed()));
2802 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2803 this, SIGNAL(changed()));
2804 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2805 this, SIGNAL(changed()));
2806 connect(macroEditStyleCO, SIGNAL(activated(int)),
2807 this, SIGNAL(changed()));
2808 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2809 this, SIGNAL(changed()));
2810 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2811 this, SIGNAL(changed()));
2812 connect(fullscreenWidthSB, SIGNAL(valueChanged(int)),
2813 this, SIGNAL(changed()));
2814 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2815 this, SIGNAL(changed()));
2816 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2817 this, SIGNAL(changed()));
2818 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2819 this, SIGNAL(changed()));
2820 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2821 this, SIGNAL(changed()));
2822 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2823 this, SIGNAL(changed()));
2827 void PrefEdit::on_fullscreenLimitCB_toggled(bool const state)
2829 fullscreenWidthSB->setEnabled(state);
2830 fullscreenWidthLA->setEnabled(state);
2835 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2837 citationSearchLE->setEnabled(state);
2838 citationSearchLA->setEnabled(state);
2843 void PrefEdit::applyRC(LyXRC & rc) const
2845 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2846 rc.scroll_below_document = scrollBelowCB->isChecked();
2847 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2848 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2849 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2850 rc.group_layouts = groupEnvironmentsCB->isChecked();
2851 switch (macroEditStyleCO->currentIndex()) {
2852 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2853 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2854 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2856 rc.cursor_width = cursorWidthSB->value();
2857 rc.citation_search = citationSearchCB->isChecked();
2858 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2859 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2860 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2861 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2862 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2863 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2864 rc.full_screen_width = fullscreenWidthSB->value();
2865 rc.full_screen_limit = fullscreenLimitCB->isChecked();
2869 void PrefEdit::updateRC(LyXRC const & rc)
2871 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2872 scrollBelowCB->setChecked(rc.scroll_below_document);
2873 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2874 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2875 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2876 groupEnvironmentsCB->setChecked(rc.group_layouts);
2877 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2878 cursorWidthSB->setValue(rc.cursor_width);
2879 citationSearchCB->setChecked(rc.citation_search);
2880 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2881 citationSearchLE->setEnabled(rc.citation_search);
2882 citationSearchLA->setEnabled(rc.citation_search);
2883 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2884 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2885 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2886 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2887 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2888 fullscreenWidthSB->setValue(rc.full_screen_width);
2889 fullscreenLimitCB->setChecked(rc.full_screen_limit);
2890 fullscreenWidthSB->setEnabled(rc.full_screen_limit);
2891 fullscreenWidthLA->setEnabled(rc.full_screen_limit);
2895 /////////////////////////////////////////////////////////////////////
2899 /////////////////////////////////////////////////////////////////////
2902 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2904 Ui::shortcutUi::setupUi(this);
2905 QDialog::setModal(true);
2906 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2910 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2911 : PrefModule(catEditing, N_("Shortcuts"), form),
2912 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2913 systemItem_(nullptr)
2917 shortcutsTW->setColumnCount(2);
2918 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2919 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2920 shortcutsTW->setSortingEnabled(true);
2921 // Multi-selection can be annoying.
2922 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2924 connect(bindFilePB, SIGNAL(clicked()),
2925 this, SLOT(selectBind()));
2926 connect(bindFileED, SIGNAL(textChanged(QString)),
2927 this, SIGNAL(changed()));
2929 shortcut_ = new GuiShortcutDialog(this);
2930 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2931 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2932 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2934 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2935 this, SIGNAL(changed()));
2936 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2937 shortcut_, SLOT(reject()));
2938 connect(shortcut_->clearPB, SIGNAL(clicked()),
2939 this, SLOT(shortcutClearPressed()));
2940 connect(shortcut_->removePB, SIGNAL(clicked()),
2941 this, SLOT(shortcutRemovePressed()));
2942 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2943 this, SLOT(shortcutOkPressed()));
2944 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2945 this, SLOT(shortcutCancelPressed()));
2949 void PrefShortcuts::applyRC(LyXRC & rc) const
2951 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2952 // write user_bind and user_unbind to .lyx/bind/user.bind
2953 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2954 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2955 lyxerr << "LyX could not create the user bind directory '"
2956 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2959 if (!bind_dir.isDirWritable()) {
2960 lyxerr << "LyX could not write to the user bind directory '"
2961 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2964 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2965 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2966 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2967 // immediately apply the keybindings. Why this is not done before?
2968 // The good thing is that the menus are updated automatically.
2969 theTopLevelKeymap().clear();
2970 theTopLevelKeymap().read("site");
2971 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2972 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2976 void PrefShortcuts::updateRC(LyXRC const & rc)
2978 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2980 system_bind_.clear();
2982 user_unbind_.clear();
2983 system_bind_.read("site");
2984 system_bind_.read(rc.bind_file);
2985 // \unbind in user.bind is added to user_unbind_
2986 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2987 updateShortcutsTW();
2991 void PrefShortcuts::updateShortcutsTW()
2993 shortcutsTW->clear();
2995 editItem_ = new QTreeWidgetItem(shortcutsTW);
2996 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2997 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
2999 mathItem_ = new QTreeWidgetItem(shortcutsTW);
3000 mathItem_->setText(0, qt_("Mathematical Symbols"));
3001 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3003 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3004 bufferItem_->setText(0, qt_("Document and Window"));
3005 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3007 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3008 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3009 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3011 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3012 systemItem_->setText(0, qt_("System and Miscellaneous"));
3013 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3015 // listBindings(unbound=true) lists all bound and unbound lfuns
3016 // Items in this list is tagged by its source.
3017 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3019 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3021 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3022 KeyMap::UserUnbind);
3023 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3024 user_bindinglist.end());
3025 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3026 user_unbindinglist.end());
3028 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3029 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3030 for (; it != it_end; ++it)
3031 insertShortcutItem(it->request, it->sequence, it->tag);
3033 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3034 on_shortcutsTW_itemSelectionChanged();
3035 on_searchLE_textEdited();
3036 shortcutsTW->resizeColumnToContents(0);
3041 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3043 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3048 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3050 // Hide rebound system settings that are empty
3051 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3055 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3057 item->setData(0, Qt::UserRole, QVariant(tag));
3061 case KeyMap::System:
3063 case KeyMap::UserBind:
3066 case KeyMap::UserUnbind:
3067 font.setStrikeOut(true);
3069 // this item is not displayed now.
3070 case KeyMap::UserExtraUnbind:
3071 font.setStrikeOut(true);
3074 item->setHidden(isAlwaysHidden(*item));
3075 item->setFont(1, font);
3079 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3080 KeySequence const & seq, KeyMap::ItemType tag)
3082 FuncCode const action = lfun.action();
3083 string const action_name = lyxaction.getActionName(action);
3084 QString const lfun_name = toqstr(from_utf8(action_name)
3085 + ' ' + lfun.argument());
3086 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3088 QTreeWidgetItem * newItem = nullptr;
3089 // for unbind items, try to find an existing item in the system bind list
3090 if (tag == KeyMap::UserUnbind) {
3091 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(lfun_name,
3092 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3093 for (auto const & item : items) {
3094 if (item->text(1) == shortcut) {
3099 // if not found, this unbind item is KeyMap::UserExtraUnbind
3100 // Such an item is not displayed to avoid confusion (what is
3101 // unmatched removed?).
3107 switch(lyxaction.getActionType(action)) {
3108 case LyXAction::Hidden:
3110 case LyXAction::Edit:
3111 newItem = new QTreeWidgetItem(editItem_);
3113 case LyXAction::Math:
3114 newItem = new QTreeWidgetItem(mathItem_);
3116 case LyXAction::Buffer:
3117 newItem = new QTreeWidgetItem(bufferItem_);
3119 case LyXAction::Layout:
3120 newItem = new QTreeWidgetItem(layoutItem_);
3122 case LyXAction::System:
3123 newItem = new QTreeWidgetItem(systemItem_);
3126 // this should not happen
3127 newItem = new QTreeWidgetItem(shortcutsTW);
3131 newItem->setText(0, lfun_name);
3132 newItem->setText(1, shortcut);
3133 // record BindFile representation to recover KeySequence when needed.
3134 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3135 setItemType(newItem, tag);
3140 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3142 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3143 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3144 modifyPB->setEnabled(!items.isEmpty());
3145 if (items.isEmpty())
3148 if (itemType(*items[0]) == KeyMap::UserUnbind)
3149 removePB->setText(qt_("Res&tore"));
3151 removePB->setText(qt_("Remo&ve"));
3155 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3161 void PrefShortcuts::modifyShortcut()
3163 QTreeWidgetItem * item = shortcutsTW->currentItem();
3164 if (item->flags() & Qt::ItemIsSelectable) {
3165 shortcut_->lfunLE->setText(item->text(0));
3166 save_lfun_ = item->text(0).trimmed();
3167 shortcut_->shortcutWG->setText(item->text(1));
3169 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3170 shortcut_->shortcutWG->setKeySequence(seq);
3171 shortcut_->shortcutWG->setFocus();
3177 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3179 // list of items that match lfun
3180 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3181 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3182 for (auto const & item : items) {
3183 if (isAlwaysHidden(*item)) {
3184 setItemType(item, KeyMap::System);
3186 shortcutsTW->setCurrentItem(item);
3193 void PrefShortcuts::removeShortcut()
3195 // it seems that only one item can be selected, but I am
3196 // removing all selected items anyway.
3197 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3198 for (auto & item : items) {
3199 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3200 string lfun = fromqstr(item->text(0));
3201 FuncRequest const func = lyxaction.lookupFunc(lfun);
3203 switch (itemType(*item)) {
3204 case KeyMap::System: {
3205 // for system bind, we do not touch the item
3206 // but add an user unbind item
3207 user_unbind_.bind(shortcut, func);
3208 setItemType(item, KeyMap::UserUnbind);
3209 removePB->setText(qt_("Res&tore"));
3212 case KeyMap::UserBind: {
3213 // for user_bind, we remove this bind
3214 QTreeWidgetItem * parent = item->parent();
3215 int itemIdx = parent->indexOfChild(item);
3216 parent->takeChild(itemIdx);
3218 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3220 shortcutsTW->scrollToItem(parent);
3221 user_bind_.unbind(shortcut, func);
3222 // If this user binding hid an empty system binding, unhide the
3223 // latter and select it.
3224 unhideEmpty(item->text(0), true);
3227 case KeyMap::UserUnbind: {
3228 // for user_unbind, we remove the unbind, and the item
3229 // become KeyMap::System again.
3231 seq.parse(shortcut);
3232 // Ask the user to replace current binding
3233 if (!validateNewShortcut(func, seq, QString()))
3235 user_unbind_.unbind(shortcut, func);
3236 setItemType(item, KeyMap::System);
3237 removePB->setText(qt_("Remo&ve"));
3240 case KeyMap::UserExtraUnbind: {
3241 // for user unbind that is not in system bind file,
3242 // remove this unbind file
3243 QTreeWidgetItem * parent = item->parent();
3244 parent->takeChild(parent->indexOfChild(item));
3245 user_unbind_.unbind(shortcut, func);
3252 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3254 for (auto item : items) {
3255 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3256 string lfun = fromqstr(item->text(0));
3257 FuncRequest const func = lyxaction.lookupFunc(lfun);
3259 switch (itemType(*item)) {
3260 case KeyMap::System:
3261 // for system bind, we do not touch the item
3262 // but add an user unbind item
3263 user_unbind_.bind(shortcut, func);
3264 setItemType(item, KeyMap::UserUnbind);
3267 case KeyMap::UserBind: {
3268 // for user_bind, we remove this bind
3269 QTreeWidgetItem * parent = item->parent();
3270 int itemIdx = parent->indexOfChild(item);
3271 parent->takeChild(itemIdx);
3272 user_bind_.unbind(shortcut, func);
3273 unhideEmpty(item->text(0), false);
3283 void PrefShortcuts::selectBind()
3285 QString file = form_->browsebind(internalPath(bindFileED->text()));
3286 if (!file.isEmpty()) {
3287 bindFileED->setText(file);
3288 system_bind_ = KeyMap();
3289 system_bind_.read(fromqstr(file));
3290 updateShortcutsTW();
3295 void PrefShortcuts::on_modifyPB_pressed()
3301 void PrefShortcuts::on_newPB_pressed()
3303 shortcut_->lfunLE->clear();
3304 shortcut_->shortcutWG->reset();
3305 save_lfun_ = QString();
3310 void PrefShortcuts::on_removePB_pressed()
3317 void PrefShortcuts::on_searchLE_textEdited()
3319 if (searchLE->text().isEmpty()) {
3320 // show all hidden items
3321 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3323 (*it)->setHidden(isAlwaysHidden(**it));
3324 // close all categories
3325 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3326 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3329 // search both columns
3330 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3331 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3332 matched += shortcutsTW->findItems(searchLE->text(),
3333 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3335 // hide everyone (to avoid searching in matched QList repeatedly
3336 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3338 (*it++)->setHidden(true);
3339 // show matched items
3340 for (auto & item : matched)
3341 if (!isAlwaysHidden(*item)) {
3342 item->setHidden(false);
3344 item->parent()->setExpanded(true);
3349 docstring makeCmdString(FuncRequest const & f)
3351 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3352 if (!f.argument().empty())
3353 actionStr += " " + f.argument();
3358 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3360 FuncRequest res = user_bind_.getBinding(k);
3361 if (res.action() != LFUN_UNKNOWN_ACTION)
3363 res = system_bind_.getBinding(k);
3364 // Check if it is unbound. Note: user_unbind_ can only unbind one
3365 // FuncRequest per key sequence.
3366 if (user_unbind_.getBinding(k) == res)
3367 return FuncRequest::unknown;
3372 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3373 KeySequence const & k,
3374 QString const & lfun_to_modify)
3376 if (func.action() == LFUN_UNKNOWN_ACTION) {
3377 Alert::error(_("Failed to create shortcut"),
3378 _("Unknown or invalid LyX function"));
3382 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3383 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3384 // and how it is used in GuiPrefs::shortcutOkPressed.
3385 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3386 Alert::error(_("Failed to create shortcut"),
3387 _("This LyX function is hidden and cannot be bound."));
3391 if (k.length() == 0) {
3392 Alert::error(_("Failed to create shortcut"),
3393 _("Invalid or empty key sequence"));
3397 FuncRequest oldBinding = currentBinding(k);
3398 if (oldBinding == func)
3399 // nothing to change
3402 // make sure this key isn't already bound---and, if so, prompt user
3403 // (exclude the lfun the user already wants to modify)
3404 docstring const action_string = makeCmdString(oldBinding);
3405 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3406 && lfun_to_modify != toqstr(action_string)) {
3407 docstring const new_action_string = makeCmdString(func);
3408 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3410 "Are you sure you want to unbind the "
3411 "current shortcut and bind it to %3$s?"),
3412 k.print(KeySequence::ForGui), action_string,
3414 int ret = Alert::prompt(_("Redefine shortcut?"),
3415 text, 0, 1, _("&Redefine"), _("&Cancel"));
3418 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3419 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3420 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3421 deactivateShortcuts(items);
3427 void PrefShortcuts::shortcutOkPressed()
3429 QString const new_lfun = shortcut_->lfunLE->text();
3430 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3431 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3433 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3434 // "modify", or is empty if they clicked "new" (which I do not really like)
3435 if (!validateNewShortcut(func, k, save_lfun_))
3438 if (!save_lfun_.isEmpty()) {
3439 // real modification of the lfun's shortcut,
3440 // so remove the previous one
3441 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3442 deactivateShortcuts(to_modify);
3445 shortcut_->accept();
3447 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3449 user_bind_.bind(&k, func);
3450 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3452 item->parent()->setExpanded(true);
3453 shortcutsTW->setCurrentItem(item);
3454 shortcutsTW->scrollToItem(item);
3456 Alert::error(_("Failed to create shortcut"),
3457 _("Can not insert shortcut to the list"));
3463 void PrefShortcuts::shortcutCancelPressed()
3465 shortcut_->shortcutWG->reset();
3469 void PrefShortcuts::shortcutClearPressed()
3471 shortcut_->shortcutWG->reset();
3475 void PrefShortcuts::shortcutRemovePressed()
3477 shortcut_->shortcutWG->removeFromSequence();
3481 /////////////////////////////////////////////////////////////////////
3485 /////////////////////////////////////////////////////////////////////
3487 PrefIdentity::PrefIdentity(GuiPreferences * form)
3488 : PrefModule(QString(), N_("Identity"), form)
3492 connect(nameED, SIGNAL(textChanged(QString)),
3493 this, SIGNAL(changed()));
3494 connect(emailED, SIGNAL(textChanged(QString)),
3495 this, SIGNAL(changed()));
3496 connect(initialsED, SIGNAL(textChanged(QString)),
3497 this, SIGNAL(changed()));
3499 nameED->setValidator(new NoNewLineValidator(nameED));
3500 emailED->setValidator(new NoNewLineValidator(emailED));
3501 initialsED->setValidator(new NoNewLineValidator(initialsED));
3505 void PrefIdentity::applyRC(LyXRC & rc) const
3507 rc.user_name = fromqstr(nameED->text());
3508 rc.user_email = fromqstr(emailED->text());
3509 rc.user_initials = fromqstr(initialsED->text());
3513 void PrefIdentity::updateRC(LyXRC const & rc)
3515 nameED->setText(toqstr(rc.user_name));
3516 emailED->setText(toqstr(rc.user_email));
3517 initialsED->setText(toqstr(rc.user_initials));
3522 /////////////////////////////////////////////////////////////////////
3526 /////////////////////////////////////////////////////////////////////
3528 GuiPreferences::GuiPreferences(GuiView & lv)
3529 : GuiDialog(lv, "prefs", qt_("Preferences"))
3533 QDialog::setModal(false);
3535 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3536 this, SLOT(slotButtonBox(QAbstractButton *)));
3538 addModule(new PrefUserInterface(this));
3539 addModule(new PrefDocHandling(this));
3540 addModule(new PrefEdit(this));
3541 addModule(new PrefShortcuts(this));
3542 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3543 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3544 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3545 addModule(screenfonts);
3546 addModule(new PrefColors(this));
3547 addModule(new PrefDisplay(this));
3548 addModule(new PrefInput(this));
3549 addModule(new PrefCompletion(this));
3551 addModule(new PrefPaths(this));
3553 addModule(new PrefIdentity(this));
3555 addModule(new PrefLanguage(this));
3556 addModule(new PrefSpellchecker(this));
3558 PrefOutput * output = new PrefOutput(this);
3560 addModule(new PrefLatex(this));
3562 PrefConverters * converters = new PrefConverters(this);
3563 PrefFileformats * formats = new PrefFileformats(this);
3564 connect(formats, SIGNAL(formatsChanged()),
3565 converters, SLOT(updateGui()));
3566 addModule(converters);
3569 prefsPS->setCurrentPanel("User Interface");
3570 // FIXME: hack to work around resizing bug in Qt >= 4.2
3571 // bug verified with Qt 4.2.{0-3} (JSpitzm)
3572 #if QT_VERSION >= 0x040200
3573 prefsPS->updateGeometry();
3576 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3577 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3578 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3579 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3580 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3582 guilyxfiles_ = new GuiLyXFiles(lv);
3583 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3584 this, SLOT(slotFileSelected(QString)));
3588 void GuiPreferences::addModule(PrefModule * module)
3590 LASSERT(module, return);
3591 if (module->category().isEmpty())
3592 prefsPS->addPanel(module, module->title());
3594 prefsPS->addPanel(module, module->title(), module->category());
3595 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3596 modules_.push_back(module);
3600 void GuiPreferences::change_adaptor()
3606 void GuiPreferences::applyRC(LyXRC & rc) const
3608 size_t end = modules_.size();
3609 for (size_t i = 0; i != end; ++i)
3610 modules_[i]->applyRC(rc);
3614 void GuiPreferences::updateRC(LyXRC const & rc)
3616 size_t const end = modules_.size();
3617 for (size_t i = 0; i != end; ++i)
3618 modules_[i]->updateRC(rc);
3622 void GuiPreferences::applyView()
3628 bool GuiPreferences::initialiseParams(string const &)
3631 formats_ = theFormats();
3632 converters_ = theConverters();
3633 converters_.update(formats_);
3634 movers_ = theMovers();
3638 // Make sure that the bc is in the INITIAL state
3639 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3646 void GuiPreferences::dispatchParams()
3649 rc_.write(ss, true);
3650 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3651 // issue prefsApplied signal. This will update the
3652 // localized screen font sizes.
3654 // FIXME: these need lfuns
3656 Author const & author =
3657 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3658 from_utf8(rc_.user_initials));
3659 theBufferList().recordCurrentAuthor(author);
3661 theFormats() = formats_;
3663 theConverters() = converters_;
3664 theConverters().update(formats_);
3665 theConverters().buildGraph();
3666 theBufferList().invalidateConverterCache();
3668 theMovers() = movers_;
3670 for (string const & color : colors_)
3671 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3675 if (!tempSaveCB->isChecked())
3676 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3680 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3682 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3686 void GuiPreferences::slotFileSelected(QString const file)
3692 QString GuiPreferences::browseLibFile(QString const & dir,
3693 QString const & name, QString const & ext)
3697 guilyxfiles_->passParams(fromqstr(dir));
3698 guilyxfiles_->selectItem(name);
3699 guilyxfiles_->exec();
3701 QString const result = uifile_;
3703 // remove the extension if it is the default one
3704 QString noextresult;
3705 if (getExtension(result) == ext)
3706 noextresult = removeExtension(result);
3708 noextresult = result;
3710 // remove the directory, if it is the default one
3711 QString const file = onlyFileName(noextresult);
3712 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3719 QString GuiPreferences::browsebind(QString const & file)
3721 return browseLibFile("bind", file, "bind");
3725 QString GuiPreferences::browseUI(QString const & file)
3727 return browseLibFile("ui", file, "ui");
3731 QString GuiPreferences::browsekbmap(QString const & file)
3733 return browseLibFile("kbd", file, "kmap");
3737 QString GuiPreferences::browse(QString const & file,
3738 QString const & title) const
3740 return browseFile(file, title, QStringList(), true);
3744 } // namespace frontend
3747 #include "moc_GuiPrefs.cpp"