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 "LengthCombo.h"
37 #include "LyXAction.h"
39 #include "PanelStack.h"
41 #include "SpellChecker.h"
43 #include "support/debug.h"
44 #include "support/FileName.h"
45 #include "support/filetools.h"
46 #include "support/gettext.h"
47 #include "support/lassert.h"
48 #include "support/lstrings.h"
49 #include "support/Messages.h"
50 #include "support/os.h"
51 #include "support/Package.h"
53 #include "frontends/alert.h"
54 #include "frontends/Application.h"
55 #include "frontends/FontLoader.h"
57 #include <QAbstractItemModel>
59 #include <QColorDialog>
60 #include <QFontDatabase>
61 #include <QHeaderView>
63 #include <QMessageBox>
64 #include <QPushButton>
67 #include <QTreeWidget>
68 #include <QTreeWidgetItem>
79 using namespace lyx::support;
80 using namespace lyx::support::os;
85 /////////////////////////////////////////////////////////////////////
89 /////////////////////////////////////////////////////////////////////
91 /** Launch a file dialog and return the chosen file.
92 filename: a suggested filename.
93 title: the title of the dialog.
95 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
97 QString browseFile(QString const & filename,
98 QString const & title,
99 QStringList const & filters,
101 QString const & label1 = QString(),
102 QString const & dir1 = QString(),
103 QString const & label2 = QString(),
104 QString const & dir2 = QString(),
105 QString const & fallback_dir = QString())
107 QString lastPath = ".";
108 if (!filename.isEmpty())
109 lastPath = onlyPath(filename);
110 else if(!fallback_dir.isEmpty())
111 lastPath = fallback_dir;
113 FileDialog dlg(title);
114 dlg.setButton1(label1, dir1);
115 dlg.setButton2(label2, dir2);
117 FileDialog::Result result;
120 result = dlg.save(lastPath, filters, onlyFileName(filename));
122 result = dlg.open(lastPath, filters, onlyFileName(filename));
124 return result.second;
128 /** Launch a file dialog and return the chosen directory.
129 pathname: a suggested pathname.
130 title: the title of the dialog.
131 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
133 QString browseDir(QString const & pathname,
134 QString const & title,
135 QString const & label1 = QString(),
136 QString const & dir1 = QString(),
137 QString const & label2 = QString(),
138 QString const & dir2 = QString())
140 QString lastPath = ".";
141 if (!pathname.isEmpty())
142 lastPath = onlyPath(pathname);
144 FileDialog dlg(title);
145 dlg.setButton1(label1, dir1);
146 dlg.setButton2(label2, dir2);
148 FileDialog::Result const result =
149 dlg.opendir(lastPath, onlyFileName(pathname));
151 return result.second;
155 } // namespace frontend
158 QString browseRelToParent(QString const & filename, QString const & relpath,
159 QString const & title, QStringList const & filters, bool save,
160 QString const & label1, QString const & dir1,
161 QString const & label2, QString const & dir2)
163 QString const fname = makeAbsPath(filename, relpath);
165 QString const outname =
166 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
168 QString const reloutname =
169 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
171 if (reloutname.startsWith("../"))
178 QString browseRelToSub(QString const & filename, QString const & relpath,
179 QString const & title, QStringList const & filters, bool save,
180 QString const & label1, QString const & dir1,
181 QString const & label2, QString const & dir2)
183 QString const fname = makeAbsPath(filename, relpath);
185 QString const outname =
186 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
188 QString const reloutname =
189 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
191 QString testname = reloutname;
192 #if QT_VERSION < 0x060000
193 testname.remove(QRegExp("^(\\.\\./)+"));
195 testname.remove(QRegularExpression("^(\\.\\./)+"));
198 if (testname.contains("/"))
206 /////////////////////////////////////////////////////////////////////
210 /////////////////////////////////////////////////////////////////////
214 QString const catLookAndFeel = N_("Look & Feel");
215 QString const catEditing = N_("Editing");
216 QString const catLanguage = N_("Language Settings");
217 QString const catOutput = N_("Output");
218 QString const catFiles = N_("File Handling");
220 static void parseFontName(QString const & mangled0,
221 string & name, string & foundry)
223 string mangled = fromqstr(mangled0);
224 size_t const idx = mangled.find('[');
225 if (idx == string::npos || idx == 0) {
229 name = mangled.substr(0, idx - 1);
230 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
235 static void setComboxFont(QComboBox * cb, string const & family,
236 string const & foundry)
238 QString fontname = toqstr(family);
239 if (!foundry.empty())
240 fontname += " [" + toqstr(foundry) + ']';
242 for (int i = 0; i != cb->count(); ++i) {
243 if (cb->itemText(i) == fontname) {
244 cb->setCurrentIndex(i);
249 // Try matching without foundry name
251 // We count in reverse in order to prefer the Xft foundry
252 for (int i = cb->count(); --i >= 0;) {
253 string name, fnt_foundry;
254 parseFontName(cb->itemText(i), name, fnt_foundry);
255 if (compare_ascii_no_case(name, family) == 0) {
256 cb->setCurrentIndex(i);
261 // family alone can contain e.g. "Helvetica [Adobe]"
262 string tmpname, tmpfoundry;
263 parseFontName(toqstr(family), tmpname, tmpfoundry);
265 // We count in reverse in order to prefer the Xft foundry
266 for (int i = cb->count(); --i >= 0; ) {
267 string name, fnt_foundry;
268 parseFontName(cb->itemText(i), name, fnt_foundry);
269 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
270 cb->setCurrentIndex(i);
275 // Bleh, default fonts, and the names couldn't be found. Hack
280 QString const font_family = toqstr(family);
281 if (font_family == guiApp->romanFontName()) {
282 font.setStyleHint(QFont::Serif);
283 font.setFamily(font_family);
284 } else if (font_family == guiApp->sansFontName()) {
285 font.setStyleHint(QFont::SansSerif);
286 font.setFamily(font_family);
287 } else if (font_family == guiApp->typewriterFontName()) {
288 font.setStyleHint(QFont::TypeWriter);
289 font.setFamily(font_family);
291 LYXERR0("FAILED to find the default font: '"
292 << foundry << "', '" << family << '\'');
296 QFontInfo info(font);
297 string default_font_name, dummyfoundry;
298 parseFontName(info.family(), default_font_name, dummyfoundry);
299 LYXERR0("Apparent font is " << default_font_name);
301 for (int i = 0; i < cb->count(); ++i) {
302 LYXERR0("Looking at " << cb->itemText(i));
303 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
304 default_font_name) == 0) {
305 cb->setCurrentIndex(i);
310 LYXERR0("FAILED to find the font: '"
311 << foundry << "', '" << family << '\'');
315 /////////////////////////////////////////////////////////////////////
319 /////////////////////////////////////////////////////////////////////
321 PrefOutput::PrefOutput(GuiPreferences * form)
322 : PrefModule(catOutput, N_("General[[settings]]"), form)
326 dviCB->setValidator(new NoNewLineValidator(dviCB));
327 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
329 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
330 this, SIGNAL(changed()));
331 connect(overwriteCO, SIGNAL(activated(int)),
332 this, SIGNAL(changed()));
333 connect(dviCB, SIGNAL(editTextChanged(QString)),
334 this, SIGNAL(changed()));
335 connect(pdfCB, SIGNAL(editTextChanged(QString)),
336 this, SIGNAL(changed()));
337 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
338 this, SIGNAL(changed()));
339 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
340 this, SIGNAL(changed()));
341 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
342 this, SIGNAL(changed()));
344 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
345 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
346 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
349 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
350 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
351 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
352 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
354 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
355 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
356 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
357 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
358 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
359 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
360 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
364 void PrefOutput::applyRC(LyXRC & rc) const
366 rc.plaintext_linelen = plaintextLinelengthSB->value();
367 rc.forward_search_dvi = fromqstr(dviCB->currentText());
368 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
370 switch (overwriteCO->currentIndex()) {
372 rc.export_overwrite = NO_FILES;
375 rc.export_overwrite = MAIN_FILE;
378 rc.export_overwrite = ALL_FILES;
382 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
383 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
384 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
388 void PrefOutput::updateRC(LyXRC const & rc)
390 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
391 dviCB->setEditText(toqstr(rc.forward_search_dvi));
392 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
394 switch (rc.export_overwrite) {
396 overwriteCO->setCurrentIndex(0);
399 overwriteCO->setCurrentIndex(1);
402 overwriteCO->setCurrentIndex(2);
406 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
407 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
408 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
412 /////////////////////////////////////////////////////////////////////
416 /////////////////////////////////////////////////////////////////////
418 PrefInput::PrefInput(GuiPreferences * form)
419 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
423 connect(keymapCB, SIGNAL(clicked()),
424 this, SIGNAL(changed()));
425 connect(firstKeymapED, SIGNAL(textChanged(QString)),
426 this, SIGNAL(changed()));
427 connect(secondKeymapED, SIGNAL(textChanged(QString)),
428 this, SIGNAL(changed()));
429 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
430 this, SIGNAL(changed()));
431 connect(scrollzoomEnableCB, SIGNAL(clicked()),
432 this, SIGNAL(changed()));
433 connect(scrollzoomValueCO, SIGNAL(activated(int)),
434 this, SIGNAL(changed()));
435 connect(dontswapCB, SIGNAL(toggled(bool)),
436 this, SIGNAL(changed()));
437 connect(mmPasteCB, SIGNAL(toggled(bool)),
438 this, SIGNAL(changed()));
440 // reveal checkbox for switching Ctrl and Meta on Mac:
442 dontswapCB->setVisible(true);
444 dontswapCB->setVisible(false);
449 void PrefInput::applyRC(LyXRC & rc) const
451 // FIXME: can derive CB from the two EDs
452 rc.use_kbmap = keymapCB->isChecked();
453 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
454 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
455 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
456 if (scrollzoomEnableCB->isChecked()) {
457 switch (scrollzoomValueCO->currentIndex()) {
459 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
462 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
465 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
469 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
471 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
472 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
476 void PrefInput::updateRC(LyXRC const & rc)
478 // FIXME: can derive CB from the two EDs
479 keymapCB->setChecked(rc.use_kbmap);
480 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
481 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
482 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
483 switch (rc.scroll_wheel_zoom) {
484 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
485 scrollzoomEnableCB->setChecked(false);
487 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
488 scrollzoomEnableCB->setChecked(true);
489 scrollzoomValueCO->setCurrentIndex(0);
491 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
492 scrollzoomEnableCB->setChecked(true);
493 scrollzoomValueCO->setCurrentIndex(1);
495 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
496 scrollzoomEnableCB->setChecked(true);
497 scrollzoomValueCO->setCurrentIndex(2);
500 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
501 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
505 QString PrefInput::testKeymap(QString const & keymap)
507 return form_->browsekbmap(internalPath(keymap));
511 void PrefInput::on_firstKeymapPB_clicked(bool)
513 QString const file = testKeymap(firstKeymapED->text());
515 firstKeymapED->setText(file);
519 void PrefInput::on_secondKeymapPB_clicked(bool)
521 QString const file = testKeymap(secondKeymapED->text());
523 secondKeymapED->setText(file);
527 void PrefInput::on_keymapCB_toggled(bool keymap)
529 firstKeymapLA->setEnabled(keymap);
530 secondKeymapLA->setEnabled(keymap);
531 firstKeymapED->setEnabled(keymap);
532 secondKeymapED->setEnabled(keymap);
533 firstKeymapPB->setEnabled(keymap);
534 secondKeymapPB->setEnabled(keymap);
538 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
540 scrollzoomValueCO->setEnabled(enabled);
544 /////////////////////////////////////////////////////////////////////
548 /////////////////////////////////////////////////////////////////////
550 PrefCompletion::PrefCompletion(GuiPreferences * form)
551 : PrefModule(catEditing, N_("Input Completion"), form)
555 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
556 this, SIGNAL(changed()));
557 connect(inlineMathCB, SIGNAL(clicked()),
558 this, SIGNAL(changed()));
559 connect(inlineTextCB, SIGNAL(clicked()),
560 this, SIGNAL(changed()));
561 connect(inlineDotsCB, SIGNAL(clicked()),
562 this, SIGNAL(changed()));
563 connect(popupDelaySB, SIGNAL(valueChanged(double)),
564 this, SIGNAL(changed()));
565 connect(popupMathCB, SIGNAL(clicked()),
566 this, SIGNAL(changed()));
567 connect(autocorrectionCB, SIGNAL(clicked()),
568 this, SIGNAL(changed()));
569 connect(popupTextCB, SIGNAL(clicked()),
570 this, SIGNAL(changed()));
571 connect(popupAfterCompleteCB, SIGNAL(clicked()),
572 this, SIGNAL(changed()));
573 connect(cursorTextCB, SIGNAL(clicked()),
574 this, SIGNAL(changed()));
575 connect(minlengthSB, SIGNAL(valueChanged(int)),
576 this, SIGNAL(changed()));
580 void PrefCompletion::on_inlineTextCB_clicked()
586 void PrefCompletion::on_popupTextCB_clicked()
592 void PrefCompletion::enableCB()
594 cursorTextCB->setEnabled(
595 popupTextCB->isChecked() || inlineTextCB->isChecked());
599 void PrefCompletion::applyRC(LyXRC & rc) const
601 rc.completion_inline_delay = inlineDelaySB->value();
602 rc.completion_inline_math = inlineMathCB->isChecked();
603 rc.completion_inline_text = inlineTextCB->isChecked();
604 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
605 rc.completion_popup_delay = popupDelaySB->value();
606 rc.completion_popup_math = popupMathCB->isChecked();
607 rc.autocorrection_math = autocorrectionCB->isChecked();
608 rc.completion_popup_text = popupTextCB->isChecked();
609 rc.completion_cursor_text = cursorTextCB->isChecked();
610 rc.completion_popup_after_complete =
611 popupAfterCompleteCB->isChecked();
612 rc.completion_minlength = minlengthSB->value();
616 void PrefCompletion::updateRC(LyXRC const & rc)
618 inlineDelaySB->setValue(rc.completion_inline_delay);
619 inlineMathCB->setChecked(rc.completion_inline_math);
620 inlineTextCB->setChecked(rc.completion_inline_text);
621 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
622 popupDelaySB->setValue(rc.completion_popup_delay);
623 popupMathCB->setChecked(rc.completion_popup_math);
624 autocorrectionCB->setChecked(rc.autocorrection_math);
625 popupTextCB->setChecked(rc.completion_popup_text);
626 cursorTextCB->setChecked(rc.completion_cursor_text);
627 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
629 minlengthSB->setValue(rc.completion_minlength);
634 /////////////////////////////////////////////////////////////////////
638 /////////////////////////////////////////////////////////////////////
640 PrefLatex::PrefLatex(GuiPreferences * form)
641 : PrefModule(catOutput, N_("LaTeX"), form)
645 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
646 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
647 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
648 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
649 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
650 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
651 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
653 connect(latexChecktexED, SIGNAL(textChanged(QString)),
654 this, SIGNAL(changed()));
655 connect(latexBibtexCO, SIGNAL(activated(int)),
656 this, SIGNAL(changed()));
657 connect(latexBibtexED, SIGNAL(textChanged(QString)),
658 this, SIGNAL(changed()));
659 connect(latexJBibtexCO, SIGNAL(activated(int)),
660 this, SIGNAL(changed()));
661 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
662 this, SIGNAL(changed()));
663 connect(latexIndexCO, SIGNAL(activated(int)),
664 this, SIGNAL(changed()));
665 connect(latexIndexED, SIGNAL(textChanged(QString)),
666 this, SIGNAL(changed()));
667 connect(latexJIndexED, SIGNAL(textChanged(QString)),
668 this, SIGNAL(changed()));
669 connect(latexAutoresetCB, SIGNAL(clicked()),
670 this, SIGNAL(changed()));
671 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
672 this, SIGNAL(changed()));
673 connect(latexNomenclED, SIGNAL(textChanged(QString)),
674 this, SIGNAL(changed()));
676 #if defined(__CYGWIN__) || defined(_WIN32)
677 pathCB->setVisible(true);
678 connect(pathCB, SIGNAL(clicked()),
679 this, SIGNAL(changed()));
681 pathCB->setVisible(false);
686 void PrefLatex::on_latexBibtexCO_activated(int n)
688 QString const bibtex = latexBibtexCO->itemData(n).toString();
689 if (bibtex.isEmpty()) {
690 latexBibtexED->clear();
691 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
694 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
695 it != bibtex_alternatives.end(); ++it) {
696 QString const bib = toqstr(*it);
697 int ind = bib.indexOf(" ");
698 QString sel_command = bib.left(ind);
699 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
700 if (bibtex == sel_command) {
702 latexBibtexED->clear();
704 latexBibtexED->setText(sel_options.trimmed());
707 latexBibtexOptionsLA->setText(qt_("&Options:"));
711 void PrefLatex::on_latexJBibtexCO_activated(int n)
713 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
714 if (jbibtex.isEmpty()) {
715 latexJBibtexED->clear();
716 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
719 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
720 it != jbibtex_alternatives.end(); ++it) {
721 QString const bib = toqstr(*it);
722 int ind = bib.indexOf(" ");
723 QString sel_command = bib.left(ind);
724 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
725 if (jbibtex == sel_command) {
727 latexJBibtexED->clear();
729 latexJBibtexED->setText(sel_options.trimmed());
732 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
736 void PrefLatex::on_latexIndexCO_activated(int n)
738 QString const index = latexIndexCO->itemData(n).toString();
739 if (index.isEmpty()) {
740 latexIndexED->clear();
741 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
744 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
745 it != index_alternatives.end(); ++it) {
746 QString const idx = toqstr(*it);
747 int ind = idx.indexOf(" ");
748 QString sel_command = idx.left(ind);
749 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
750 if (index == sel_command) {
752 latexIndexED->clear();
754 latexIndexED->setText(sel_options.trimmed());
757 latexIndexOptionsLA->setText(qt_("Op&tions:"));
761 void PrefLatex::applyRC(LyXRC & rc) const
763 // If bibtex is not empty, bibopt contains the options, otherwise
764 // it is a customized bibtex command with options.
765 QString const bibtex = latexBibtexCO->itemData(
766 latexBibtexCO->currentIndex()).toString();
767 QString const bibopt = latexBibtexED->text();
768 if (bibtex.isEmpty())
769 rc.bibtex_command = fromqstr(bibopt);
770 else if (bibopt.isEmpty())
771 rc.bibtex_command = fromqstr(bibtex);
773 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
775 // If jbibtex is not empty, jbibopt contains the options, otherwise
776 // it is a customized bibtex command with options.
777 QString const jbibtex = latexJBibtexCO->itemData(
778 latexJBibtexCO->currentIndex()).toString();
779 QString const jbibopt = latexJBibtexED->text();
780 if (jbibtex.isEmpty())
781 rc.jbibtex_command = fromqstr(jbibopt);
782 else if (jbibopt.isEmpty())
783 rc.jbibtex_command = fromqstr(jbibtex);
785 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
787 // If index is not empty, idxopt contains the options, otherwise
788 // it is a customized index command with options.
789 QString const index = latexIndexCO->itemData(
790 latexIndexCO->currentIndex()).toString();
791 QString const idxopt = latexIndexED->text();
793 rc.index_command = fromqstr(idxopt);
794 else if (idxopt.isEmpty())
795 rc.index_command = fromqstr(index);
797 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
799 rc.chktex_command = fromqstr(latexChecktexED->text());
800 rc.jindex_command = fromqstr(latexJIndexED->text());
801 rc.nomencl_command = fromqstr(latexNomenclED->text());
802 rc.auto_reset_options = latexAutoresetCB->isChecked();
803 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
804 #if defined(__CYGWIN__) || defined(_WIN32)
805 rc.windows_style_tex_paths = pathCB->isChecked();
810 void PrefLatex::updateRC(LyXRC const & rc)
812 latexBibtexCO->clear();
814 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
815 latexBibtexCO->addItem(qt_("Custom"), QString());
816 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
817 it != rc.bibtex_alternatives.end(); ++it) {
818 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
819 latexBibtexCO->addItem(command, command);
822 bibtex_alternatives = rc.bibtex_alternatives;
824 QString const bib = toqstr(rc.bibtex_command);
825 int ind = bib.indexOf(" ");
826 QString sel_command = bib.left(ind);
827 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
829 int pos = latexBibtexCO->findData(sel_command);
831 latexBibtexCO->setCurrentIndex(pos);
832 latexBibtexED->setText(sel_options.trimmed());
833 latexBibtexOptionsLA->setText(qt_("&Options:"));
835 latexBibtexED->setText(toqstr(rc.bibtex_command));
836 latexBibtexCO->setCurrentIndex(0);
837 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
840 latexJBibtexCO->clear();
842 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
843 latexJBibtexCO->addItem(qt_("Custom"), QString());
844 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
845 it != rc.jbibtex_alternatives.end(); ++it) {
846 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
847 latexJBibtexCO->addItem(command, command);
850 jbibtex_alternatives = rc.jbibtex_alternatives;
852 QString const jbib = toqstr(rc.jbibtex_command);
853 ind = jbib.indexOf(" ");
854 sel_command = jbib.left(ind);
855 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
857 pos = latexJBibtexCO->findData(sel_command);
859 latexJBibtexCO->setCurrentIndex(pos);
860 latexJBibtexED->setText(sel_options.trimmed());
861 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
863 latexJBibtexED->setText(toqstr(rc.bibtex_command));
864 latexJBibtexCO->setCurrentIndex(0);
865 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
868 latexIndexCO->clear();
870 latexIndexCO->addItem(qt_("Custom"), QString());
871 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
872 it != rc.index_alternatives.end(); ++it) {
873 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
874 latexIndexCO->addItem(command, command);
877 index_alternatives = rc.index_alternatives;
879 QString const idx = toqstr(rc.index_command);
880 ind = idx.indexOf(" ");
881 sel_command = idx.left(ind);
882 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
884 pos = latexIndexCO->findData(sel_command);
886 latexIndexCO->setCurrentIndex(pos);
887 latexIndexED->setText(sel_options.trimmed());
888 latexIndexOptionsLA->setText(qt_("Op&tions:"));
890 latexIndexED->setText(toqstr(rc.index_command));
891 latexIndexCO->setCurrentIndex(0);
892 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
895 latexChecktexED->setText(toqstr(rc.chktex_command));
896 latexJIndexED->setText(toqstr(rc.jindex_command));
897 latexNomenclED->setText(toqstr(rc.nomencl_command));
898 latexAutoresetCB->setChecked(rc.auto_reset_options);
899 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
900 #if defined(__CYGWIN__) || defined(_WIN32)
901 pathCB->setChecked(rc.windows_style_tex_paths);
906 /////////////////////////////////////////////////////////////////////
910 /////////////////////////////////////////////////////////////////////
912 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
913 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
917 #if QT_VERSION < 0x050e00
918 connect(screenRomanCO, SIGNAL(activated(QString)),
919 this, SLOT(selectRoman(QString)));
920 connect(screenSansCO, SIGNAL(activated(QString)),
921 this, SLOT(selectSans(QString)));
922 connect(screenTypewriterCO, SIGNAL(activated(QString)),
923 this, SLOT(selectTypewriter(QString)));
925 connect(screenRomanCO, SIGNAL(textActivated(QString)),
926 this, SLOT(selectRoman(QString)));
927 connect(screenSansCO, SIGNAL(textActivated(QString)),
928 this, SLOT(selectSans(QString)));
929 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
930 this, SLOT(selectTypewriter(QString)));
933 #if QT_VERSION >= 0x060000
934 const QStringList families(QFontDatabase::families());
936 QFontDatabase fontdb;
937 const QStringList families(fontdb.families());
939 for (auto const & family : families) {
940 screenRomanCO->addItem(family);
941 screenSansCO->addItem(family);
942 screenTypewriterCO->addItem(family);
944 #if QT_VERSION < 0x050e00
945 connect(screenRomanCO, SIGNAL(activated(QString)),
946 this, SIGNAL(changed()));
947 connect(screenSansCO, SIGNAL(activated(QString)),
948 this, SIGNAL(changed()));
949 connect(screenTypewriterCO, SIGNAL(activated(QString)),
950 this, SIGNAL(changed()));
952 connect(screenRomanCO, SIGNAL(textActivated(QString)),
953 this, SIGNAL(changed()));
954 connect(screenSansCO, SIGNAL(textActivated(QString)),
955 this, SIGNAL(changed()));
956 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
957 this, SIGNAL(changed()));
959 connect(screenZoomSB, SIGNAL(valueChanged(int)),
960 this, SIGNAL(changed()));
961 connect(screenTinyED, SIGNAL(textChanged(QString)),
962 this, SIGNAL(changed()));
963 connect(screenSmallestED, SIGNAL(textChanged(QString)),
964 this, SIGNAL(changed()));
965 connect(screenSmallerED, SIGNAL(textChanged(QString)),
966 this, SIGNAL(changed()));
967 connect(screenSmallED, SIGNAL(textChanged(QString)),
968 this, SIGNAL(changed()));
969 connect(screenNormalED, SIGNAL(textChanged(QString)),
970 this, SIGNAL(changed()));
971 connect(screenLargeED, SIGNAL(textChanged(QString)),
972 this, SIGNAL(changed()));
973 connect(screenLargerED, SIGNAL(textChanged(QString)),
974 this, SIGNAL(changed()));
975 connect(screenLargestED, SIGNAL(textChanged(QString)),
976 this, SIGNAL(changed()));
977 connect(screenHugeED, SIGNAL(textChanged(QString)),
978 this, SIGNAL(changed()));
979 connect(screenHugerED, SIGNAL(textChanged(QString)),
980 this, SIGNAL(changed()));
982 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
983 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
984 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
985 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
986 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
987 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
988 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
989 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
990 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
991 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
995 void PrefScreenFonts::applyRC(LyXRC & rc) const
997 LyXRC const oldrc = rc;
999 parseFontName(screenRomanCO->currentText(),
1000 rc.roman_font_name, rc.roman_font_foundry);
1001 parseFontName(screenSansCO->currentText(),
1002 rc.sans_font_name, rc.sans_font_foundry);
1003 parseFontName(screenTypewriterCO->currentText(),
1004 rc.typewriter_font_name, rc.typewriter_font_foundry);
1006 rc.defaultZoom = screenZoomSB->value();
1007 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
1008 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
1009 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
1010 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
1011 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
1012 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
1013 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
1014 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
1015 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
1016 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
1020 void PrefScreenFonts::updateRC(LyXRC const & rc)
1022 setComboxFont(screenRomanCO, rc.roman_font_name,
1023 rc.roman_font_foundry);
1024 setComboxFont(screenSansCO, rc.sans_font_name,
1025 rc.sans_font_foundry);
1026 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1027 rc.typewriter_font_foundry);
1029 selectRoman(screenRomanCO->currentText());
1030 selectSans(screenSansCO->currentText());
1031 selectTypewriter(screenTypewriterCO->currentText());
1033 screenZoomSB->setValue(rc.defaultZoom);
1034 updateScreenFontSizes(rc);
1038 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1040 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1041 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1042 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1043 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1044 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1045 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1046 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1047 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1048 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1049 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1053 void PrefScreenFonts::selectRoman(const QString & name)
1055 screenRomanFE->set(QFont(name), name);
1059 void PrefScreenFonts::selectSans(const QString & name)
1061 screenSansFE->set(QFont(name), name);
1065 void PrefScreenFonts::selectTypewriter(const QString & name)
1067 screenTypewriterFE->set(QFont(name), name);
1071 /////////////////////////////////////////////////////////////////////
1075 /////////////////////////////////////////////////////////////////////
1078 PrefColors::PrefColors(GuiPreferences * form)
1079 : PrefModule(catLookAndFeel, N_("Colors"), form)
1083 // FIXME: all of this initialization should be put into the controller.
1084 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1085 // for some discussion of why that is not trivial.
1086 QPixmap icon(32, 32);
1087 for (int i = 0; i < Color_ignore; ++i) {
1088 ColorCode lc = static_cast<ColorCode>(i);
1089 if (lc == Color_none
1090 || lc == Color_black
1091 || lc == Color_white
1093 || lc == Color_brown
1095 || lc == Color_darkgray
1097 || lc == Color_green
1098 || lc == Color_lightgray
1100 || lc == Color_magenta
1101 || lc == Color_olive
1102 || lc == Color_orange
1104 || lc == Color_purple
1107 || lc == Color_violet
1108 || lc == Color_yellow
1109 || lc == Color_inherit
1110 || lc == Color_ignore)
1112 lcolors_.push_back(lc);
1114 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1115 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1116 vector<ColorCode>::const_iterator const end = lcolors_.end();
1117 for (; cit != end; ++cit) {
1118 (void) new QListWidgetItem(QIcon(icon),
1119 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1121 curcolors_.resize(lcolors_.size());
1122 newcolors_.resize(lcolors_.size());
1123 // End initialization
1125 connect(colorChangePB, SIGNAL(clicked()),
1126 this, SLOT(changeColor()));
1127 connect(colorResetPB, SIGNAL(clicked()),
1128 this, SLOT(resetColor()));
1129 connect(colorResetAllPB, SIGNAL(clicked()),
1130 this, SLOT(resetAllColor()));
1131 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1132 this, SLOT(changeLyxObjectsSelection()));
1133 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1134 this, SLOT(changeColor()));
1135 connect(syscolorsCB, SIGNAL(toggled(bool)),
1136 this, SIGNAL(changed()));
1137 connect(syscolorsCB, SIGNAL(toggled(bool)),
1138 this, SLOT(changeSysColor()));
1142 void PrefColors::applyRC(LyXRC & rc) const
1146 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1147 if (curcolors_[i] != newcolors_[i])
1148 form_->setColor(lcolors_[i], newcolors_[i]);
1149 rc.use_system_colors = syscolorsCB->isChecked();
1151 if (oldrc.use_system_colors != rc.use_system_colors)
1152 guiApp->colorCache().clear();
1156 void PrefColors::updateRC(LyXRC const & rc)
1158 for (size_type i = 0; i < lcolors_.size(); ++i) {
1159 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1160 QPixmap coloritem(32, 32);
1161 coloritem.fill(color);
1162 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1163 newcolors_[i] = curcolors_[i] = color.name();
1165 syscolorsCB->setChecked(rc.use_system_colors);
1166 changeLyxObjectsSelection();
1168 setDisabledResets();
1172 void PrefColors::changeColor()
1174 int const row = lyxObjectsLW->currentRow();
1180 QString const color = newcolors_[size_t(row)];
1181 QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1183 if (setColor(row, c, color)) {
1184 setDisabledResets();
1191 void PrefColors::resetColor()
1193 int const row = lyxObjectsLW->currentRow();
1199 QString const color = newcolors_[size_t(row)];
1200 QColor const c = getDefaultColorByRow(row);
1202 if (setColor(row, c, color)) {
1203 setDisabledResets();
1210 void PrefColors::resetAllColor()
1212 bool isChanged = false;
1214 colorResetAllPB->setDisabled(true);
1216 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1217 QString const color = newcolors_[size_t(irow)];
1218 QColor const c = getDefaultColorByRow(irow);
1220 if (setColor(irow, c, color))
1225 setDisabledResets();
1232 bool PrefColors::setColor(int const row, QColor const & new_color,
1233 QString const & old_color)
1235 if (new_color.isValid() && new_color.name() != old_color) {
1236 newcolors_[size_t(row)] = new_color.name();
1237 QPixmap coloritem(32, 32);
1238 coloritem.fill(new_color);
1239 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1246 void PrefColors::setDisabledResets()
1248 int const row = lyxObjectsLW->currentRow();
1249 // set disable reset buttons ...
1251 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1253 colorResetAllPB->setDisabled(true);
1255 // ... in between process qt events to give quicker visual feedback to the user ...
1256 guiApp->processEvents();
1258 // ... set disable Reset All button
1259 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1260 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1261 colorResetAllPB->setDisabled(false);
1262 // the break condition might hide performance issues
1263 // if a non-default color is at the top of the list
1270 bool PrefColors::isDefaultColor(int const row, QString const & color)
1272 return color == getDefaultColorByRow(row).name();
1276 QColor PrefColors::getDefaultColorByRow(int const row)
1278 ColorSet const defaultcolor;
1279 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1280 guiApp->colorCache().isDarkMode()).c_str();
1284 void PrefColors::changeSysColor()
1286 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1287 // skip colors that are taken from system palette
1288 bool const disable = syscolorsCB->isChecked()
1289 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1291 QListWidgetItem * const item = lyxObjectsLW->item(row);
1292 Qt::ItemFlags const flags = item->flags();
1295 item->setFlags(flags & ~Qt::ItemIsEnabled);
1297 item->setFlags(flags | Qt::ItemIsEnabled);
1302 void PrefColors::changeLyxObjectsSelection()
1304 int currentRow = lyxObjectsLW->currentRow();
1305 colorChangePB->setDisabled(currentRow < 0);
1308 colorResetPB->setDisabled(true);
1310 colorResetPB->setDisabled(
1311 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1315 /////////////////////////////////////////////////////////////////////
1319 /////////////////////////////////////////////////////////////////////
1321 PrefDisplay::PrefDisplay(GuiPreferences * form)
1322 : PrefModule(catLookAndFeel, N_("Display"), form)
1325 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1326 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1327 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1328 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1329 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1333 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1335 previewSizeSB->setEnabled(index != 0);
1339 void PrefDisplay::applyRC(LyXRC & rc) const
1341 switch (instantPreviewCO->currentIndex()) {
1343 rc.preview = LyXRC::PREVIEW_OFF;
1346 rc.preview = LyXRC::PREVIEW_NO_MATH;
1349 rc.preview = LyXRC::PREVIEW_ON;
1353 rc.display_graphics = displayGraphicsCB->isChecked();
1354 rc.preview_scale_factor = previewSizeSB->value();
1355 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1356 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1358 // FIXME!! The graphics cache no longer has a changeDisplay method.
1360 if (old_value != rc.display_graphics) {
1361 graphics::GCache & gc = graphics::GCache::get();
1368 void PrefDisplay::updateRC(LyXRC const & rc)
1370 switch (rc.preview) {
1371 case LyXRC::PREVIEW_OFF:
1372 instantPreviewCO->setCurrentIndex(0);
1374 case LyXRC::PREVIEW_NO_MATH :
1375 instantPreviewCO->setCurrentIndex(1);
1377 case LyXRC::PREVIEW_ON :
1378 instantPreviewCO->setCurrentIndex(2);
1382 displayGraphicsCB->setChecked(rc.display_graphics);
1383 previewSizeSB->setValue(rc.preview_scale_factor);
1384 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1385 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1386 previewSizeSB->setEnabled(
1388 && rc.preview != LyXRC::PREVIEW_OFF);
1392 /////////////////////////////////////////////////////////////////////
1396 /////////////////////////////////////////////////////////////////////
1398 PrefPaths::PrefPaths(GuiPreferences * form)
1399 : PrefModule(QString(), N_("Paths"), form)
1403 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1404 connect(workingDirED, SIGNAL(textChanged(QString)),
1405 this, SIGNAL(changed()));
1407 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1408 connect(templateDirED, SIGNAL(textChanged(QString)),
1409 this, SIGNAL(changed()));
1411 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1412 connect(exampleDirED, SIGNAL(textChanged(QString)),
1413 this, SIGNAL(changed()));
1415 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1416 connect(backupDirED, SIGNAL(textChanged(QString)),
1417 this, SIGNAL(changed()));
1419 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1420 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1421 this, SIGNAL(changed()));
1423 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1424 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1425 this, SIGNAL(changed()));
1427 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1428 connect(tempDirED, SIGNAL(textChanged(QString)),
1429 this, SIGNAL(changed()));
1431 #if defined(USE_HUNSPELL)
1432 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1433 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1434 this, SIGNAL(changed()));
1436 hunspellDirPB->setEnabled(false);
1437 hunspellDirED->setEnabled(false);
1440 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1441 this, SIGNAL(changed()));
1443 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1444 this, SIGNAL(changed()));
1446 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1447 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1451 void PrefPaths::applyRC(LyXRC & rc) const
1453 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1454 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1455 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1456 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1457 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1458 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1459 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1460 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1461 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1462 // FIXME: should be a checkbox only
1463 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1467 void PrefPaths::updateRC(LyXRC const & rc)
1469 workingDirED->setText(toqstr(external_path(rc.document_path)));
1470 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1471 templateDirED->setText(toqstr(external_path(rc.template_path)));
1472 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1473 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1474 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1475 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1476 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1477 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1478 // FIXME: should be a checkbox only
1479 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1483 void PrefPaths::selectExampledir()
1485 QString file = browseDir(internalPath(exampleDirED->text()),
1486 qt_("Select directory for example files"));
1487 if (!file.isEmpty())
1488 exampleDirED->setText(file);
1492 void PrefPaths::selectTemplatedir()
1494 QString file = browseDir(internalPath(templateDirED->text()),
1495 qt_("Select a document templates directory"));
1496 if (!file.isEmpty())
1497 templateDirED->setText(file);
1501 void PrefPaths::selectTempdir()
1503 QString file = browseDir(internalPath(tempDirED->text()),
1504 qt_("Select a temporary directory"));
1505 if (!file.isEmpty())
1506 tempDirED->setText(file);
1510 void PrefPaths::selectBackupdir()
1512 QString file = browseDir(internalPath(backupDirED->text()),
1513 qt_("Select a backups directory"));
1514 if (!file.isEmpty())
1515 backupDirED->setText(file);
1519 void PrefPaths::selectWorkingdir()
1521 QString file = browseDir(internalPath(workingDirED->text()),
1522 qt_("Select a document directory"));
1523 if (!file.isEmpty())
1524 workingDirED->setText(file);
1528 void PrefPaths::selectThesaurusdir()
1530 QString file = browseDir(internalPath(thesaurusDirED->text()),
1531 qt_("Set the path to the thesaurus dictionaries"));
1532 if (!file.isEmpty())
1533 thesaurusDirED->setText(file);
1537 void PrefPaths::selectHunspelldir()
1539 QString file = browseDir(internalPath(hunspellDirED->text()),
1540 qt_("Set the path to the Hunspell dictionaries"));
1541 if (!file.isEmpty())
1542 hunspellDirED->setText(file);
1546 void PrefPaths::selectLyxPipe()
1548 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1549 qt_("Give a filename for the LyX server pipe"));
1550 if (!file.isEmpty())
1551 lyxserverDirED->setText(file);
1555 /////////////////////////////////////////////////////////////////////
1559 /////////////////////////////////////////////////////////////////////
1561 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1562 : PrefModule(catLanguage, N_("Spellchecker"), form)
1566 // FIXME: this check should test the target platform (darwin)
1567 #if defined(USE_MACOSX_PACKAGING)
1568 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1569 #define CONNECT_APPLESPELL
1571 #undef CONNECT_APPLESPELL
1573 #if defined(USE_ASPELL)
1574 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1576 #if defined(USE_ENCHANT)
1577 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1579 #if defined(USE_HUNSPELL)
1580 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1583 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1584 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1585 this, SIGNAL(changed()));
1586 connect(altLanguageED, SIGNAL(textChanged(QString)),
1587 this, SIGNAL(changed()));
1588 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1589 this, SIGNAL(changed()));
1590 connect(compoundWordCB, SIGNAL(clicked()),
1591 this, SIGNAL(changed()));
1592 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1593 this, SIGNAL(changed()));
1594 connect(spellcheckNotesCB, SIGNAL(clicked()),
1595 this, SIGNAL(changed()));
1597 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1598 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1600 spellcheckerCB->setEnabled(false);
1601 altLanguageED->setEnabled(false);
1602 escapeCharactersED->setEnabled(false);
1603 compoundWordCB->setEnabled(false);
1604 spellcheckContinuouslyCB->setEnabled(false);
1605 spellcheckNotesCB->setEnabled(false);
1610 void PrefSpellchecker::applyRC(LyXRC & rc) const
1612 string const speller = fromqstr(spellcheckerCB->
1613 itemData(spellcheckerCB->currentIndex()).toString());
1614 if (!speller.empty())
1615 rc.spellchecker = speller;
1616 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1617 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1618 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1619 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1620 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1624 void PrefSpellchecker::updateRC(LyXRC const & rc)
1626 spellcheckerCB->setCurrentIndex(
1627 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1628 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1629 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1630 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1631 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1632 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1636 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1638 QString spellchecker = spellcheckerCB->itemData(index).toString();
1640 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1645 /////////////////////////////////////////////////////////////////////
1649 /////////////////////////////////////////////////////////////////////
1652 PrefConverters::PrefConverters(GuiPreferences * form)
1653 : PrefModule(catFiles, N_("Converters"), form)
1657 connect(converterNewPB, SIGNAL(clicked()),
1658 this, SLOT(updateConverter()));
1659 connect(converterRemovePB, SIGNAL(clicked()),
1660 this, SLOT(removeConverter()));
1661 connect(converterModifyPB, SIGNAL(clicked()),
1662 this, SLOT(updateConverter()));
1663 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1664 this, SLOT(switchConverter()));
1665 #if QT_VERSION < 0x050e00
1666 connect(converterFromCO, SIGNAL(activated(QString)),
1667 this, SLOT(changeConverter()));
1668 connect(converterToCO, SIGNAL(activated(QString)),
1669 this, SLOT(changeConverter()));
1671 connect(converterFromCO, SIGNAL(textActivated(QString)),
1672 this, SLOT(changeConverter()));
1673 connect(converterToCO, SIGNAL(textActivated(QString)),
1674 this, SLOT(changeConverter()));
1676 connect(converterED, SIGNAL(textEdited(QString)),
1677 this, SLOT(changeConverter()));
1678 connect(converterFlagED, SIGNAL(textEdited(QString)),
1679 this, SLOT(changeConverter()));
1680 connect(converterNewPB, SIGNAL(clicked()),
1681 this, SIGNAL(changed()));
1682 connect(converterRemovePB, SIGNAL(clicked()),
1683 this, SIGNAL(changed()));
1684 connect(converterModifyPB, SIGNAL(clicked()),
1685 this, SIGNAL(changed()));
1686 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1687 this, SIGNAL(changed()));
1688 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1689 this, SIGNAL(changed()));
1691 converterED->setValidator(new NoNewLineValidator(converterED));
1692 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1693 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1694 //converterDefGB->setFocusProxy(convertersLW);
1698 void PrefConverters::applyRC(LyXRC & rc) const
1700 rc.use_converter_cache = cacheCB->isChecked();
1701 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1702 rc.use_converter_needauth = needauthCB->isChecked();
1703 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1707 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1708 cb->blockSignals(true);
1709 cb->setChecked(checked);
1710 cb->blockSignals(false);
1714 void PrefConverters::updateRC(LyXRC const & rc)
1716 cacheCB->setChecked(rc.use_converter_cache);
1717 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1718 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1720 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1725 void PrefConverters::updateGui()
1727 QString const pattern("%1 -> %2");
1728 form_->formats().sort();
1729 form_->converters().update(form_->formats());
1730 // save current selection
1733 .arg(converterFromCO->currentText())
1734 .arg(converterToCO->currentText());
1736 converterFromCO->clear();
1737 converterToCO->clear();
1739 for (Format const & f : form_->formats()) {
1740 QString const name = toqstr(translateIfPossible(f.prettyname()));
1741 converterFromCO->addItem(name);
1742 converterToCO->addItem(name);
1745 // currentRowChanged(int) is also triggered when updating the listwidget
1746 // block signals to avoid unnecessary calls to switchConverter()
1747 convertersLW->blockSignals(true);
1748 convertersLW->clear();
1750 for (Converter const & c : form_->converters()) {
1751 QString const name =
1753 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1754 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1755 int type = form_->converters().getNumber(c.From()->name(),
1757 new QListWidgetItem(name, convertersLW, type);
1759 convertersLW->sortItems(Qt::AscendingOrder);
1760 convertersLW->blockSignals(false);
1762 // restore selection
1763 if (current != pattern.arg(QString()).arg(QString())) {
1764 QList<QListWidgetItem *> const item =
1765 convertersLW->findItems(current, Qt::MatchExactly);
1766 if (!item.isEmpty())
1767 convertersLW->setCurrentItem(item.at(0));
1770 // select first element if restoring failed
1771 if (convertersLW->currentRow() == -1)
1772 convertersLW->setCurrentRow(0);
1778 void PrefConverters::switchConverter()
1780 int const cnr = convertersLW->currentItem()->type();
1781 Converter const & c(form_->converters().get(cnr));
1782 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1783 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1784 converterED->setText(toqstr(c.command()));
1785 converterFlagED->setText(toqstr(c.flags()));
1791 void PrefConverters::changeConverter()
1797 void PrefConverters::updateButtons()
1799 if (form_->formats().empty())
1801 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1802 Format const & to = form_->formats().get(converterToCO->currentIndex());
1803 int const sel = form_->converters().getNumber(from.name(), to.name());
1804 bool const known = sel >= 0;
1805 bool const valid = !(converterED->text().isEmpty()
1806 || from.name() == to.name());
1811 if (convertersLW->count() > 0) {
1812 int const cnr = convertersLW->currentItem()->type();
1813 Converter const & c = form_->converters().get(cnr);
1814 old_command = c.command();
1815 old_flag = c.flags();
1818 string const new_command = fromqstr(converterED->text());
1819 string const new_flag = fromqstr(converterFlagED->text());
1821 bool modified = (old_command != new_command || old_flag != new_flag);
1823 converterModifyPB->setEnabled(valid && known && modified);
1824 converterNewPB->setEnabled(valid && !known);
1825 converterRemovePB->setEnabled(known);
1827 maxAgeLE->setEnabled(cacheCB->isChecked());
1828 maxAgeLA->setEnabled(cacheCB->isChecked());
1833 // specify unique from/to or it doesn't appear. This is really bad UI
1834 // this is why we can use the same function for both new and modify
1835 void PrefConverters::updateConverter()
1837 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1838 Format const & to = form_->formats().get(converterToCO->currentIndex());
1839 string const flags = fromqstr(converterFlagED->text());
1840 string const command = fromqstr(converterED->text());
1842 Converter const * old =
1843 form_->converters().getConverter(from.name(), to.name());
1844 form_->converters().add(from.name(), to.name(), command, flags);
1847 form_->converters().updateLast(form_->formats());
1851 // Remove all files created by this converter from the cache, since
1852 // the modified converter might create different files.
1853 ConverterCache::get().remove_all(from.name(), to.name());
1857 void PrefConverters::removeConverter()
1859 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1860 Format const & to = form_->formats().get(converterToCO->currentIndex());
1861 form_->converters().erase(from.name(), to.name());
1865 // Remove all files created by this converter from the cache, since
1866 // a possible new converter might create different files.
1867 ConverterCache::get().remove_all(from.name(), to.name());
1871 void PrefConverters::on_cacheCB_stateChanged(int state)
1873 maxAgeLE->setEnabled(state == Qt::Checked);
1874 maxAgeLA->setEnabled(state == Qt::Checked);
1879 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1881 needauthCB->setEnabled(!checked);
1885 void PrefConverters::on_needauthCB_toggled(bool checked)
1892 int ret = frontend::Alert::prompt(
1893 _("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!"),
1894 0, 0, _("&No"), _("&Yes"));
1898 setCheckboxBlockSignals(needauthCB, true);
1902 /////////////////////////////////////////////////////////////////////
1906 /////////////////////////////////////////////////////////////////////
1908 class FormatValidator : public QValidator
1911 FormatValidator(QWidget *, Formats const & f);
1912 void fixup(QString & input) const override;
1913 QValidator::State validate(QString & input, int & pos) const override;
1915 virtual QString toString(Format const & format) const = 0;
1917 Formats const & formats_;
1921 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1922 : QValidator(parent), formats_(f)
1927 void FormatValidator::fixup(QString & input) const
1929 Formats::const_iterator cit = formats_.begin();
1930 Formats::const_iterator end = formats_.end();
1931 for (; cit != end; ++cit) {
1932 QString const name = toString(*cit);
1933 if (distance(formats_.begin(), cit) == nr()) {
1941 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1943 Formats::const_iterator cit = formats_.begin();
1944 Formats::const_iterator end = formats_.end();
1945 bool unknown = true;
1946 for (; unknown && cit != end; ++cit) {
1947 QString const name = toString(*cit);
1948 if (distance(formats_.begin(), cit) != nr())
1949 unknown = name != input;
1952 if (unknown && !input.isEmpty())
1953 return QValidator::Acceptable;
1955 return QValidator::Intermediate;
1959 int FormatValidator::nr() const
1961 QComboBox * p = qobject_cast<QComboBox *>(parent());
1962 return p->itemData(p->currentIndex()).toInt();
1966 /////////////////////////////////////////////////////////////////////
1968 // FormatNameValidator
1970 /////////////////////////////////////////////////////////////////////
1972 class FormatNameValidator : public FormatValidator
1975 FormatNameValidator(QWidget * parent, Formats const & f)
1976 : FormatValidator(parent, f)
1979 QString toString(Format const & format) const override
1981 return toqstr(format.name());
1986 /////////////////////////////////////////////////////////////////////
1988 // FormatPrettynameValidator
1990 /////////////////////////////////////////////////////////////////////
1992 class FormatPrettynameValidator : public FormatValidator
1995 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1996 : FormatValidator(parent, f)
1999 QString toString(Format const & format) const override
2001 return toqstr(translateIfPossible(format.prettyname()));
2006 /////////////////////////////////////////////////////////////////////
2010 /////////////////////////////////////////////////////////////////////
2012 PrefFileformats::PrefFileformats(GuiPreferences * form)
2013 : PrefModule(catFiles, N_("File Formats"), form)
2017 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2018 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2019 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2020 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2021 editorED->setValidator(new NoNewLineValidator(editorED));
2022 viewerED->setValidator(new NoNewLineValidator(viewerED));
2023 copierED->setValidator(new NoNewLineValidator(copierED));
2025 connect(documentCB, SIGNAL(clicked()),
2026 this, SLOT(setFlags()));
2027 connect(vectorCB, SIGNAL(clicked()),
2028 this, SLOT(setFlags()));
2029 connect(exportMenuCB, SIGNAL(clicked()),
2030 this, SLOT(setFlags()));
2031 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2032 this, SLOT(updatePrettyname()));
2033 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2034 this, SIGNAL(changed()));
2035 #if QT_VERSION < 0x050e00
2036 connect(defaultFormatCB, SIGNAL(activated(QString)),
2037 this, SIGNAL(changed()));
2038 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2039 this, SIGNAL(changed()));
2040 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2041 this, SIGNAL(changed()));
2043 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2044 this, SIGNAL(changed()));
2045 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2046 this, SIGNAL(changed()));
2047 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2048 this, SIGNAL(changed()));
2050 connect(viewerCO, SIGNAL(activated(int)),
2051 this, SIGNAL(changed()));
2052 connect(editorCO, SIGNAL(activated(int)),
2053 this, SIGNAL(changed()));
2059 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2061 if (shortcut.empty())
2064 string l10n_format =
2065 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2066 return split(l10n_format, '|');
2072 void PrefFileformats::applyRC(LyXRC & rc) const
2074 QString const default_format = defaultFormatCB->itemData(
2075 defaultFormatCB->currentIndex()).toString();
2076 rc.default_view_format = fromqstr(default_format);
2077 QString const default_otf_format = defaultOTFFormatCB->itemData(
2078 defaultOTFFormatCB->currentIndex()).toString();
2079 rc.default_otf_view_format = fromqstr(default_otf_format);
2080 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2081 defaultPlatexFormatCB->currentIndex()).toString();
2082 rc.default_platex_view_format = fromqstr(default_platex_format);
2086 void PrefFileformats::updateRC(LyXRC const & rc)
2088 viewer_alternatives = rc.viewer_alternatives;
2089 editor_alternatives = rc.editor_alternatives;
2090 bool const init = defaultFormatCB->currentText().isEmpty();
2094 defaultFormatCB->findData(toqstr(rc.default_view_format));
2095 defaultFormatCB->setCurrentIndex(pos);
2096 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2097 defaultOTFFormatCB->setCurrentIndex(pos);
2098 defaultOTFFormatCB->setCurrentIndex(pos);
2099 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2100 defaultPlatexFormatCB->setCurrentIndex(pos);
2101 defaultPlatexFormatCB->setCurrentIndex(pos);
2106 void PrefFileformats::updateView()
2108 QString const current = formatsCB->currentText();
2109 QString const current_def = defaultFormatCB->currentText();
2110 QString const current_def_otf = defaultOTFFormatCB->currentText();
2111 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2113 // update comboboxes with formats
2114 formatsCB->blockSignals(true);
2115 defaultFormatCB->blockSignals(true);
2116 defaultOTFFormatCB->blockSignals(true);
2117 defaultPlatexFormatCB->blockSignals(true);
2119 defaultFormatCB->clear();
2120 defaultOTFFormatCB->clear();
2121 defaultPlatexFormatCB->clear();
2122 form_->formats().sort();
2123 for (Format const & f : form_->formats()) {
2124 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2125 formatsCB->addItem(prettyname,
2126 QVariant(form_->formats().getNumber(f.name())));
2127 if (f.viewer().empty())
2129 if (form_->converters().isReachable("xhtml", f.name())
2130 || form_->converters().isReachable("dviluatex", f.name())
2131 || form_->converters().isReachable("luatex", f.name())
2132 || form_->converters().isReachable("xetex", f.name())) {
2133 defaultFormatCB->addItem(prettyname,
2134 QVariant(toqstr(f.name())));
2135 defaultOTFFormatCB->addItem(prettyname,
2136 QVariant(toqstr(f.name())));
2138 if (form_->converters().isReachable("latex", f.name())
2139 || form_->converters().isReachable("pdflatex", f.name()))
2140 defaultFormatCB->addItem(prettyname,
2141 QVariant(toqstr(f.name())));
2142 if (form_->converters().isReachable("platex", f.name()))
2143 defaultPlatexFormatCB->addItem(prettyname,
2144 QVariant(toqstr(f.name())));
2148 // restore selections
2149 int item = formatsCB->findText(current, Qt::MatchExactly);
2150 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2151 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2152 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2153 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2154 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2155 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2156 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2157 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2158 formatsCB->blockSignals(false);
2159 defaultFormatCB->blockSignals(false);
2160 defaultOTFFormatCB->blockSignals(false);
2161 defaultPlatexFormatCB->blockSignals(false);
2165 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2167 if (form_->formats().empty())
2169 int const nr = formatsCB->itemData(i).toInt();
2170 Format const f = form_->formats().get(nr);
2172 formatED->setText(toqstr(f.name()));
2173 copierED->setText(toqstr(form_->movers().command(f.name())));
2174 extensionsED->setText(toqstr(f.extensions()));
2175 mimeED->setText(toqstr(f.mime()));
2176 shortcutED->setText(
2177 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2178 documentCB->setChecked((f.documentFormat()));
2179 vectorCB->setChecked((f.vectorFormat()));
2180 exportMenuCB->setChecked((f.inExportMenu()));
2181 exportMenuCB->setEnabled((f.documentFormat()));
2187 void PrefFileformats::setFlags()
2189 int flags = Format::none;
2190 if (documentCB->isChecked())
2191 flags |= Format::document;
2192 if (vectorCB->isChecked())
2193 flags |= Format::vector;
2194 if (exportMenuCB->isChecked())
2195 flags |= Format::export_menu;
2196 currentFormat().setFlags(flags);
2197 exportMenuCB->setEnabled(documentCB->isChecked());
2202 void PrefFileformats::on_copierED_textEdited(const QString & s)
2204 string const fmt = fromqstr(formatED->text());
2205 form_->movers().set(fmt, fromqstr(s));
2210 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2212 currentFormat().setExtensions(fromqstr(s));
2217 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2219 currentFormat().setViewer(fromqstr(s));
2224 void PrefFileformats::on_editorED_textEdited(const QString & s)
2226 currentFormat().setEditor(fromqstr(s));
2231 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2233 currentFormat().setMime(fromqstr(s));
2238 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2240 string const new_shortcut = fromqstr(s);
2241 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2242 currentFormat().shortcut()))
2244 currentFormat().setShortcut(new_shortcut);
2249 void PrefFileformats::on_formatED_editingFinished()
2251 string const newname = fromqstr(formatED->displayText());
2252 string const oldname = currentFormat().name();
2253 if (newname == oldname)
2255 if (form_->converters().formatIsUsed(oldname)) {
2256 Alert::error(_("Format in use"),
2257 _("You cannot change a format's short name "
2258 "if the format is used by a converter. "
2259 "Please remove the converter first."));
2264 currentFormat().setName(newname);
2269 void PrefFileformats::on_formatED_textChanged(const QString &)
2271 QString t = formatED->text();
2273 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2274 setValid(formatLA, valid);
2278 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2280 QString t = formatsCB->currentText();
2282 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2283 setValid(formatsLA, valid);
2287 void PrefFileformats::updatePrettyname()
2289 QString const newname = formatsCB->currentText();
2290 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2293 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2301 void updateComboBox(LyXRC::Alternatives const & alts,
2302 string const & fmt, QComboBox * combo)
2304 LyXRC::Alternatives::const_iterator it =
2306 if (it != alts.end()) {
2307 LyXRC::CommandSet const & cmds = it->second;
2308 LyXRC::CommandSet::const_iterator sit =
2310 LyXRC::CommandSet::const_iterator const sen =
2312 for (; sit != sen; ++sit) {
2313 QString const qcmd = toqstr(*sit);
2314 combo->addItem(qcmd, qcmd);
2321 void PrefFileformats::updateViewers()
2323 Format const f = currentFormat();
2324 viewerCO->blockSignals(true);
2326 viewerCO->addItem(qt_("None"), QString());
2327 if (os::canAutoOpenFile(f.extension(), os::VIEW))
2328 viewerCO->addItem(qt_("System Default"), QString("auto"));
2329 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2330 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2331 viewerCO->blockSignals(false);
2333 int pos = viewerCO->findData(toqstr(f.viewer()));
2336 viewerED->setEnabled(false);
2337 viewerCO->setCurrentIndex(pos);
2339 viewerED->setEnabled(true);
2340 viewerED->setText(toqstr(f.viewer()));
2341 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2346 void PrefFileformats::updateEditors()
2348 Format const f = currentFormat();
2349 editorCO->blockSignals(true);
2351 editorCO->addItem(qt_("None"), QString());
2352 if (os::canAutoOpenFile(f.extension(), os::EDIT))
2353 editorCO->addItem(qt_("System Default"), QString("auto"));
2354 updateComboBox(editor_alternatives, f.name(), editorCO);
2355 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2356 editorCO->blockSignals(false);
2358 int pos = editorCO->findData(toqstr(f.editor()));
2361 editorED->setEnabled(false);
2362 editorCO->setCurrentIndex(pos);
2364 editorED->setEnabled(true);
2365 editorED->setText(toqstr(f.editor()));
2366 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2371 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2373 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2374 viewerED->setEnabled(custom);
2376 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2380 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2382 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2383 editorED->setEnabled(custom);
2385 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2389 Format & PrefFileformats::currentFormat()
2391 int const i = formatsCB->currentIndex();
2392 int const nr = formatsCB->itemData(i).toInt();
2393 return form_->formats().get(nr);
2397 void PrefFileformats::on_formatNewPB_clicked()
2399 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2401 formatsCB->setCurrentIndex(0);
2402 formatsCB->setFocus(Qt::OtherFocusReason);
2406 void PrefFileformats::on_formatRemovePB_clicked()
2408 int const i = formatsCB->currentIndex();
2409 int const nr = formatsCB->itemData(i).toInt();
2410 string const current_text = form_->formats().get(nr).name();
2411 if (form_->converters().formatIsUsed(current_text)) {
2412 Alert::error(_("Format in use"),
2413 _("Cannot remove a Format used by a Converter. "
2414 "Remove the converter first."));
2418 form_->formats().erase(current_text);
2421 on_formatsCB_editTextChanged(formatsCB->currentText());
2426 /////////////////////////////////////////////////////////////////////
2430 /////////////////////////////////////////////////////////////////////
2432 PrefLanguage::PrefLanguage(GuiPreferences * form)
2433 : PrefModule(catLanguage, N_("Language"), form)
2437 connect(visualCursorRB, SIGNAL(clicked()),
2438 this, SIGNAL(changed()));
2439 connect(logicalCursorRB, SIGNAL(clicked()),
2440 this, SIGNAL(changed()));
2441 connect(markForeignCB, SIGNAL(clicked()),
2442 this, SIGNAL(changed()));
2443 connect(respectOSkbdCB, SIGNAL(clicked()),
2444 this, SIGNAL(changed()));
2445 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2446 this, SIGNAL(changed()));
2447 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2448 this, SIGNAL(changed()));
2449 connect(languagePackageCO, SIGNAL(activated(int)),
2450 this, SIGNAL(changed()));
2451 connect(languagePackageED, SIGNAL(textChanged(QString)),
2452 this, SIGNAL(changed()));
2453 connect(globalCB, SIGNAL(clicked()),
2454 this, SIGNAL(changed()));
2455 connect(startCommandED, SIGNAL(textChanged(QString)),
2456 this, SIGNAL(changed()));
2457 connect(endCommandED, SIGNAL(textChanged(QString)),
2458 this, SIGNAL(changed()));
2459 connect(uiLanguageCO, SIGNAL(activated(int)),
2460 this, SIGNAL(changed()));
2461 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2462 this, SIGNAL(changed()));
2463 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2464 this, SIGNAL(changed()));
2465 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2466 this, SIGNAL(changed()));
2468 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2469 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2470 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2472 #if QT_VERSION < 0x060000
2473 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2475 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2477 defaultDecimalSepED->setMaxLength(1);
2479 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2480 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2482 QAbstractItemModel * language_model = guiApp->languageModel();
2483 language_model->sort(0);
2484 uiLanguageCO->blockSignals(true);
2485 uiLanguageCO->clear();
2486 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2487 for (int i = 0; i != language_model->rowCount(); ++i) {
2488 QModelIndex index = language_model->index(i, 0);
2489 // Filter the list based on the available translation and add
2490 // each language code only once
2491 string const name = fromqstr(index.data(Qt::UserRole).toString());
2492 Language const * lang = languages.getLanguage(name);
2495 // never remove the currently selected language
2496 if (name != form->rc().gui_language
2497 && name != lyxrc.gui_language
2498 && (!Messages::available(lang->code())
2499 || !lang->hasGuiSupport()))
2501 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2502 index.data(Qt::UserRole).toString());
2504 uiLanguageCO->blockSignals(false);
2506 // FIXME: restore this when it works (see discussion in #6450).
2507 respectOSkbdCB->hide();
2511 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2513 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2514 qt_("The change of user interface language will be fully "
2515 "effective only after a restart."));
2519 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2522 languagePackageED->setText(save_langpack_);
2523 else if (!languagePackageED->text().isEmpty()) {
2524 save_langpack_ = languagePackageED->text();
2525 languagePackageED->clear();
2527 languagePackageED->setEnabled(i == 2);
2531 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2533 defaultDecimalSepED->setEnabled(i == 1);
2537 void PrefLanguage::applyRC(LyXRC & rc) const
2539 rc.visual_cursor = visualCursorRB->isChecked();
2540 rc.mark_foreign_language = markForeignCB->isChecked();
2541 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2542 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2543 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2544 int const p = languagePackageCO->currentIndex();
2546 rc.language_package_selection = LyXRC::LP_AUTO;
2548 rc.language_package_selection = LyXRC::LP_BABEL;
2550 rc.language_package_selection = LyXRC::LP_CUSTOM;
2552 rc.language_package_selection = LyXRC::LP_NONE;
2553 rc.language_custom_package = fromqstr(languagePackageED->text());
2554 rc.language_global_options = globalCB->isChecked();
2555 rc.language_command_begin = fromqstr(startCommandED->text());
2556 rc.language_command_end = fromqstr(endCommandED->text());
2557 rc.gui_language = fromqstr(
2558 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2559 if (defaultDecimalSepCO->currentIndex() == 0)
2560 rc.default_decimal_sep = "locale";
2562 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2563 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2567 void PrefLanguage::updateRC(LyXRC const & rc)
2569 if (rc.visual_cursor)
2570 visualCursorRB->setChecked(true);
2572 logicalCursorRB->setChecked(true);
2573 markForeignCB->setChecked(rc.mark_foreign_language);
2574 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2575 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2576 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2577 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2578 if (languagePackageCO->currentIndex() == 2) {
2579 languagePackageED->setText(toqstr(rc.language_custom_package));
2580 languagePackageED->setEnabled(true);
2582 languagePackageED->clear();
2583 save_langpack_ = toqstr(rc.language_custom_package);
2584 languagePackageED->setEnabled(false);
2586 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2587 globalCB->setChecked(rc.language_global_options);
2588 startCommandED->setText(toqstr(rc.language_command_begin));
2589 endCommandED->setText(toqstr(rc.language_command_end));
2590 if (rc.default_decimal_sep == "locale") {
2591 defaultDecimalSepCO->setCurrentIndex(0);
2592 defaultDecimalSepED->clear();
2594 defaultDecimalSepCO->setCurrentIndex(1);
2595 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2597 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2598 defaultLengthUnitCO->setCurrentIndex(pos);
2600 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2601 uiLanguageCO->blockSignals(true);
2602 uiLanguageCO->setCurrentIndex(pos);
2603 uiLanguageCO->blockSignals(false);
2607 /////////////////////////////////////////////////////////////////////
2609 // PrefUserInterface
2611 /////////////////////////////////////////////////////////////////////
2613 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2614 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2618 connect(uiFilePB, SIGNAL(clicked()),
2619 this, SLOT(selectUi()));
2620 connect(uiFileED, SIGNAL(textChanged(QString)),
2621 this, SIGNAL(changed()));
2622 connect(iconSetCO, SIGNAL(activated(int)),
2623 this, SIGNAL(changed()));
2624 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2625 this, SIGNAL(changed()));
2626 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2627 this, SIGNAL(changed()));
2628 connect(tooltipCB, SIGNAL(toggled(bool)),
2629 this, SIGNAL(changed()));
2630 lastfilesSB->setMaximum(maxlastfiles);
2632 iconSetCO->addItem(qt_("Default"), QString());
2633 iconSetCO->addItem(qt_("Classic"), "classic");
2634 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2636 if (guiApp->platformName() != "xcb"
2637 && !guiApp->platformName().contains("wayland"))
2638 useSystemThemeIconsCB->hide();
2642 void PrefUserInterface::applyRC(LyXRC & rc) const
2644 rc.icon_set = fromqstr(iconSetCO->itemData(
2645 iconSetCO->currentIndex()).toString());
2647 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2648 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2649 rc.num_lastfiles = lastfilesSB->value();
2650 rc.use_tooltip = tooltipCB->isChecked();
2654 void PrefUserInterface::updateRC(LyXRC const & rc)
2656 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2659 iconSetCO->setCurrentIndex(iconset);
2660 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2661 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2662 lastfilesSB->setValue(rc.num_lastfiles);
2663 tooltipCB->setChecked(rc.use_tooltip);
2667 void PrefUserInterface::selectUi()
2669 QString file = form_->browseUI(internalPath(uiFileED->text()));
2670 if (!file.isEmpty())
2671 uiFileED->setText(file);
2675 /////////////////////////////////////////////////////////////////////
2677 // PrefDocumentHandling
2679 /////////////////////////////////////////////////////////////////////
2681 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2682 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2686 connect(autoSaveCB, SIGNAL(toggled(bool)),
2687 autoSaveSB, SLOT(setEnabled(bool)));
2688 connect(autoSaveCB, SIGNAL(toggled(bool)),
2689 TextLabel1, SLOT(setEnabled(bool)));
2690 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2691 this, SIGNAL(changed()));
2692 connect(singleInstanceCB, SIGNAL(clicked()),
2693 this, SIGNAL(changed()));
2694 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2695 this, SIGNAL(changed()));
2696 connect(closeLastViewCO, SIGNAL(activated(int)),
2697 this, SIGNAL(changed()));
2698 connect(restoreCursorCB, SIGNAL(clicked()),
2699 this, SIGNAL(changed()));
2700 connect(loadSessionCB, SIGNAL(clicked()),
2701 this, SIGNAL(changed()));
2702 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2703 this, SIGNAL(changed()));
2704 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2705 this, SIGNAL(changed()));
2706 connect(autoSaveCB, SIGNAL(clicked()),
2707 this, SIGNAL(changed()));
2708 connect(backupCB, SIGNAL(clicked()),
2709 this, SIGNAL(changed()));
2710 connect(saveCompressedCB, SIGNAL(clicked()),
2711 this, SIGNAL(changed()));
2712 connect(saveOriginCB, SIGNAL(clicked()),
2713 this, SIGNAL(changed()));
2717 void PrefDocHandling::applyRC(LyXRC & rc) const
2719 rc.use_lastfilepos = restoreCursorCB->isChecked();
2720 rc.load_session = loadSessionCB->isChecked();
2721 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2722 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2723 rc.make_backup = backupCB->isChecked();
2724 rc.save_compressed = saveCompressedCB->isChecked();
2725 rc.save_origin = saveOriginCB->isChecked();
2726 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2727 rc.single_instance = singleInstanceCB->isChecked();
2728 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2730 switch (closeLastViewCO->currentIndex()) {
2732 rc.close_buffer_with_last_view = "yes";
2735 rc.close_buffer_with_last_view = "no";
2738 rc.close_buffer_with_last_view = "ask";
2746 void PrefDocHandling::updateRC(LyXRC const & rc)
2748 restoreCursorCB->setChecked(rc.use_lastfilepos);
2749 loadSessionCB->setChecked(rc.load_session);
2750 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2751 // convert to minutes
2752 bool autosave = rc.autosave > 0;
2753 int mins = rc.autosave / 60;
2756 autoSaveSB->setValue(mins);
2757 autoSaveCB->setChecked(autosave);
2758 autoSaveSB->setEnabled(autosave);
2759 backupCB->setChecked(rc.make_backup);
2760 saveCompressedCB->setChecked(rc.save_compressed);
2761 saveOriginCB->setChecked(rc.save_origin);
2762 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2763 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2764 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2765 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2766 if (rc.close_buffer_with_last_view == "yes")
2767 closeLastViewCO->setCurrentIndex(0);
2768 else if (rc.close_buffer_with_last_view == "no")
2769 closeLastViewCO->setCurrentIndex(1);
2770 else if (rc.close_buffer_with_last_view == "ask")
2771 closeLastViewCO->setCurrentIndex(2);
2775 void PrefDocHandling::on_clearSessionPB_clicked()
2777 guiApp->clearSession();
2782 /////////////////////////////////////////////////////////////////////
2786 /////////////////////////////////////////////////////////////////////
2788 PrefEdit::PrefEdit(GuiPreferences * form)
2789 : PrefModule(catEditing, N_("Control"), form)
2793 connect(cursorFollowsCB, SIGNAL(clicked()),
2794 this, SIGNAL(changed()));
2795 connect(scrollBelowCB, SIGNAL(clicked()),
2796 this, SIGNAL(changed()));
2797 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2798 this, SIGNAL(changed()));
2799 connect(copyCTMarkupCB, SIGNAL(clicked()),
2800 this, SIGNAL(changed()));
2801 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2802 this, SIGNAL(changed()));
2803 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2804 this, SIGNAL(changed()));
2805 connect(macroEditStyleCO, SIGNAL(activated(int)),
2806 this, SIGNAL(changed()));
2807 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2808 this, SIGNAL(changed()));
2809 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2810 this, SIGNAL(changed()));
2811 connect(screenWidthLE, SIGNAL(textChanged(QString)),
2812 this, SIGNAL(changed()));
2813 connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
2814 this, SIGNAL(changed()));
2815 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2816 this, SIGNAL(changed()));
2817 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2818 this, SIGNAL(changed()));
2819 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2820 this, SIGNAL(changed()));
2821 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2822 this, SIGNAL(changed()));
2823 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2824 this, SIGNAL(changed()));
2828 void PrefEdit::on_screenLimitCB_toggled(bool const state)
2830 screenWidthLE->setEnabled(state);
2831 screenWidthUnitCO->setEnabled(state);
2836 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2838 citationSearchLE->setEnabled(state);
2839 citationSearchLA->setEnabled(state);
2844 void PrefEdit::applyRC(LyXRC & rc) const
2846 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2847 rc.scroll_below_document = scrollBelowCB->isChecked();
2848 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2849 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2850 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2851 rc.group_layouts = groupEnvironmentsCB->isChecked();
2852 switch (macroEditStyleCO->currentIndex()) {
2853 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2854 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2855 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2857 rc.cursor_width = cursorWidthSB->value();
2858 rc.citation_search = citationSearchCB->isChecked();
2859 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2860 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2861 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2862 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2863 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2864 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2865 rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO));
2866 rc.screen_limit = screenLimitCB->isChecked();
2870 void PrefEdit::updateRC(LyXRC const & rc)
2872 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2873 scrollBelowCB->setChecked(rc.scroll_below_document);
2874 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2875 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2876 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2877 groupEnvironmentsCB->setChecked(rc.group_layouts);
2878 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2879 cursorWidthSB->setValue(rc.cursor_width);
2880 citationSearchCB->setChecked(rc.citation_search);
2881 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2882 citationSearchLE->setEnabled(rc.citation_search);
2883 citationSearchLA->setEnabled(rc.citation_search);
2884 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2885 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2886 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2887 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2888 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2889 lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
2890 screenWidthUnitCO->setEnabled(rc.screen_limit);
2891 screenLimitCB->setChecked(rc.screen_limit);
2892 screenWidthLE->setEnabled(rc.screen_limit);
2896 /////////////////////////////////////////////////////////////////////
2900 /////////////////////////////////////////////////////////////////////
2903 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2905 Ui::shortcutUi::setupUi(this);
2906 QDialog::setModal(true);
2907 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2911 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2912 : PrefModule(catEditing, N_("Shortcuts"), form),
2913 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2914 systemItem_(nullptr)
2918 shortcutsTW->setColumnCount(2);
2919 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2920 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2921 shortcutsTW->setSortingEnabled(true);
2922 // Multi-selection can be annoying.
2923 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2925 connect(bindFilePB, SIGNAL(clicked()),
2926 this, SLOT(selectBind()));
2927 connect(bindFileED, SIGNAL(textChanged(QString)),
2928 this, SIGNAL(changed()));
2930 shortcut_ = new GuiShortcutDialog(this);
2931 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2932 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2933 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2935 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2936 this, SIGNAL(changed()));
2937 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2938 shortcut_, SLOT(reject()));
2939 connect(shortcut_->clearPB, SIGNAL(clicked()),
2940 this, SLOT(shortcutClearPressed()));
2941 connect(shortcut_->removePB, SIGNAL(clicked()),
2942 this, SLOT(shortcutRemovePressed()));
2943 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2944 this, SLOT(shortcutOkPressed()));
2945 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2946 this, SLOT(shortcutCancelPressed()));
2950 void PrefShortcuts::applyRC(LyXRC & rc) const
2952 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2953 // write user_bind and user_unbind to .lyx/bind/user.bind
2954 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2955 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2956 lyxerr << "LyX could not create the user bind directory '"
2957 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2960 if (!bind_dir.isDirWritable()) {
2961 lyxerr << "LyX could not write to the user bind directory '"
2962 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2965 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2966 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2967 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2968 // immediately apply the keybindings. Why this is not done before?
2969 // The good thing is that the menus are updated automatically.
2970 theTopLevelKeymap().clear();
2971 theTopLevelKeymap().read("site");
2972 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2973 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2977 void PrefShortcuts::updateRC(LyXRC const & rc)
2979 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2981 system_bind_.clear();
2983 user_unbind_.clear();
2984 system_bind_.read("site");
2985 system_bind_.read(rc.bind_file);
2986 // \unbind in user.bind is added to user_unbind_
2987 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2988 updateShortcutsTW();
2992 void PrefShortcuts::updateShortcutsTW()
2994 shortcutsTW->clear();
2996 editItem_ = new QTreeWidgetItem(shortcutsTW);
2997 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2998 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
3000 mathItem_ = new QTreeWidgetItem(shortcutsTW);
3001 mathItem_->setText(0, qt_("Mathematical Symbols"));
3002 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3004 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3005 bufferItem_->setText(0, qt_("Document and Window"));
3006 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3008 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3009 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3010 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3012 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3013 systemItem_->setText(0, qt_("System and Miscellaneous"));
3014 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3016 // listBindings(unbound=true) lists all bound and unbound lfuns
3017 // Items in this list is tagged by its source.
3018 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3020 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3022 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3023 KeyMap::UserUnbind);
3024 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3025 user_bindinglist.end());
3026 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3027 user_unbindinglist.end());
3029 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3030 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3031 for (; it != it_end; ++it)
3032 insertShortcutItem(it->request, it->sequence, it->tag);
3034 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3035 on_shortcutsTW_itemSelectionChanged();
3036 on_searchLE_textEdited();
3037 shortcutsTW->resizeColumnToContents(0);
3042 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3044 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3049 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3051 // Hide rebound system settings that are empty
3052 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3056 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3058 item->setData(0, Qt::UserRole, QVariant(tag));
3062 case KeyMap::System:
3064 case KeyMap::UserBind:
3067 case KeyMap::UserUnbind:
3068 font.setStrikeOut(true);
3070 // this item is not displayed now.
3071 case KeyMap::UserExtraUnbind:
3072 font.setStrikeOut(true);
3075 item->setHidden(isAlwaysHidden(*item));
3076 item->setFont(1, font);
3080 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3081 KeySequence const & seq, KeyMap::ItemType tag)
3083 FuncCode const action = lfun.action();
3084 string const action_name = lyxaction.getActionName(action);
3085 QString const lfun_name = toqstr(from_utf8(action_name)
3086 + ' ' + lfun.argument());
3087 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3089 QTreeWidgetItem * newItem = nullptr;
3090 // for unbind items, try to find an existing item in the system bind list
3091 if (tag == KeyMap::UserUnbind) {
3092 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3093 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3094 for (auto const & item : items) {
3095 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3100 // if not found, this unbind item is KeyMap::UserExtraUnbind
3101 // Such an item is not displayed to avoid confusion (what is
3102 // unmatched removed?).
3108 switch(lyxaction.getActionType(action)) {
3109 case LyXAction::Hidden:
3111 case LyXAction::Edit:
3112 newItem = new QTreeWidgetItem(editItem_);
3114 case LyXAction::Math:
3115 newItem = new QTreeWidgetItem(mathItem_);
3117 case LyXAction::Buffer:
3118 newItem = new QTreeWidgetItem(bufferItem_);
3120 case LyXAction::Layout:
3121 newItem = new QTreeWidgetItem(layoutItem_);
3123 case LyXAction::System:
3124 newItem = new QTreeWidgetItem(systemItem_);
3127 // this should not happen
3128 newItem = new QTreeWidgetItem(shortcutsTW);
3130 newItem->setText(0, lfun_name);
3131 newItem->setText(1, shortcut);
3134 // record BindFile representation to recover KeySequence when needed.
3135 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3136 setItemType(newItem, tag);
3141 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3143 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3144 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3145 modifyPB->setEnabled(!items.isEmpty());
3146 if (items.isEmpty())
3149 if (itemType(*items[0]) == KeyMap::UserUnbind)
3150 removePB->setText(qt_("Res&tore"));
3152 removePB->setText(qt_("Remo&ve"));
3156 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3162 void PrefShortcuts::modifyShortcut()
3164 QTreeWidgetItem * item = shortcutsTW->currentItem();
3165 if (item->flags() & Qt::ItemIsSelectable) {
3166 shortcut_->lfunLE->setText(item->text(0));
3167 save_lfun_ = item->text(0).trimmed();
3168 shortcut_->shortcutWG->setText(item->text(1));
3170 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3171 shortcut_->shortcutWG->setKeySequence(seq);
3172 shortcut_->shortcutWG->setFocus();
3178 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3180 // list of items that match lfun
3181 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3182 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3183 for (auto const & item : items) {
3184 if (isAlwaysHidden(*item)) {
3185 setItemType(item, KeyMap::System);
3187 shortcutsTW->setCurrentItem(item);
3194 void PrefShortcuts::removeShortcut()
3196 // it seems that only one item can be selected, but I am
3197 // removing all selected items anyway.
3198 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3199 for (auto & item : items) {
3200 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3201 string lfun = fromqstr(item->text(0));
3202 FuncRequest const func = lyxaction.lookupFunc(lfun);
3204 switch (itemType(*item)) {
3205 case KeyMap::System: {
3206 // for system bind, we do not touch the item
3207 // but add an user unbind item
3208 user_unbind_.bind(shortcut, func);
3209 setItemType(item, KeyMap::UserUnbind);
3210 removePB->setText(qt_("Res&tore"));
3213 case KeyMap::UserBind: {
3214 // for user_bind, we remove this bind
3215 QTreeWidgetItem * parent = item->parent();
3216 int itemIdx = parent->indexOfChild(item);
3217 parent->takeChild(itemIdx);
3219 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3221 shortcutsTW->scrollToItem(parent);
3222 user_bind_.unbind(shortcut, func);
3223 // If this user binding hid an empty system binding, unhide the
3224 // latter and select it.
3225 unhideEmpty(item->text(0), true);
3228 case KeyMap::UserUnbind: {
3229 // for user_unbind, we remove the unbind, and the item
3230 // become KeyMap::System again.
3232 seq.parse(shortcut);
3233 // Ask the user to replace current binding
3234 if (!validateNewShortcut(func, seq, QString()))
3236 user_unbind_.unbind(shortcut, func);
3237 setItemType(item, KeyMap::System);
3238 removePB->setText(qt_("Remo&ve"));
3241 case KeyMap::UserExtraUnbind: {
3242 // for user unbind that is not in system bind file,
3243 // remove this unbind file
3244 QTreeWidgetItem * parent = item->parent();
3245 parent->takeChild(parent->indexOfChild(item));
3246 user_unbind_.unbind(shortcut, func);
3253 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3255 for (auto item : items) {
3256 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3257 string lfun = fromqstr(item->text(0));
3258 FuncRequest const func = lyxaction.lookupFunc(lfun);
3260 switch (itemType(*item)) {
3261 case KeyMap::System:
3262 // for system bind, we do not touch the item
3263 // but add an user unbind item
3264 user_unbind_.bind(shortcut, func);
3265 setItemType(item, KeyMap::UserUnbind);
3268 case KeyMap::UserBind: {
3269 // for user_bind, we remove this bind
3270 QTreeWidgetItem * parent = item->parent();
3271 int itemIdx = parent->indexOfChild(item);
3272 parent->takeChild(itemIdx);
3273 user_bind_.unbind(shortcut, func);
3274 unhideEmpty(item->text(0), false);
3284 void PrefShortcuts::selectBind()
3286 QString file = form_->browsebind(internalPath(bindFileED->text()));
3287 if (!file.isEmpty()) {
3288 bindFileED->setText(file);
3289 system_bind_ = KeyMap();
3290 system_bind_.read(fromqstr(file));
3291 updateShortcutsTW();
3296 void PrefShortcuts::on_modifyPB_pressed()
3302 void PrefShortcuts::on_newPB_pressed()
3304 shortcut_->lfunLE->clear();
3305 shortcut_->shortcutWG->reset();
3306 save_lfun_ = QString();
3311 void PrefShortcuts::on_removePB_pressed()
3318 void PrefShortcuts::on_searchLE_textEdited()
3320 if (searchLE->text().isEmpty()) {
3321 // show all hidden items
3322 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3324 (*it)->setHidden(isAlwaysHidden(**it));
3325 // close all categories
3326 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3327 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3330 // search both columns
3331 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3332 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3333 matched += shortcutsTW->findItems(searchLE->text(),
3334 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3336 // hide everyone (to avoid searching in matched QList repeatedly
3337 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3339 (*it++)->setHidden(true);
3340 // show matched items
3341 for (auto & item : matched)
3342 if (!isAlwaysHidden(*item)) {
3343 item->setHidden(false);
3345 item->parent()->setExpanded(true);
3350 docstring makeCmdString(FuncRequest const & f)
3352 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3353 if (!f.argument().empty())
3354 actionStr += " " + f.argument();
3359 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3361 FuncRequest res = user_bind_.getBinding(k);
3362 if (res.action() != LFUN_UNKNOWN_ACTION)
3364 res = system_bind_.getBinding(k);
3365 // Check if it is unbound. Note: user_unbind_ can only unbind one
3366 // FuncRequest per key sequence.
3367 if (user_unbind_.getBinding(k) == res)
3368 return FuncRequest::unknown;
3373 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3374 KeySequence const & k,
3375 QString const & lfun_to_modify)
3377 if (func.action() == LFUN_UNKNOWN_ACTION) {
3378 Alert::error(_("Failed to create shortcut"),
3379 _("Unknown or invalid LyX function"));
3383 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3384 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3385 // and how it is used in GuiPrefs::shortcutOkPressed.
3386 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3387 Alert::error(_("Failed to create shortcut"),
3388 _("This LyX function is hidden and cannot be bound."));
3392 if (k.length() == 0) {
3393 Alert::error(_("Failed to create shortcut"),
3394 _("Invalid or empty key sequence"));
3398 FuncRequest oldBinding = currentBinding(k);
3399 if (oldBinding == func)
3400 // nothing to change
3403 // make sure this key isn't already bound---and, if so, prompt user
3404 // (exclude the lfun the user already wants to modify)
3405 docstring const action_string = makeCmdString(oldBinding);
3406 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3407 && lfun_to_modify != toqstr(action_string)) {
3408 docstring const new_action_string = makeCmdString(func);
3409 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3411 "Are you sure you want to unbind the "
3412 "current shortcut and bind it to %3$s?"),
3413 k.print(KeySequence::ForGui), action_string,
3415 int ret = Alert::prompt(_("Redefine shortcut?"),
3416 text, 0, 1, _("&Redefine"), _("&Cancel"));
3419 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3420 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3421 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3422 deactivateShortcuts(items);
3428 void PrefShortcuts::shortcutOkPressed()
3430 QString const new_lfun = shortcut_->lfunLE->text();
3431 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3432 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3434 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3435 // "modify", or is empty if they clicked "new" (which I do not really like)
3436 if (!validateNewShortcut(func, k, save_lfun_))
3439 if (!save_lfun_.isEmpty()) {
3440 // real modification of the lfun's shortcut,
3441 // so remove the previous one
3442 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3443 deactivateShortcuts(to_modify);
3446 shortcut_->accept();
3448 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3450 user_bind_.bind(&k, func);
3451 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3453 item->parent()->setExpanded(true);
3454 shortcutsTW->setCurrentItem(item);
3455 shortcutsTW->scrollToItem(item);
3457 Alert::error(_("Failed to create shortcut"),
3458 _("Can not insert shortcut to the list"));
3464 void PrefShortcuts::shortcutCancelPressed()
3466 shortcut_->shortcutWG->reset();
3470 void PrefShortcuts::shortcutClearPressed()
3472 shortcut_->shortcutWG->reset();
3476 void PrefShortcuts::shortcutRemovePressed()
3478 shortcut_->shortcutWG->removeFromSequence();
3482 /////////////////////////////////////////////////////////////////////
3486 /////////////////////////////////////////////////////////////////////
3488 PrefIdentity::PrefIdentity(GuiPreferences * form)
3489 : PrefModule(QString(), N_("Identity"), form)
3493 connect(nameED, SIGNAL(textChanged(QString)),
3494 this, SIGNAL(changed()));
3495 connect(emailED, SIGNAL(textChanged(QString)),
3496 this, SIGNAL(changed()));
3497 connect(initialsED, SIGNAL(textChanged(QString)),
3498 this, SIGNAL(changed()));
3500 nameED->setValidator(new NoNewLineValidator(nameED));
3501 emailED->setValidator(new NoNewLineValidator(emailED));
3502 initialsED->setValidator(new NoNewLineValidator(initialsED));
3506 void PrefIdentity::applyRC(LyXRC & rc) const
3508 rc.user_name = fromqstr(nameED->text());
3509 rc.user_email = fromqstr(emailED->text());
3510 rc.user_initials = fromqstr(initialsED->text());
3514 void PrefIdentity::updateRC(LyXRC const & rc)
3516 nameED->setText(toqstr(rc.user_name));
3517 emailED->setText(toqstr(rc.user_email));
3518 initialsED->setText(toqstr(rc.user_initials));
3523 /////////////////////////////////////////////////////////////////////
3527 /////////////////////////////////////////////////////////////////////
3529 GuiPreferences::GuiPreferences(GuiView & lv)
3530 : GuiDialog(lv, "prefs", qt_("Preferences"))
3534 QDialog::setModal(false);
3536 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3537 this, SLOT(slotButtonBox(QAbstractButton *)));
3539 addModule(new PrefUserInterface(this));
3540 addModule(new PrefDocHandling(this));
3541 addModule(new PrefEdit(this));
3542 addModule(new PrefShortcuts(this));
3543 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3544 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3545 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3546 addModule(screenfonts);
3547 addModule(new PrefColors(this));
3548 addModule(new PrefDisplay(this));
3549 addModule(new PrefInput(this));
3550 addModule(new PrefCompletion(this));
3552 addModule(new PrefPaths(this));
3554 addModule(new PrefIdentity(this));
3556 addModule(new PrefLanguage(this));
3557 addModule(new PrefSpellchecker(this));
3559 PrefOutput * output = new PrefOutput(this);
3561 addModule(new PrefLatex(this));
3563 PrefConverters * converters = new PrefConverters(this);
3564 PrefFileformats * formats = new PrefFileformats(this);
3565 connect(formats, SIGNAL(formatsChanged()),
3566 converters, SLOT(updateGui()));
3567 addModule(converters);
3570 prefsPS->setCurrentPanel("User Interface");
3572 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3573 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3574 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3575 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3576 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3578 guilyxfiles_ = new GuiLyXFiles(lv);
3579 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3580 this, SLOT(slotFileSelected(QString)));
3584 void GuiPreferences::addModule(PrefModule * module)
3586 LASSERT(module, return);
3587 if (module->category().isEmpty())
3588 prefsPS->addPanel(module, module->title());
3590 prefsPS->addPanel(module, module->title(), module->category());
3591 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3592 modules_.push_back(module);
3596 void GuiPreferences::change_adaptor()
3602 void GuiPreferences::applyRC(LyXRC & rc) const
3604 size_t end = modules_.size();
3605 for (size_t i = 0; i != end; ++i)
3606 modules_[i]->applyRC(rc);
3610 void GuiPreferences::updateRC(LyXRC const & rc)
3612 size_t const end = modules_.size();
3613 for (size_t i = 0; i != end; ++i)
3614 modules_[i]->updateRC(rc);
3618 void GuiPreferences::applyView()
3624 bool GuiPreferences::initialiseParams(string const &)
3627 formats_ = theFormats();
3628 converters_ = theConverters();
3629 converters_.update(formats_);
3630 movers_ = theMovers();
3634 // Make sure that the bc is in the INITIAL state
3635 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3642 void GuiPreferences::dispatchParams()
3645 rc_.write(ss, true);
3646 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3647 // issue prefsApplied signal. This will update the
3648 // localized screen font sizes.
3650 // FIXME: these need lfuns
3652 Author const & author =
3653 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3654 from_utf8(rc_.user_initials));
3655 theBufferList().recordCurrentAuthor(author);
3657 theFormats() = formats_;
3659 theConverters() = converters_;
3660 theConverters().update(formats_);
3661 theConverters().buildGraph();
3662 theBufferList().invalidateConverterCache();
3664 theMovers() = movers_;
3666 for (string const & color : colors_)
3667 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3671 if (!tempSaveCB->isChecked())
3672 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3676 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3678 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3682 void GuiPreferences::slotFileSelected(QString const file)
3688 QString GuiPreferences::browseLibFile(QString const & dir,
3689 QString const & name, QString const & ext)
3693 guilyxfiles_->passParams(fromqstr(dir));
3694 guilyxfiles_->selectItem(name);
3695 guilyxfiles_->exec();
3697 QString const result = uifile_;
3699 // remove the extension if it is the default one
3700 QString noextresult;
3701 if (getExtension(result) == ext)
3702 noextresult = removeExtension(result);
3704 noextresult = result;
3706 // remove the directory, if it is the default one
3707 QString const file = onlyFileName(noextresult);
3708 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3715 QString GuiPreferences::browsebind(QString const & file)
3717 return browseLibFile("bind", file, "bind");
3721 QString GuiPreferences::browseUI(QString const & file)
3723 return browseLibFile("ui", file, "ui");
3727 QString GuiPreferences::browsekbmap(QString const & file)
3729 return browseLibFile("kbd", file, "kmap");
3733 QString GuiPreferences::browse(QString const & file,
3734 QString const & title) const
3736 return browseFile(file, title, QStringList(), true);
3740 } // namespace frontend
3743 #include "moc_GuiPrefs.cpp"