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