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 testname.remove(QRegularExpression("^(\\.\\./)+"));
194 if (testname.contains("/"))
202 /////////////////////////////////////////////////////////////////////
206 /////////////////////////////////////////////////////////////////////
210 QString const catLookAndFeel = N_("Look & Feel");
211 QString const catEditing = N_("Editing");
212 QString const catLanguage = N_("Language Settings");
213 QString const catOutput = N_("Output");
214 QString const catFiles = N_("File Handling");
216 static void parseFontName(QString const & mangled0,
217 string & name, string & foundry)
219 string mangled = fromqstr(mangled0);
220 size_t const idx = mangled.find('[');
221 if (idx == string::npos || idx == 0) {
225 name = mangled.substr(0, idx - 1);
226 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
231 static void setComboxFont(QComboBox * cb, string const & family,
232 string const & foundry)
234 QString fontname = toqstr(family);
235 if (!foundry.empty())
236 fontname += " [" + toqstr(foundry) + ']';
238 for (int i = 0; i != cb->count(); ++i) {
239 if (cb->itemText(i) == fontname) {
240 cb->setCurrentIndex(i);
245 // Try matching without foundry name
247 // We count in reverse in order to prefer the Xft foundry
248 for (int i = cb->count(); --i >= 0;) {
249 string name, fnt_foundry;
250 parseFontName(cb->itemText(i), name, fnt_foundry);
251 if (compare_ascii_no_case(name, family) == 0) {
252 cb->setCurrentIndex(i);
257 // family alone can contain e.g. "Helvetica [Adobe]"
258 string tmpname, tmpfoundry;
259 parseFontName(toqstr(family), tmpname, tmpfoundry);
261 // We count in reverse in order to prefer the Xft foundry
262 for (int i = cb->count(); --i >= 0; ) {
263 string name, fnt_foundry;
264 parseFontName(cb->itemText(i), name, fnt_foundry);
265 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
266 cb->setCurrentIndex(i);
271 // Bleh, default fonts, and the names couldn't be found. Hack
276 QString const font_family = toqstr(family);
277 if (font_family == guiApp->romanFontName()) {
278 font.setStyleHint(QFont::Serif);
279 font.setFamily(font_family);
280 } else if (font_family == guiApp->sansFontName()) {
281 font.setStyleHint(QFont::SansSerif);
282 font.setFamily(font_family);
283 } else if (font_family == guiApp->typewriterFontName()) {
284 font.setStyleHint(QFont::TypeWriter);
285 font.setFamily(font_family);
287 LYXERR0("FAILED to find the default font: '"
288 << foundry << "', '" << family << '\'');
292 QFontInfo info(font);
293 string default_font_name, dummyfoundry;
294 parseFontName(info.family(), default_font_name, dummyfoundry);
295 LYXERR0("Apparent font is " << default_font_name);
297 for (int i = 0; i < cb->count(); ++i) {
298 LYXERR0("Looking at " << cb->itemText(i));
299 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
300 default_font_name) == 0) {
301 cb->setCurrentIndex(i);
306 LYXERR0("FAILED to find the font: '"
307 << foundry << "', '" << family << '\'');
311 /////////////////////////////////////////////////////////////////////
315 /////////////////////////////////////////////////////////////////////
317 PrefOutput::PrefOutput(GuiPreferences * form)
318 : PrefModule(catOutput, N_("General[[settings]]"), form)
322 dviCB->setValidator(new NoNewLineValidator(dviCB));
323 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
325 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
326 this, SIGNAL(changed()));
327 connect(overwriteCO, SIGNAL(activated(int)),
328 this, SIGNAL(changed()));
329 connect(dviCB, SIGNAL(editTextChanged(QString)),
330 this, SIGNAL(changed()));
331 connect(pdfCB, SIGNAL(editTextChanged(QString)),
332 this, SIGNAL(changed()));
333 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
334 this, SIGNAL(changed()));
335 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
336 this, SIGNAL(changed()));
337 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
338 this, SIGNAL(changed()));
340 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
341 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
342 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
345 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
346 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
347 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
348 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
350 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
351 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
352 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
353 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
354 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
355 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
356 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
360 void PrefOutput::applyRC(LyXRC & rc) const
362 rc.plaintext_linelen = plaintextLinelengthSB->value();
363 rc.forward_search_dvi = fromqstr(dviCB->currentText());
364 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
366 switch (overwriteCO->currentIndex()) {
368 rc.export_overwrite = NO_FILES;
371 rc.export_overwrite = MAIN_FILE;
374 rc.export_overwrite = ALL_FILES;
378 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
379 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
380 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
384 void PrefOutput::updateRC(LyXRC const & rc)
386 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
387 dviCB->setEditText(toqstr(rc.forward_search_dvi));
388 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
390 switch (rc.export_overwrite) {
392 overwriteCO->setCurrentIndex(0);
395 overwriteCO->setCurrentIndex(1);
398 overwriteCO->setCurrentIndex(2);
402 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
403 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
404 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
408 /////////////////////////////////////////////////////////////////////
412 /////////////////////////////////////////////////////////////////////
414 PrefInput::PrefInput(GuiPreferences * form)
415 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
419 connect(keymapCB, SIGNAL(clicked()),
420 this, SIGNAL(changed()));
421 connect(firstKeymapED, SIGNAL(textChanged(QString)),
422 this, SIGNAL(changed()));
423 connect(secondKeymapED, SIGNAL(textChanged(QString)),
424 this, SIGNAL(changed()));
425 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
426 this, SIGNAL(changed()));
427 connect(scrollzoomEnableCB, SIGNAL(clicked()),
428 this, SIGNAL(changed()));
429 connect(scrollzoomValueCO, SIGNAL(activated(int)),
430 this, SIGNAL(changed()));
431 connect(dontswapCB, SIGNAL(toggled(bool)),
432 this, SIGNAL(changed()));
433 connect(mmPasteCB, SIGNAL(toggled(bool)),
434 this, SIGNAL(changed()));
436 // reveal checkbox for switching Ctrl and Meta on Mac:
438 dontswapCB->setVisible(true);
440 dontswapCB->setVisible(false);
445 void PrefInput::applyRC(LyXRC & rc) const
447 // FIXME: can derive CB from the two EDs
448 rc.use_kbmap = keymapCB->isChecked();
449 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
450 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
451 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
452 if (scrollzoomEnableCB->isChecked()) {
453 switch (scrollzoomValueCO->currentIndex()) {
455 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
458 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
461 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
465 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
467 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
468 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
472 void PrefInput::updateRC(LyXRC const & rc)
474 // FIXME: can derive CB from the two EDs
475 keymapCB->setChecked(rc.use_kbmap);
476 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
477 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
478 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
479 switch (rc.scroll_wheel_zoom) {
480 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
481 scrollzoomEnableCB->setChecked(false);
483 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
484 scrollzoomEnableCB->setChecked(true);
485 scrollzoomValueCO->setCurrentIndex(0);
487 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
488 scrollzoomEnableCB->setChecked(true);
489 scrollzoomValueCO->setCurrentIndex(1);
491 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
492 scrollzoomEnableCB->setChecked(true);
493 scrollzoomValueCO->setCurrentIndex(2);
496 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
497 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
501 QString PrefInput::testKeymap(QString const & keymap)
503 return form_->browsekbmap(internalPath(keymap));
507 void PrefInput::on_firstKeymapPB_clicked(bool)
509 QString const file = testKeymap(firstKeymapED->text());
511 firstKeymapED->setText(file);
515 void PrefInput::on_secondKeymapPB_clicked(bool)
517 QString const file = testKeymap(secondKeymapED->text());
519 secondKeymapED->setText(file);
523 void PrefInput::on_keymapCB_toggled(bool keymap)
525 firstKeymapLA->setEnabled(keymap);
526 secondKeymapLA->setEnabled(keymap);
527 firstKeymapED->setEnabled(keymap);
528 secondKeymapED->setEnabled(keymap);
529 firstKeymapPB->setEnabled(keymap);
530 secondKeymapPB->setEnabled(keymap);
534 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
536 scrollzoomValueCO->setEnabled(enabled);
540 /////////////////////////////////////////////////////////////////////
544 /////////////////////////////////////////////////////////////////////
546 PrefCompletion::PrefCompletion(GuiPreferences * form)
547 : PrefModule(catEditing, N_("Input Completion"), form)
551 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
552 this, SIGNAL(changed()));
553 connect(inlineMathCB, SIGNAL(clicked()),
554 this, SIGNAL(changed()));
555 connect(inlineTextCB, SIGNAL(clicked()),
556 this, SIGNAL(changed()));
557 connect(inlineDotsCB, SIGNAL(clicked()),
558 this, SIGNAL(changed()));
559 connect(popupDelaySB, SIGNAL(valueChanged(double)),
560 this, SIGNAL(changed()));
561 connect(popupMathCB, SIGNAL(clicked()),
562 this, SIGNAL(changed()));
563 connect(autocorrectionCB, SIGNAL(clicked()),
564 this, SIGNAL(changed()));
565 connect(popupTextCB, SIGNAL(clicked()),
566 this, SIGNAL(changed()));
567 connect(popupAfterCompleteCB, SIGNAL(clicked()),
568 this, SIGNAL(changed()));
569 connect(cursorTextCB, SIGNAL(clicked()),
570 this, SIGNAL(changed()));
571 connect(minlengthSB, SIGNAL(valueChanged(int)),
572 this, SIGNAL(changed()));
576 void PrefCompletion::on_inlineTextCB_clicked()
582 void PrefCompletion::on_popupTextCB_clicked()
588 void PrefCompletion::enableCB()
590 cursorTextCB->setEnabled(
591 popupTextCB->isChecked() || inlineTextCB->isChecked());
595 void PrefCompletion::applyRC(LyXRC & rc) const
597 rc.completion_inline_delay = inlineDelaySB->value();
598 rc.completion_inline_math = inlineMathCB->isChecked();
599 rc.completion_inline_text = inlineTextCB->isChecked();
600 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
601 rc.completion_popup_delay = popupDelaySB->value();
602 rc.completion_popup_math = popupMathCB->isChecked();
603 rc.autocorrection_math = autocorrectionCB->isChecked();
604 rc.completion_popup_text = popupTextCB->isChecked();
605 rc.completion_cursor_text = cursorTextCB->isChecked();
606 rc.completion_popup_after_complete =
607 popupAfterCompleteCB->isChecked();
608 rc.completion_minlength = minlengthSB->value();
612 void PrefCompletion::updateRC(LyXRC const & rc)
614 inlineDelaySB->setValue(rc.completion_inline_delay);
615 inlineMathCB->setChecked(rc.completion_inline_math);
616 inlineTextCB->setChecked(rc.completion_inline_text);
617 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
618 popupDelaySB->setValue(rc.completion_popup_delay);
619 popupMathCB->setChecked(rc.completion_popup_math);
620 autocorrectionCB->setChecked(rc.autocorrection_math);
621 popupTextCB->setChecked(rc.completion_popup_text);
622 cursorTextCB->setChecked(rc.completion_cursor_text);
623 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
625 minlengthSB->setValue(rc.completion_minlength);
630 /////////////////////////////////////////////////////////////////////
634 /////////////////////////////////////////////////////////////////////
636 PrefLatex::PrefLatex(GuiPreferences * form)
637 : PrefModule(catOutput, N_("LaTeX"), form)
641 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
642 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
643 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
644 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
645 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
646 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
647 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
649 connect(latexChecktexED, SIGNAL(textChanged(QString)),
650 this, SIGNAL(changed()));
651 connect(latexBibtexCO, SIGNAL(activated(int)),
652 this, SIGNAL(changed()));
653 connect(latexBibtexED, SIGNAL(textChanged(QString)),
654 this, SIGNAL(changed()));
655 connect(latexJBibtexCO, SIGNAL(activated(int)),
656 this, SIGNAL(changed()));
657 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
658 this, SIGNAL(changed()));
659 connect(latexIndexCO, SIGNAL(activated(int)),
660 this, SIGNAL(changed()));
661 connect(latexIndexED, SIGNAL(textChanged(QString)),
662 this, SIGNAL(changed()));
663 connect(latexJIndexED, SIGNAL(textChanged(QString)),
664 this, SIGNAL(changed()));
665 connect(latexAutoresetCB, SIGNAL(clicked()),
666 this, SIGNAL(changed()));
667 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
668 this, SIGNAL(changed()));
669 connect(latexNomenclED, SIGNAL(textChanged(QString)),
670 this, SIGNAL(changed()));
672 #if defined(__CYGWIN__) || defined(_WIN32)
673 pathCB->setVisible(true);
674 connect(pathCB, SIGNAL(clicked()),
675 this, SIGNAL(changed()));
677 pathCB->setVisible(false);
682 void PrefLatex::on_latexBibtexCO_activated(int n)
684 QString const bibtex = latexBibtexCO->itemData(n).toString();
685 if (bibtex.isEmpty()) {
686 latexBibtexED->clear();
687 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
690 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
691 it != bibtex_alternatives.end(); ++it) {
692 QString const bib = toqstr(*it);
693 int ind = bib.indexOf(" ");
694 QString sel_command = bib.left(ind);
695 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
696 if (bibtex == sel_command) {
698 latexBibtexED->clear();
700 latexBibtexED->setText(sel_options.trimmed());
703 latexBibtexOptionsLA->setText(qt_("&Options:"));
707 void PrefLatex::on_latexJBibtexCO_activated(int n)
709 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
710 if (jbibtex.isEmpty()) {
711 latexJBibtexED->clear();
712 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
715 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
716 it != jbibtex_alternatives.end(); ++it) {
717 QString const bib = toqstr(*it);
718 int ind = bib.indexOf(" ");
719 QString sel_command = bib.left(ind);
720 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
721 if (jbibtex == sel_command) {
723 latexJBibtexED->clear();
725 latexJBibtexED->setText(sel_options.trimmed());
728 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
732 void PrefLatex::on_latexIndexCO_activated(int n)
734 QString const index = latexIndexCO->itemData(n).toString();
735 if (index.isEmpty()) {
736 latexIndexED->clear();
737 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
740 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
741 it != index_alternatives.end(); ++it) {
742 QString const idx = toqstr(*it);
743 int ind = idx.indexOf(" ");
744 QString sel_command = idx.left(ind);
745 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
746 if (index == sel_command) {
748 latexIndexED->clear();
750 latexIndexED->setText(sel_options.trimmed());
753 latexIndexOptionsLA->setText(qt_("Op&tions:"));
757 void PrefLatex::applyRC(LyXRC & rc) const
759 // If bibtex is not empty, bibopt contains the options, otherwise
760 // it is a customized bibtex command with options.
761 QString const bibtex = latexBibtexCO->itemData(
762 latexBibtexCO->currentIndex()).toString();
763 QString const bibopt = latexBibtexED->text();
764 if (bibtex.isEmpty())
765 rc.bibtex_command = fromqstr(bibopt);
766 else if (bibopt.isEmpty())
767 rc.bibtex_command = fromqstr(bibtex);
769 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
771 // If jbibtex is not empty, jbibopt contains the options, otherwise
772 // it is a customized bibtex command with options.
773 QString const jbibtex = latexJBibtexCO->itemData(
774 latexJBibtexCO->currentIndex()).toString();
775 QString const jbibopt = latexJBibtexED->text();
776 if (jbibtex.isEmpty())
777 rc.jbibtex_command = fromqstr(jbibopt);
778 else if (jbibopt.isEmpty())
779 rc.jbibtex_command = fromqstr(jbibtex);
781 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
783 // If index is not empty, idxopt contains the options, otherwise
784 // it is a customized index command with options.
785 QString const index = latexIndexCO->itemData(
786 latexIndexCO->currentIndex()).toString();
787 QString const idxopt = latexIndexED->text();
789 rc.index_command = fromqstr(idxopt);
790 else if (idxopt.isEmpty())
791 rc.index_command = fromqstr(index);
793 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
795 rc.chktex_command = fromqstr(latexChecktexED->text());
796 rc.jindex_command = fromqstr(latexJIndexED->text());
797 rc.nomencl_command = fromqstr(latexNomenclED->text());
798 rc.auto_reset_options = latexAutoresetCB->isChecked();
799 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
800 #if defined(__CYGWIN__) || defined(_WIN32)
801 rc.windows_style_tex_paths = pathCB->isChecked();
806 void PrefLatex::updateRC(LyXRC const & rc)
808 latexBibtexCO->clear();
810 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
811 latexBibtexCO->addItem(qt_("Custom"), QString());
812 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
813 it != rc.bibtex_alternatives.end(); ++it) {
814 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
815 latexBibtexCO->addItem(command, command);
818 bibtex_alternatives = rc.bibtex_alternatives;
820 QString const bib = toqstr(rc.bibtex_command);
821 int ind = bib.indexOf(" ");
822 QString sel_command = bib.left(ind);
823 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
825 int pos = latexBibtexCO->findData(sel_command);
827 latexBibtexCO->setCurrentIndex(pos);
828 latexBibtexED->setText(sel_options.trimmed());
829 latexBibtexOptionsLA->setText(qt_("&Options:"));
831 latexBibtexED->setText(toqstr(rc.bibtex_command));
832 latexBibtexCO->setCurrentIndex(0);
833 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
836 latexJBibtexCO->clear();
838 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
839 latexJBibtexCO->addItem(qt_("Custom"), QString());
840 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
841 it != rc.jbibtex_alternatives.end(); ++it) {
842 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
843 latexJBibtexCO->addItem(command, command);
846 jbibtex_alternatives = rc.jbibtex_alternatives;
848 QString const jbib = toqstr(rc.jbibtex_command);
849 ind = jbib.indexOf(" ");
850 sel_command = jbib.left(ind);
851 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
853 pos = latexJBibtexCO->findData(sel_command);
855 latexJBibtexCO->setCurrentIndex(pos);
856 latexJBibtexED->setText(sel_options.trimmed());
857 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
859 latexJBibtexED->setText(toqstr(rc.bibtex_command));
860 latexJBibtexCO->setCurrentIndex(0);
861 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
864 latexIndexCO->clear();
866 latexIndexCO->addItem(qt_("Custom"), QString());
867 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
868 it != rc.index_alternatives.end(); ++it) {
869 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
870 latexIndexCO->addItem(command, command);
873 index_alternatives = rc.index_alternatives;
875 QString const idx = toqstr(rc.index_command);
876 ind = idx.indexOf(" ");
877 sel_command = idx.left(ind);
878 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
880 pos = latexIndexCO->findData(sel_command);
882 latexIndexCO->setCurrentIndex(pos);
883 latexIndexED->setText(sel_options.trimmed());
884 latexIndexOptionsLA->setText(qt_("Op&tions:"));
886 latexIndexED->setText(toqstr(rc.index_command));
887 latexIndexCO->setCurrentIndex(0);
888 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
891 latexChecktexED->setText(toqstr(rc.chktex_command));
892 latexJIndexED->setText(toqstr(rc.jindex_command));
893 latexNomenclED->setText(toqstr(rc.nomencl_command));
894 latexAutoresetCB->setChecked(rc.auto_reset_options);
895 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
896 #if defined(__CYGWIN__) || defined(_WIN32)
897 pathCB->setChecked(rc.windows_style_tex_paths);
902 /////////////////////////////////////////////////////////////////////
906 /////////////////////////////////////////////////////////////////////
908 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
909 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
913 #if QT_VERSION < 0x050e00
914 connect(screenRomanCO, SIGNAL(activated(QString)),
915 this, SLOT(selectRoman(QString)));
916 connect(screenSansCO, SIGNAL(activated(QString)),
917 this, SLOT(selectSans(QString)));
918 connect(screenTypewriterCO, SIGNAL(activated(QString)),
919 this, SLOT(selectTypewriter(QString)));
921 connect(screenRomanCO, SIGNAL(textActivated(QString)),
922 this, SLOT(selectRoman(QString)));
923 connect(screenSansCO, SIGNAL(textActivated(QString)),
924 this, SLOT(selectSans(QString)));
925 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
926 this, SLOT(selectTypewriter(QString)));
929 #if QT_VERSION >= 0x060000
930 const QStringList families(QFontDatabase::families());
932 QFontDatabase fontdb;
933 const QStringList families(fontdb.families());
935 for (auto const & family : families) {
936 screenRomanCO->addItem(family);
937 screenSansCO->addItem(family);
938 screenTypewriterCO->addItem(family);
940 #if QT_VERSION < 0x050e00
941 connect(screenRomanCO, SIGNAL(activated(QString)),
942 this, SIGNAL(changed()));
943 connect(screenSansCO, SIGNAL(activated(QString)),
944 this, SIGNAL(changed()));
945 connect(screenTypewriterCO, SIGNAL(activated(QString)),
946 this, SIGNAL(changed()));
948 connect(screenRomanCO, SIGNAL(textActivated(QString)),
949 this, SIGNAL(changed()));
950 connect(screenSansCO, SIGNAL(textActivated(QString)),
951 this, SIGNAL(changed()));
952 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
953 this, SIGNAL(changed()));
955 connect(screenZoomSB, SIGNAL(valueChanged(int)),
956 this, SIGNAL(changed()));
957 connect(screenTinyED, SIGNAL(textChanged(QString)),
958 this, SIGNAL(changed()));
959 connect(screenSmallestED, SIGNAL(textChanged(QString)),
960 this, SIGNAL(changed()));
961 connect(screenSmallerED, SIGNAL(textChanged(QString)),
962 this, SIGNAL(changed()));
963 connect(screenSmallED, SIGNAL(textChanged(QString)),
964 this, SIGNAL(changed()));
965 connect(screenNormalED, SIGNAL(textChanged(QString)),
966 this, SIGNAL(changed()));
967 connect(screenLargeED, SIGNAL(textChanged(QString)),
968 this, SIGNAL(changed()));
969 connect(screenLargerED, SIGNAL(textChanged(QString)),
970 this, SIGNAL(changed()));
971 connect(screenLargestED, SIGNAL(textChanged(QString)),
972 this, SIGNAL(changed()));
973 connect(screenHugeED, SIGNAL(textChanged(QString)),
974 this, SIGNAL(changed()));
975 connect(screenHugerED, SIGNAL(textChanged(QString)),
976 this, SIGNAL(changed()));
978 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
979 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
980 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
981 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
982 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
983 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
984 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
985 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
986 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
987 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
991 void PrefScreenFonts::applyRC(LyXRC & rc) const
993 LyXRC const oldrc = rc;
995 parseFontName(screenRomanCO->currentText(),
996 rc.roman_font_name, rc.roman_font_foundry);
997 parseFontName(screenSansCO->currentText(),
998 rc.sans_font_name, rc.sans_font_foundry);
999 parseFontName(screenTypewriterCO->currentText(),
1000 rc.typewriter_font_name, rc.typewriter_font_foundry);
1002 rc.defaultZoom = screenZoomSB->value();
1003 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
1004 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
1005 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
1006 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
1007 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
1008 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
1009 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
1010 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
1011 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
1012 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
1016 void PrefScreenFonts::updateRC(LyXRC const & rc)
1018 setComboxFont(screenRomanCO, rc.roman_font_name,
1019 rc.roman_font_foundry);
1020 setComboxFont(screenSansCO, rc.sans_font_name,
1021 rc.sans_font_foundry);
1022 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1023 rc.typewriter_font_foundry);
1025 selectRoman(screenRomanCO->currentText());
1026 selectSans(screenSansCO->currentText());
1027 selectTypewriter(screenTypewriterCO->currentText());
1029 screenZoomSB->setValue(rc.defaultZoom);
1030 updateScreenFontSizes(rc);
1034 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1036 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1037 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1038 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1039 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1040 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1041 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1042 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1043 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1044 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1045 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1049 void PrefScreenFonts::selectRoman(const QString & name)
1051 screenRomanFE->set(QFont(name), name);
1055 void PrefScreenFonts::selectSans(const QString & name)
1057 screenSansFE->set(QFont(name), name);
1061 void PrefScreenFonts::selectTypewriter(const QString & name)
1063 screenTypewriterFE->set(QFont(name), name);
1067 /////////////////////////////////////////////////////////////////////
1071 /////////////////////////////////////////////////////////////////////
1074 PrefColors::PrefColors(GuiPreferences * form)
1075 : PrefModule(catLookAndFeel, N_("Colors"), form)
1079 // FIXME: all of this initialization should be put into the controller.
1080 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1081 // for some discussion of why that is not trivial.
1082 QPixmap icon(32, 32);
1083 for (int i = 0; i < Color_ignore; ++i) {
1084 ColorCode lc = static_cast<ColorCode>(i);
1085 if (lc == Color_none
1086 || lc == Color_black
1087 || lc == Color_white
1089 || lc == Color_brown
1091 || lc == Color_darkgray
1093 || lc == Color_green
1094 || lc == Color_lightgray
1096 || lc == Color_magenta
1097 || lc == Color_olive
1098 || lc == Color_orange
1100 || lc == Color_purple
1103 || lc == Color_violet
1104 || lc == Color_yellow
1105 || lc == Color_inherit
1106 || lc == Color_ignore)
1108 lcolors_.push_back(lc);
1110 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1111 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1112 vector<ColorCode>::const_iterator const end = lcolors_.end();
1113 for (; cit != end; ++cit) {
1114 (void) new QListWidgetItem(QIcon(icon),
1115 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1117 curcolors_.resize(lcolors_.size());
1118 newcolors_.resize(lcolors_.size());
1119 // End initialization
1121 connect(colorChangePB, SIGNAL(clicked()),
1122 this, SLOT(changeColor()));
1123 connect(colorResetPB, SIGNAL(clicked()),
1124 this, SLOT(resetColor()));
1125 connect(colorResetAllPB, SIGNAL(clicked()),
1126 this, SLOT(resetAllColor()));
1127 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1128 this, SLOT(changeLyxObjectsSelection()));
1129 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1130 this, SLOT(changeColor()));
1131 connect(syscolorsCB, SIGNAL(toggled(bool)),
1132 this, SIGNAL(changed()));
1133 connect(syscolorsCB, SIGNAL(toggled(bool)),
1134 this, SLOT(changeSysColor()));
1138 void PrefColors::applyRC(LyXRC & rc) const
1142 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1143 if (curcolors_[i] != newcolors_[i])
1144 form_->setColor(lcolors_[i], newcolors_[i]);
1145 rc.use_system_colors = syscolorsCB->isChecked();
1147 if (oldrc.use_system_colors != rc.use_system_colors)
1148 guiApp->colorCache().clear();
1152 void PrefColors::updateRC(LyXRC const & rc)
1154 for (size_type i = 0; i < lcolors_.size(); ++i) {
1155 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1156 QPixmap coloritem(32, 32);
1157 coloritem.fill(color);
1158 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1159 newcolors_[i] = curcolors_[i] = color.name();
1161 syscolorsCB->setChecked(rc.use_system_colors);
1162 changeLyxObjectsSelection();
1164 setDisabledResets();
1168 void PrefColors::changeColor()
1170 int const row = lyxObjectsLW->currentRow();
1176 QString const color = newcolors_[size_t(row)];
1177 QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1179 if (setColor(row, c, color)) {
1180 setDisabledResets();
1187 void PrefColors::resetColor()
1189 int const row = lyxObjectsLW->currentRow();
1195 QString const color = newcolors_[size_t(row)];
1196 QColor const c = getDefaultColorByRow(row);
1198 if (setColor(row, c, color)) {
1199 setDisabledResets();
1206 void PrefColors::resetAllColor()
1208 bool isChanged = false;
1210 colorResetAllPB->setDisabled(true);
1212 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1213 QString const color = newcolors_[size_t(irow)];
1214 QColor const c = getDefaultColorByRow(irow);
1216 if (setColor(irow, c, color))
1221 setDisabledResets();
1228 bool PrefColors::setColor(int const row, QColor const & new_color,
1229 QString const & old_color)
1231 if (new_color.isValid() && new_color.name() != old_color) {
1232 newcolors_[size_t(row)] = new_color.name();
1233 QPixmap coloritem(32, 32);
1234 coloritem.fill(new_color);
1235 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1242 void PrefColors::setDisabledResets()
1244 int const row = lyxObjectsLW->currentRow();
1245 // set disable reset buttons ...
1247 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1249 colorResetAllPB->setDisabled(true);
1251 // ... in between process qt events to give quicker visual feedback to the user ...
1252 guiApp->processEvents();
1254 // ... set disable Reset All button
1255 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1256 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1257 colorResetAllPB->setDisabled(false);
1258 // the break condition might hide performance issues
1259 // if a non-default color is at the top of the list
1266 bool PrefColors::isDefaultColor(int const row, QString const & color)
1268 return color == getDefaultColorByRow(row).name();
1272 QColor PrefColors::getDefaultColorByRow(int const row)
1274 ColorSet const defaultcolor;
1275 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1276 guiApp->colorCache().isDarkMode()).c_str();
1280 void PrefColors::changeSysColor()
1282 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1283 // skip colors that are taken from system palette
1284 bool const disable = syscolorsCB->isChecked()
1285 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1287 QListWidgetItem * const item = lyxObjectsLW->item(row);
1288 Qt::ItemFlags const flags = item->flags();
1291 item->setFlags(flags & ~Qt::ItemIsEnabled);
1293 item->setFlags(flags | Qt::ItemIsEnabled);
1298 void PrefColors::changeLyxObjectsSelection()
1300 int currentRow = lyxObjectsLW->currentRow();
1301 colorChangePB->setDisabled(currentRow < 0);
1304 colorResetPB->setDisabled(true);
1306 colorResetPB->setDisabled(
1307 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1311 /////////////////////////////////////////////////////////////////////
1315 /////////////////////////////////////////////////////////////////////
1317 PrefDisplay::PrefDisplay(GuiPreferences * form)
1318 : PrefModule(catLookAndFeel, N_("Display"), form)
1321 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1322 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1323 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1324 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1325 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1329 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1331 previewSizeSB->setEnabled(index != 0);
1335 void PrefDisplay::applyRC(LyXRC & rc) const
1337 switch (instantPreviewCO->currentIndex()) {
1339 rc.preview = LyXRC::PREVIEW_OFF;
1342 rc.preview = LyXRC::PREVIEW_NO_MATH;
1345 rc.preview = LyXRC::PREVIEW_ON;
1349 rc.display_graphics = displayGraphicsCB->isChecked();
1350 rc.preview_scale_factor = previewSizeSB->value();
1351 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1352 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1354 // FIXME!! The graphics cache no longer has a changeDisplay method.
1356 if (old_value != rc.display_graphics) {
1357 graphics::GCache & gc = graphics::GCache::get();
1364 void PrefDisplay::updateRC(LyXRC const & rc)
1366 switch (rc.preview) {
1367 case LyXRC::PREVIEW_OFF:
1368 instantPreviewCO->setCurrentIndex(0);
1370 case LyXRC::PREVIEW_NO_MATH :
1371 instantPreviewCO->setCurrentIndex(1);
1373 case LyXRC::PREVIEW_ON :
1374 instantPreviewCO->setCurrentIndex(2);
1378 displayGraphicsCB->setChecked(rc.display_graphics);
1379 previewSizeSB->setValue(rc.preview_scale_factor);
1380 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1381 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1382 previewSizeSB->setEnabled(
1384 && rc.preview != LyXRC::PREVIEW_OFF);
1388 /////////////////////////////////////////////////////////////////////
1392 /////////////////////////////////////////////////////////////////////
1394 PrefPaths::PrefPaths(GuiPreferences * form)
1395 : PrefModule(QString(), N_("Paths"), form)
1399 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1400 connect(workingDirED, SIGNAL(textChanged(QString)),
1401 this, SIGNAL(changed()));
1403 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1404 connect(templateDirED, SIGNAL(textChanged(QString)),
1405 this, SIGNAL(changed()));
1407 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1408 connect(exampleDirED, SIGNAL(textChanged(QString)),
1409 this, SIGNAL(changed()));
1411 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1412 connect(backupDirED, SIGNAL(textChanged(QString)),
1413 this, SIGNAL(changed()));
1415 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1416 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1417 this, SIGNAL(changed()));
1419 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1420 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1421 this, SIGNAL(changed()));
1423 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1424 connect(tempDirED, SIGNAL(textChanged(QString)),
1425 this, SIGNAL(changed()));
1427 #if defined(USE_HUNSPELL)
1428 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1429 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1430 this, SIGNAL(changed()));
1432 hunspellDirPB->setEnabled(false);
1433 hunspellDirED->setEnabled(false);
1436 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1437 this, SIGNAL(changed()));
1439 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1440 this, SIGNAL(changed()));
1442 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1443 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1447 void PrefPaths::applyRC(LyXRC & rc) const
1449 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1450 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1451 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1452 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1453 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1454 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1455 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1456 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1457 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1458 // FIXME: should be a checkbox only
1459 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1463 void PrefPaths::updateRC(LyXRC const & rc)
1465 workingDirED->setText(toqstr(external_path(rc.document_path)));
1466 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1467 templateDirED->setText(toqstr(external_path(rc.template_path)));
1468 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1469 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1470 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1471 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1472 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1473 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1474 // FIXME: should be a checkbox only
1475 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1479 void PrefPaths::selectExampledir()
1481 QString file = browseDir(internalPath(exampleDirED->text()),
1482 qt_("Select directory for example files"));
1483 if (!file.isEmpty())
1484 exampleDirED->setText(file);
1488 void PrefPaths::selectTemplatedir()
1490 QString file = browseDir(internalPath(templateDirED->text()),
1491 qt_("Select a document templates directory"));
1492 if (!file.isEmpty())
1493 templateDirED->setText(file);
1497 void PrefPaths::selectTempdir()
1499 QString file = browseDir(internalPath(tempDirED->text()),
1500 qt_("Select a temporary directory"));
1501 if (!file.isEmpty())
1502 tempDirED->setText(file);
1506 void PrefPaths::selectBackupdir()
1508 QString file = browseDir(internalPath(backupDirED->text()),
1509 qt_("Select a backups directory"));
1510 if (!file.isEmpty())
1511 backupDirED->setText(file);
1515 void PrefPaths::selectWorkingdir()
1517 QString file = browseDir(internalPath(workingDirED->text()),
1518 qt_("Select a document directory"));
1519 if (!file.isEmpty())
1520 workingDirED->setText(file);
1524 void PrefPaths::selectThesaurusdir()
1526 QString file = browseDir(internalPath(thesaurusDirED->text()),
1527 qt_("Set the path to the thesaurus dictionaries"));
1528 if (!file.isEmpty())
1529 thesaurusDirED->setText(file);
1533 void PrefPaths::selectHunspelldir()
1535 QString file = browseDir(internalPath(hunspellDirED->text()),
1536 qt_("Set the path to the Hunspell dictionaries"));
1537 if (!file.isEmpty())
1538 hunspellDirED->setText(file);
1542 void PrefPaths::selectLyxPipe()
1544 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1545 qt_("Give a filename for the LyX server pipe"));
1546 if (!file.isEmpty())
1547 lyxserverDirED->setText(file);
1551 /////////////////////////////////////////////////////////////////////
1555 /////////////////////////////////////////////////////////////////////
1557 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1558 : PrefModule(catLanguage, N_("Spellchecker"), form)
1562 // FIXME: this check should test the target platform (darwin)
1563 #if defined(USE_MACOSX_PACKAGING)
1564 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1565 #define CONNECT_APPLESPELL
1567 #undef CONNECT_APPLESPELL
1569 #if defined(USE_ASPELL)
1570 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1572 #if defined(USE_ENCHANT)
1573 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1575 #if defined(USE_HUNSPELL)
1576 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1579 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1580 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1581 this, SIGNAL(changed()));
1582 connect(altLanguageED, SIGNAL(textChanged(QString)),
1583 this, SIGNAL(changed()));
1584 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1585 this, SIGNAL(changed()));
1586 connect(compoundWordCB, SIGNAL(clicked()),
1587 this, SIGNAL(changed()));
1588 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1589 this, SIGNAL(changed()));
1590 connect(spellcheckNotesCB, SIGNAL(clicked()),
1591 this, SIGNAL(changed()));
1593 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1594 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1596 spellcheckerCB->setEnabled(false);
1597 altLanguageED->setEnabled(false);
1598 escapeCharactersED->setEnabled(false);
1599 compoundWordCB->setEnabled(false);
1600 spellcheckContinuouslyCB->setEnabled(false);
1601 spellcheckNotesCB->setEnabled(false);
1606 void PrefSpellchecker::applyRC(LyXRC & rc) const
1608 string const speller = fromqstr(spellcheckerCB->
1609 itemData(spellcheckerCB->currentIndex()).toString());
1610 if (!speller.empty())
1611 rc.spellchecker = speller;
1612 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1613 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1614 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1615 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1616 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1620 void PrefSpellchecker::updateRC(LyXRC const & rc)
1622 spellcheckerCB->setCurrentIndex(
1623 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1624 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1625 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1626 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1627 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1628 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1632 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1634 QString spellchecker = spellcheckerCB->itemData(index).toString();
1636 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1641 /////////////////////////////////////////////////////////////////////
1645 /////////////////////////////////////////////////////////////////////
1648 PrefConverters::PrefConverters(GuiPreferences * form)
1649 : PrefModule(catFiles, N_("Converters"), form)
1653 connect(converterNewPB, SIGNAL(clicked()),
1654 this, SLOT(updateConverter()));
1655 connect(converterRemovePB, SIGNAL(clicked()),
1656 this, SLOT(removeConverter()));
1657 connect(converterModifyPB, SIGNAL(clicked()),
1658 this, SLOT(updateConverter()));
1659 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1660 this, SLOT(switchConverter()));
1661 #if QT_VERSION < 0x050e00
1662 connect(converterFromCO, SIGNAL(activated(QString)),
1663 this, SLOT(changeConverter()));
1664 connect(converterToCO, SIGNAL(activated(QString)),
1665 this, SLOT(changeConverter()));
1667 connect(converterFromCO, SIGNAL(textActivated(QString)),
1668 this, SLOT(changeConverter()));
1669 connect(converterToCO, SIGNAL(textActivated(QString)),
1670 this, SLOT(changeConverter()));
1672 connect(converterED, SIGNAL(textEdited(QString)),
1673 this, SLOT(changeConverter()));
1674 connect(converterFlagED, SIGNAL(textEdited(QString)),
1675 this, SLOT(changeConverter()));
1676 connect(converterNewPB, SIGNAL(clicked()),
1677 this, SIGNAL(changed()));
1678 connect(converterRemovePB, SIGNAL(clicked()),
1679 this, SIGNAL(changed()));
1680 connect(converterModifyPB, SIGNAL(clicked()),
1681 this, SIGNAL(changed()));
1682 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1683 this, SIGNAL(changed()));
1684 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1685 this, SIGNAL(changed()));
1687 converterED->setValidator(new NoNewLineValidator(converterED));
1688 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1689 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1690 //converterDefGB->setFocusProxy(convertersLW);
1694 void PrefConverters::applyRC(LyXRC & rc) const
1696 rc.use_converter_cache = cacheCB->isChecked();
1697 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1698 rc.use_converter_needauth = needauthCB->isChecked();
1699 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1703 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1704 cb->blockSignals(true);
1705 cb->setChecked(checked);
1706 cb->blockSignals(false);
1710 void PrefConverters::updateRC(LyXRC const & rc)
1712 cacheCB->setChecked(rc.use_converter_cache);
1713 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1714 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1716 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1721 void PrefConverters::updateGui()
1723 QString const pattern("%1 -> %2");
1724 form_->formats().sort();
1725 form_->converters().update(form_->formats());
1726 // save current selection
1729 .arg(converterFromCO->currentText())
1730 .arg(converterToCO->currentText());
1732 converterFromCO->clear();
1733 converterToCO->clear();
1735 for (Format const & f : form_->formats()) {
1736 QString const name = toqstr(translateIfPossible(f.prettyname()));
1737 converterFromCO->addItem(name);
1738 converterToCO->addItem(name);
1741 // currentRowChanged(int) is also triggered when updating the listwidget
1742 // block signals to avoid unnecessary calls to switchConverter()
1743 convertersLW->blockSignals(true);
1744 convertersLW->clear();
1746 for (Converter const & c : form_->converters()) {
1747 QString const name =
1749 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1750 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1751 int type = form_->converters().getNumber(c.From()->name(),
1753 new QListWidgetItem(name, convertersLW, type);
1755 convertersLW->sortItems(Qt::AscendingOrder);
1756 convertersLW->blockSignals(false);
1758 // restore selection
1759 if (current != pattern.arg(QString()).arg(QString())) {
1760 QList<QListWidgetItem *> const item =
1761 convertersLW->findItems(current, Qt::MatchExactly);
1762 if (!item.isEmpty())
1763 convertersLW->setCurrentItem(item.at(0));
1766 // select first element if restoring failed
1767 if (convertersLW->currentRow() == -1)
1768 convertersLW->setCurrentRow(0);
1774 void PrefConverters::switchConverter()
1776 int const cnr = convertersLW->currentItem()->type();
1777 Converter const & c(form_->converters().get(cnr));
1778 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1779 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1780 converterED->setText(toqstr(c.command()));
1781 converterFlagED->setText(toqstr(c.flags()));
1787 void PrefConverters::changeConverter()
1793 void PrefConverters::updateButtons()
1795 if (form_->formats().empty())
1797 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1798 Format const & to = form_->formats().get(converterToCO->currentIndex());
1799 int const sel = form_->converters().getNumber(from.name(), to.name());
1800 bool const known = sel >= 0;
1801 bool const valid = !(converterED->text().isEmpty()
1802 || from.name() == to.name());
1807 if (convertersLW->count() > 0) {
1808 int const cnr = convertersLW->currentItem()->type();
1809 Converter const & c = form_->converters().get(cnr);
1810 old_command = c.command();
1811 old_flag = c.flags();
1814 string const new_command = fromqstr(converterED->text());
1815 string const new_flag = fromqstr(converterFlagED->text());
1817 bool modified = (old_command != new_command || old_flag != new_flag);
1819 converterModifyPB->setEnabled(valid && known && modified);
1820 converterNewPB->setEnabled(valid && !known);
1821 converterRemovePB->setEnabled(known);
1823 maxAgeLE->setEnabled(cacheCB->isChecked());
1824 maxAgeLA->setEnabled(cacheCB->isChecked());
1829 // specify unique from/to or it doesn't appear. This is really bad UI
1830 // this is why we can use the same function for both new and modify
1831 void PrefConverters::updateConverter()
1833 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1834 Format const & to = form_->formats().get(converterToCO->currentIndex());
1835 string const flags = fromqstr(converterFlagED->text());
1836 string const command = fromqstr(converterED->text());
1838 Converter const * old =
1839 form_->converters().getConverter(from.name(), to.name());
1840 form_->converters().add(from.name(), to.name(), command, flags);
1843 form_->converters().updateLast(form_->formats());
1847 // Remove all files created by this converter from the cache, since
1848 // the modified converter might create different files.
1849 ConverterCache::get().remove_all(from.name(), to.name());
1853 void PrefConverters::removeConverter()
1855 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1856 Format const & to = form_->formats().get(converterToCO->currentIndex());
1857 form_->converters().erase(from.name(), to.name());
1861 // Remove all files created by this converter from the cache, since
1862 // a possible new converter might create different files.
1863 ConverterCache::get().remove_all(from.name(), to.name());
1867 void PrefConverters::on_cacheCB_stateChanged(int state)
1869 maxAgeLE->setEnabled(state == Qt::Checked);
1870 maxAgeLA->setEnabled(state == Qt::Checked);
1875 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1877 needauthCB->setEnabled(!checked);
1881 void PrefConverters::on_needauthCB_toggled(bool checked)
1888 int ret = frontend::Alert::prompt(
1889 _("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!"),
1890 0, 0, _("&No"), _("&Yes"));
1894 setCheckboxBlockSignals(needauthCB, true);
1898 /////////////////////////////////////////////////////////////////////
1902 /////////////////////////////////////////////////////////////////////
1904 class FormatValidator : public QValidator
1907 FormatValidator(QWidget *, Formats const & f);
1908 void fixup(QString & input) const override;
1909 QValidator::State validate(QString & input, int & pos) const override;
1911 virtual QString toString(Format const & format) const = 0;
1913 Formats const & formats_;
1917 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1918 : QValidator(parent), formats_(f)
1923 void FormatValidator::fixup(QString & input) const
1925 Formats::const_iterator cit = formats_.begin();
1926 Formats::const_iterator end = formats_.end();
1927 for (; cit != end; ++cit) {
1928 QString const name = toString(*cit);
1929 if (distance(formats_.begin(), cit) == nr()) {
1937 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1939 Formats::const_iterator cit = formats_.begin();
1940 Formats::const_iterator end = formats_.end();
1941 bool unknown = true;
1942 for (; unknown && cit != end; ++cit) {
1943 QString const name = toString(*cit);
1944 if (distance(formats_.begin(), cit) != nr())
1945 unknown = name != input;
1948 if (unknown && !input.isEmpty())
1949 return QValidator::Acceptable;
1951 return QValidator::Intermediate;
1955 int FormatValidator::nr() const
1957 QComboBox * p = qobject_cast<QComboBox *>(parent());
1958 return p->itemData(p->currentIndex()).toInt();
1962 /////////////////////////////////////////////////////////////////////
1964 // FormatNameValidator
1966 /////////////////////////////////////////////////////////////////////
1968 class FormatNameValidator : public FormatValidator
1971 FormatNameValidator(QWidget * parent, Formats const & f)
1972 : FormatValidator(parent, f)
1975 QString toString(Format const & format) const override
1977 return toqstr(format.name());
1982 /////////////////////////////////////////////////////////////////////
1984 // FormatPrettynameValidator
1986 /////////////////////////////////////////////////////////////////////
1988 class FormatPrettynameValidator : public FormatValidator
1991 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1992 : FormatValidator(parent, f)
1995 QString toString(Format const & format) const override
1997 return toqstr(translateIfPossible(format.prettyname()));
2002 /////////////////////////////////////////////////////////////////////
2006 /////////////////////////////////////////////////////////////////////
2008 PrefFileformats::PrefFileformats(GuiPreferences * form)
2009 : PrefModule(catFiles, N_("File Formats"), form)
2013 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2014 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2015 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2016 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2017 editorED->setValidator(new NoNewLineValidator(editorED));
2018 viewerED->setValidator(new NoNewLineValidator(viewerED));
2019 copierED->setValidator(new NoNewLineValidator(copierED));
2021 connect(documentCB, SIGNAL(clicked()),
2022 this, SLOT(setFlags()));
2023 connect(vectorCB, SIGNAL(clicked()),
2024 this, SLOT(setFlags()));
2025 connect(exportMenuCB, SIGNAL(clicked()),
2026 this, SLOT(setFlags()));
2027 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2028 this, SLOT(updatePrettyname()));
2029 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2030 this, SIGNAL(changed()));
2031 #if QT_VERSION < 0x050e00
2032 connect(defaultFormatCB, SIGNAL(activated(QString)),
2033 this, SIGNAL(changed()));
2034 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2035 this, SIGNAL(changed()));
2036 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2037 this, SIGNAL(changed()));
2039 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2040 this, SIGNAL(changed()));
2041 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2042 this, SIGNAL(changed()));
2043 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2044 this, SIGNAL(changed()));
2046 connect(viewerCO, SIGNAL(activated(int)),
2047 this, SIGNAL(changed()));
2048 connect(editorCO, SIGNAL(activated(int)),
2049 this, SIGNAL(changed()));
2055 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2057 if (shortcut.empty())
2060 string l10n_format =
2061 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2062 return split(l10n_format, '|');
2068 void PrefFileformats::applyRC(LyXRC & rc) const
2070 QString const default_format = defaultFormatCB->itemData(
2071 defaultFormatCB->currentIndex()).toString();
2072 rc.default_view_format = fromqstr(default_format);
2073 QString const default_otf_format = defaultOTFFormatCB->itemData(
2074 defaultOTFFormatCB->currentIndex()).toString();
2075 rc.default_otf_view_format = fromqstr(default_otf_format);
2076 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2077 defaultPlatexFormatCB->currentIndex()).toString();
2078 rc.default_platex_view_format = fromqstr(default_platex_format);
2082 void PrefFileformats::updateRC(LyXRC const & rc)
2084 viewer_alternatives = rc.viewer_alternatives;
2085 editor_alternatives = rc.editor_alternatives;
2086 bool const init = defaultFormatCB->currentText().isEmpty();
2090 defaultFormatCB->findData(toqstr(rc.default_view_format));
2091 defaultFormatCB->setCurrentIndex(pos);
2092 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2093 defaultOTFFormatCB->setCurrentIndex(pos);
2094 defaultOTFFormatCB->setCurrentIndex(pos);
2095 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2096 defaultPlatexFormatCB->setCurrentIndex(pos);
2097 defaultPlatexFormatCB->setCurrentIndex(pos);
2102 void PrefFileformats::updateView()
2104 QString const current = formatsCB->currentText();
2105 QString const current_def = defaultFormatCB->currentText();
2106 QString const current_def_otf = defaultOTFFormatCB->currentText();
2107 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2109 // update comboboxes with formats
2110 formatsCB->blockSignals(true);
2111 defaultFormatCB->blockSignals(true);
2112 defaultOTFFormatCB->blockSignals(true);
2113 defaultPlatexFormatCB->blockSignals(true);
2115 defaultFormatCB->clear();
2116 defaultOTFFormatCB->clear();
2117 defaultPlatexFormatCB->clear();
2118 form_->formats().sort();
2119 for (Format const & f : form_->formats()) {
2120 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2121 formatsCB->addItem(prettyname,
2122 QVariant(form_->formats().getNumber(f.name())));
2123 if (f.viewer().empty())
2125 if (form_->converters().isReachable("xhtml", f.name())
2126 || form_->converters().isReachable("dviluatex", f.name())
2127 || form_->converters().isReachable("luatex", f.name())
2128 || form_->converters().isReachable("xetex", f.name())) {
2129 defaultFormatCB->addItem(prettyname,
2130 QVariant(toqstr(f.name())));
2131 defaultOTFFormatCB->addItem(prettyname,
2132 QVariant(toqstr(f.name())));
2134 if (form_->converters().isReachable("latex", f.name())
2135 || form_->converters().isReachable("pdflatex", f.name()))
2136 defaultFormatCB->addItem(prettyname,
2137 QVariant(toqstr(f.name())));
2138 if (form_->converters().isReachable("platex", f.name()))
2139 defaultPlatexFormatCB->addItem(prettyname,
2140 QVariant(toqstr(f.name())));
2144 // restore selections
2145 int item = formatsCB->findText(current, Qt::MatchExactly);
2146 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2147 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2148 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2149 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2150 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2151 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2152 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2153 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2154 formatsCB->blockSignals(false);
2155 defaultFormatCB->blockSignals(false);
2156 defaultOTFFormatCB->blockSignals(false);
2157 defaultPlatexFormatCB->blockSignals(false);
2161 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2163 if (form_->formats().empty())
2165 int const nr = formatsCB->itemData(i).toInt();
2166 Format const f = form_->formats().get(nr);
2168 formatED->setText(toqstr(f.name()));
2169 copierED->setText(toqstr(form_->movers().command(f.name())));
2170 extensionsED->setText(toqstr(f.extensions()));
2171 mimeED->setText(toqstr(f.mime()));
2172 shortcutED->setText(
2173 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2174 documentCB->setChecked((f.documentFormat()));
2175 vectorCB->setChecked((f.vectorFormat()));
2176 exportMenuCB->setChecked((f.inExportMenu()));
2177 exportMenuCB->setEnabled((f.documentFormat()));
2183 void PrefFileformats::setFlags()
2185 int flags = Format::none;
2186 if (documentCB->isChecked())
2187 flags |= Format::document;
2188 if (vectorCB->isChecked())
2189 flags |= Format::vector;
2190 if (exportMenuCB->isChecked())
2191 flags |= Format::export_menu;
2192 currentFormat().setFlags(flags);
2193 exportMenuCB->setEnabled(documentCB->isChecked());
2198 void PrefFileformats::on_copierED_textEdited(const QString & s)
2200 string const fmt = fromqstr(formatED->text());
2201 form_->movers().set(fmt, fromqstr(s));
2206 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2208 currentFormat().setExtensions(fromqstr(s));
2213 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2215 currentFormat().setViewer(fromqstr(s));
2220 void PrefFileformats::on_editorED_textEdited(const QString & s)
2222 currentFormat().setEditor(fromqstr(s));
2227 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2229 currentFormat().setMime(fromqstr(s));
2234 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2236 string const new_shortcut = fromqstr(s);
2237 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2238 currentFormat().shortcut()))
2240 currentFormat().setShortcut(new_shortcut);
2245 void PrefFileformats::on_formatED_editingFinished()
2247 string const newname = fromqstr(formatED->displayText());
2248 string const oldname = currentFormat().name();
2249 if (newname == oldname)
2251 if (form_->converters().formatIsUsed(oldname)) {
2252 Alert::error(_("Format in use"),
2253 _("You cannot change a format's short name "
2254 "if the format is used by a converter. "
2255 "Please remove the converter first."));
2260 currentFormat().setName(newname);
2265 void PrefFileformats::on_formatED_textChanged(const QString &)
2267 QString t = formatED->text();
2269 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2270 setValid(formatLA, valid);
2274 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2276 QString t = formatsCB->currentText();
2278 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2279 setValid(formatsLA, valid);
2283 void PrefFileformats::updatePrettyname()
2285 QString const newname = formatsCB->currentText();
2286 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2289 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2297 void updateComboBox(LyXRC::Alternatives const & alts,
2298 string const & fmt, QComboBox * combo)
2300 LyXRC::Alternatives::const_iterator it =
2302 if (it != alts.end()) {
2303 LyXRC::CommandSet const & cmds = it->second;
2304 LyXRC::CommandSet::const_iterator sit =
2306 LyXRC::CommandSet::const_iterator const sen =
2308 for (; sit != sen; ++sit) {
2309 QString const qcmd = toqstr(*sit);
2310 combo->addItem(qcmd, qcmd);
2317 void PrefFileformats::updateViewers()
2319 Format const f = currentFormat();
2320 viewerCO->blockSignals(true);
2322 viewerCO->addItem(qt_("None"), QString());
2323 if (os::canAutoOpenFile(f.extension(), os::VIEW))
2324 viewerCO->addItem(qt_("System Default"), QString("auto"));
2325 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2326 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2327 viewerCO->blockSignals(false);
2329 int pos = viewerCO->findData(toqstr(f.viewer()));
2332 viewerED->setEnabled(false);
2333 viewerCO->setCurrentIndex(pos);
2335 viewerED->setEnabled(true);
2336 viewerED->setText(toqstr(f.viewer()));
2337 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2342 void PrefFileformats::updateEditors()
2344 Format const f = currentFormat();
2345 editorCO->blockSignals(true);
2347 editorCO->addItem(qt_("None"), QString());
2348 if (os::canAutoOpenFile(f.extension(), os::EDIT))
2349 editorCO->addItem(qt_("System Default"), QString("auto"));
2350 updateComboBox(editor_alternatives, f.name(), editorCO);
2351 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2352 editorCO->blockSignals(false);
2354 int pos = editorCO->findData(toqstr(f.editor()));
2357 editorED->setEnabled(false);
2358 editorCO->setCurrentIndex(pos);
2360 editorED->setEnabled(true);
2361 editorED->setText(toqstr(f.editor()));
2362 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2367 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2369 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2370 viewerED->setEnabled(custom);
2372 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2376 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2378 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2379 editorED->setEnabled(custom);
2381 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2385 Format & PrefFileformats::currentFormat()
2387 int const i = formatsCB->currentIndex();
2388 int const nr = formatsCB->itemData(i).toInt();
2389 return form_->formats().get(nr);
2393 void PrefFileformats::on_formatNewPB_clicked()
2395 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2397 formatsCB->setCurrentIndex(0);
2398 formatsCB->setFocus(Qt::OtherFocusReason);
2402 void PrefFileformats::on_formatRemovePB_clicked()
2404 int const i = formatsCB->currentIndex();
2405 int const nr = formatsCB->itemData(i).toInt();
2406 string const current_text = form_->formats().get(nr).name();
2407 if (form_->converters().formatIsUsed(current_text)) {
2408 Alert::error(_("Format in use"),
2409 _("Cannot remove a Format used by a Converter. "
2410 "Remove the converter first."));
2414 form_->formats().erase(current_text);
2417 on_formatsCB_editTextChanged(formatsCB->currentText());
2422 /////////////////////////////////////////////////////////////////////
2426 /////////////////////////////////////////////////////////////////////
2428 PrefLanguage::PrefLanguage(GuiPreferences * form)
2429 : PrefModule(catLanguage, N_("Language"), form)
2433 connect(visualCursorRB, SIGNAL(clicked()),
2434 this, SIGNAL(changed()));
2435 connect(logicalCursorRB, SIGNAL(clicked()),
2436 this, SIGNAL(changed()));
2437 connect(markForeignCB, SIGNAL(clicked()),
2438 this, SIGNAL(changed()));
2439 connect(respectOSkbdCB, SIGNAL(clicked()),
2440 this, SIGNAL(changed()));
2441 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2442 this, SIGNAL(changed()));
2443 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2444 this, SIGNAL(changed()));
2445 connect(languagePackageCO, SIGNAL(activated(int)),
2446 this, SIGNAL(changed()));
2447 connect(languagePackageED, SIGNAL(textChanged(QString)),
2448 this, SIGNAL(changed()));
2449 connect(globalCB, SIGNAL(clicked()),
2450 this, SIGNAL(changed()));
2451 connect(startCommandED, SIGNAL(textChanged(QString)),
2452 this, SIGNAL(changed()));
2453 connect(endCommandED, SIGNAL(textChanged(QString)),
2454 this, SIGNAL(changed()));
2455 connect(uiLanguageCO, SIGNAL(activated(int)),
2456 this, SIGNAL(changed()));
2457 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2458 this, SIGNAL(changed()));
2459 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2460 this, SIGNAL(changed()));
2461 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2462 this, SIGNAL(changed()));
2464 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2465 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2466 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2468 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2469 defaultDecimalSepED->setMaxLength(1);
2471 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2472 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2474 QAbstractItemModel * language_model = guiApp->languageModel();
2475 language_model->sort(0);
2476 uiLanguageCO->blockSignals(true);
2477 uiLanguageCO->clear();
2478 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2479 for (int i = 0; i != language_model->rowCount(); ++i) {
2480 QModelIndex index = language_model->index(i, 0);
2481 // Filter the list based on the available translation and add
2482 // each language code only once
2483 string const name = fromqstr(index.data(Qt::UserRole).toString());
2484 Language const * lang = languages.getLanguage(name);
2487 // never remove the currently selected language
2488 if (name != form->rc().gui_language
2489 && name != lyxrc.gui_language
2490 && (!Messages::available(lang->code())
2491 || !lang->hasGuiSupport()))
2493 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2494 index.data(Qt::UserRole).toString());
2496 uiLanguageCO->blockSignals(false);
2498 // FIXME: restore this when it works (see discussion in #6450).
2499 respectOSkbdCB->hide();
2503 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2505 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2506 qt_("The change of user interface language will be fully "
2507 "effective only after a restart."));
2511 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2514 languagePackageED->setText(save_langpack_);
2515 else if (!languagePackageED->text().isEmpty()) {
2516 save_langpack_ = languagePackageED->text();
2517 languagePackageED->clear();
2519 languagePackageED->setEnabled(i == 2);
2523 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2525 defaultDecimalSepED->setEnabled(i == 1);
2529 void PrefLanguage::applyRC(LyXRC & rc) const
2531 rc.visual_cursor = visualCursorRB->isChecked();
2532 rc.mark_foreign_language = markForeignCB->isChecked();
2533 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2534 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2535 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2536 int const p = languagePackageCO->currentIndex();
2538 rc.language_package_selection = LyXRC::LP_AUTO;
2540 rc.language_package_selection = LyXRC::LP_BABEL;
2542 rc.language_package_selection = LyXRC::LP_CUSTOM;
2544 rc.language_package_selection = LyXRC::LP_NONE;
2545 rc.language_custom_package = fromqstr(languagePackageED->text());
2546 rc.language_global_options = globalCB->isChecked();
2547 rc.language_command_begin = fromqstr(startCommandED->text());
2548 rc.language_command_end = fromqstr(endCommandED->text());
2549 rc.gui_language = fromqstr(
2550 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2551 if (defaultDecimalSepCO->currentIndex() == 0)
2552 rc.default_decimal_sep = "locale";
2554 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2555 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2559 void PrefLanguage::updateRC(LyXRC const & rc)
2561 if (rc.visual_cursor)
2562 visualCursorRB->setChecked(true);
2564 logicalCursorRB->setChecked(true);
2565 markForeignCB->setChecked(rc.mark_foreign_language);
2566 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2567 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2568 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2569 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2570 if (languagePackageCO->currentIndex() == 2) {
2571 languagePackageED->setText(toqstr(rc.language_custom_package));
2572 languagePackageED->setEnabled(true);
2574 languagePackageED->clear();
2575 save_langpack_ = toqstr(rc.language_custom_package);
2576 languagePackageED->setEnabled(false);
2578 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2579 globalCB->setChecked(rc.language_global_options);
2580 startCommandED->setText(toqstr(rc.language_command_begin));
2581 endCommandED->setText(toqstr(rc.language_command_end));
2582 if (rc.default_decimal_sep == "locale") {
2583 defaultDecimalSepCO->setCurrentIndex(0);
2584 defaultDecimalSepED->clear();
2586 defaultDecimalSepCO->setCurrentIndex(1);
2587 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2589 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2590 defaultLengthUnitCO->setCurrentIndex(pos);
2592 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2593 uiLanguageCO->blockSignals(true);
2594 uiLanguageCO->setCurrentIndex(pos);
2595 uiLanguageCO->blockSignals(false);
2599 /////////////////////////////////////////////////////////////////////
2601 // PrefUserInterface
2603 /////////////////////////////////////////////////////////////////////
2605 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2606 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2610 connect(uiFilePB, SIGNAL(clicked()),
2611 this, SLOT(selectUi()));
2612 connect(uiFileED, SIGNAL(textChanged(QString)),
2613 this, SIGNAL(changed()));
2614 connect(iconSetCO, SIGNAL(activated(int)),
2615 this, SIGNAL(changed()));
2616 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2617 this, SIGNAL(changed()));
2618 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2619 this, SIGNAL(changed()));
2620 connect(tooltipCB, SIGNAL(toggled(bool)),
2621 this, SIGNAL(changed()));
2622 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2623 this, SIGNAL(changed()));
2624 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2625 this, SIGNAL(changed()));
2626 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2627 this, SIGNAL(changed()));
2628 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2629 this, SIGNAL(changed()));
2630 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2631 this, SIGNAL(changed()));
2632 lastfilesSB->setMaximum(maxlastfiles);
2634 iconSetCO->addItem(qt_("Default"), QString());
2635 iconSetCO->addItem(qt_("Classic"), "classic");
2636 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2638 if (guiApp->platformName() != "xcb"
2639 && !guiApp->platformName().contains("wayland"))
2640 useSystemThemeIconsCB->hide();
2644 void PrefUserInterface::applyRC(LyXRC & rc) const
2646 rc.icon_set = fromqstr(iconSetCO->itemData(
2647 iconSetCO->currentIndex()).toString());
2649 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2650 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2651 rc.num_lastfiles = lastfilesSB->value();
2652 rc.use_tooltip = tooltipCB->isChecked();
2653 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2654 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2655 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2656 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2657 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2661 void PrefUserInterface::updateRC(LyXRC const & rc)
2663 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2666 iconSetCO->setCurrentIndex(iconset);
2667 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2668 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2669 lastfilesSB->setValue(rc.num_lastfiles);
2670 tooltipCB->setChecked(rc.use_tooltip);
2671 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2672 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2673 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2674 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2675 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2679 void PrefUserInterface::selectUi()
2681 QString file = form_->browseUI(internalPath(uiFileED->text()));
2682 if (!file.isEmpty())
2683 uiFileED->setText(file);
2687 /////////////////////////////////////////////////////////////////////
2689 // PrefDocumentHandling
2691 /////////////////////////////////////////////////////////////////////
2693 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2694 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2698 connect(autoSaveCB, SIGNAL(toggled(bool)),
2699 autoSaveSB, SLOT(setEnabled(bool)));
2700 connect(autoSaveCB, SIGNAL(toggled(bool)),
2701 TextLabel1, SLOT(setEnabled(bool)));
2702 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2703 this, SIGNAL(changed()));
2704 connect(singleInstanceCB, SIGNAL(clicked()),
2705 this, SIGNAL(changed()));
2706 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2707 this, SIGNAL(changed()));
2708 connect(closeLastViewCO, SIGNAL(activated(int)),
2709 this, SIGNAL(changed()));
2710 connect(restoreCursorCB, SIGNAL(clicked()),
2711 this, SIGNAL(changed()));
2712 connect(loadSessionCB, SIGNAL(clicked()),
2713 this, SIGNAL(changed()));
2714 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2715 this, SIGNAL(changed()));
2716 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2717 this, SIGNAL(changed()));
2718 connect(autoSaveCB, SIGNAL(clicked()),
2719 this, SIGNAL(changed()));
2720 connect(backupCB, SIGNAL(clicked()),
2721 this, SIGNAL(changed()));
2722 connect(saveCompressedCB, SIGNAL(clicked()),
2723 this, SIGNAL(changed()));
2724 connect(saveOriginCB, SIGNAL(clicked()),
2725 this, SIGNAL(changed()));
2729 void PrefDocHandling::applyRC(LyXRC & rc) const
2731 rc.use_lastfilepos = restoreCursorCB->isChecked();
2732 rc.load_session = loadSessionCB->isChecked();
2733 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2734 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2735 rc.make_backup = backupCB->isChecked();
2736 rc.save_compressed = saveCompressedCB->isChecked();
2737 rc.save_origin = saveOriginCB->isChecked();
2738 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2739 rc.single_instance = singleInstanceCB->isChecked();
2740 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2742 switch (closeLastViewCO->currentIndex()) {
2744 rc.close_buffer_with_last_view = "yes";
2747 rc.close_buffer_with_last_view = "no";
2750 rc.close_buffer_with_last_view = "ask";
2758 void PrefDocHandling::updateRC(LyXRC const & rc)
2760 restoreCursorCB->setChecked(rc.use_lastfilepos);
2761 loadSessionCB->setChecked(rc.load_session);
2762 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2763 // convert to minutes
2764 bool autosave = rc.autosave > 0;
2765 int mins = rc.autosave / 60;
2768 autoSaveSB->setValue(mins);
2769 autoSaveCB->setChecked(autosave);
2770 autoSaveSB->setEnabled(autosave);
2771 backupCB->setChecked(rc.make_backup);
2772 saveCompressedCB->setChecked(rc.save_compressed);
2773 saveOriginCB->setChecked(rc.save_origin);
2774 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2775 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2776 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2777 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2778 if (rc.close_buffer_with_last_view == "yes")
2779 closeLastViewCO->setCurrentIndex(0);
2780 else if (rc.close_buffer_with_last_view == "no")
2781 closeLastViewCO->setCurrentIndex(1);
2782 else if (rc.close_buffer_with_last_view == "ask")
2783 closeLastViewCO->setCurrentIndex(2);
2784 if (rc.backupdir_path.empty())
2785 backupCB->setToolTip(qt_("If this is checked, a backup of the document is created "
2786 "in the current working directory. "
2787 "The backup file has the same name but the suffix '.lyx~'. "
2788 "Note that these files are hidden by default by some file managers. "
2789 "A dedicated backup directory can be set in the 'Paths' section."));
2791 docstring const tip = bformat(_("If this is checked, a backup of the document is created "
2792 "in the backup directory (%1$s). "
2793 "The backup file has the full original path and name as file name "
2794 "and the suffix \'.lyx~\' (e.g., !mydir!filename.lyx~). "
2795 "Note that these files are hidden by default by some file managers."),
2796 FileName(rc.backupdir_path).absoluteFilePath());
2797 backupCB->setToolTip(toqstr(tip));
2802 void PrefDocHandling::on_clearSessionPB_clicked()
2804 guiApp->clearSession();
2809 /////////////////////////////////////////////////////////////////////
2813 /////////////////////////////////////////////////////////////////////
2815 PrefEdit::PrefEdit(GuiPreferences * form)
2816 : PrefModule(catEditing, N_("Control"), form)
2820 connect(cursorFollowsCB, SIGNAL(clicked()),
2821 this, SIGNAL(changed()));
2822 connect(scrollBelowCB, SIGNAL(clicked()),
2823 this, SIGNAL(changed()));
2824 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2825 this, SIGNAL(changed()));
2826 connect(copyCTMarkupCB, SIGNAL(clicked()),
2827 this, SIGNAL(changed()));
2828 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2829 this, SIGNAL(changed()));
2830 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2831 this, SIGNAL(changed()));
2832 connect(macroEditStyleCO, SIGNAL(activated(int)),
2833 this, SIGNAL(changed()));
2834 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2835 this, SIGNAL(changed()));
2836 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2837 this, SIGNAL(changed()));
2838 connect(screenWidthLE, SIGNAL(textChanged(QString)),
2839 this, SIGNAL(changed()));
2840 connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
2841 this, SIGNAL(changed()));
2845 void PrefEdit::on_screenLimitCB_toggled(bool const state)
2847 screenWidthLE->setEnabled(state);
2848 screenWidthUnitCO->setEnabled(state);
2853 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2855 citationSearchLE->setEnabled(state);
2856 citationSearchLA->setEnabled(state);
2861 void PrefEdit::applyRC(LyXRC & rc) const
2863 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2864 rc.scroll_below_document = scrollBelowCB->isChecked();
2865 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2866 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2867 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2868 rc.group_layouts = groupEnvironmentsCB->isChecked();
2869 switch (macroEditStyleCO->currentIndex()) {
2870 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2871 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2872 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2874 rc.cursor_width = cursorWidthSB->value();
2875 rc.citation_search = citationSearchCB->isChecked();
2876 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2877 rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO));
2878 rc.screen_limit = screenLimitCB->isChecked();
2882 void PrefEdit::updateRC(LyXRC const & rc)
2884 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2885 scrollBelowCB->setChecked(rc.scroll_below_document);
2886 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2887 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2888 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2889 groupEnvironmentsCB->setChecked(rc.group_layouts);
2890 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2891 cursorWidthSB->setValue(rc.cursor_width);
2892 citationSearchCB->setChecked(rc.citation_search);
2893 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2894 citationSearchLE->setEnabled(rc.citation_search);
2895 citationSearchLA->setEnabled(rc.citation_search);
2896 lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
2897 screenWidthUnitCO->setEnabled(rc.screen_limit);
2898 screenLimitCB->setChecked(rc.screen_limit);
2899 screenWidthLE->setEnabled(rc.screen_limit);
2903 /////////////////////////////////////////////////////////////////////
2907 /////////////////////////////////////////////////////////////////////
2910 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2912 Ui::shortcutUi::setupUi(this);
2913 QDialog::setModal(true);
2914 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2918 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2919 : PrefModule(catEditing, N_("Shortcuts"), form),
2920 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2921 systemItem_(nullptr)
2925 shortcutsTW->setColumnCount(2);
2926 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2927 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2928 shortcutsTW->setSortingEnabled(true);
2929 // Multi-selection can be annoying.
2930 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2932 connect(bindFilePB, SIGNAL(clicked()),
2933 this, SLOT(selectBind()));
2934 connect(bindFileED, SIGNAL(textChanged(QString)),
2935 this, SIGNAL(changed()));
2937 shortcut_ = new GuiShortcutDialog(this);
2938 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2939 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2940 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2942 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2943 this, SIGNAL(changed()));
2944 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2945 shortcut_, SLOT(reject()));
2946 connect(shortcut_->clearPB, SIGNAL(clicked()),
2947 this, SLOT(shortcutClearPressed()));
2948 connect(shortcut_->removePB, SIGNAL(clicked()),
2949 this, SLOT(shortcutRemovePressed()));
2950 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2951 this, SLOT(shortcutOkPressed()));
2952 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2953 this, SLOT(shortcutCancelPressed()));
2957 void PrefShortcuts::applyRC(LyXRC & rc) const
2959 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2960 // write user_bind and user_unbind to .lyx/bind/user.bind
2961 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2962 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2963 lyxerr << "LyX could not create the user bind directory '"
2964 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2967 if (!bind_dir.isDirWritable()) {
2968 lyxerr << "LyX could not write to the user bind directory '"
2969 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2972 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2973 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2974 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2975 // immediately apply the keybindings. Why this is not done before?
2976 // The good thing is that the menus are updated automatically.
2977 theTopLevelKeymap().clear();
2978 theTopLevelKeymap().read("site");
2979 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2980 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2984 void PrefShortcuts::updateRC(LyXRC const & rc)
2986 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2988 system_bind_.clear();
2990 user_unbind_.clear();
2991 system_bind_.read("site");
2992 system_bind_.read(rc.bind_file);
2993 // \unbind in user.bind is added to user_unbind_
2994 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2995 updateShortcutsTW();
2999 void PrefShortcuts::updateShortcutsTW()
3001 shortcutsTW->clear();
3003 editItem_ = new QTreeWidgetItem(shortcutsTW);
3004 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
3005 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
3007 mathItem_ = new QTreeWidgetItem(shortcutsTW);
3008 mathItem_->setText(0, qt_("Mathematical Symbols"));
3009 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3011 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3012 bufferItem_->setText(0, qt_("Document and Window"));
3013 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3015 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3016 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3017 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3019 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3020 systemItem_->setText(0, qt_("System and Miscellaneous"));
3021 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3023 // listBindings(unbound=true) lists all bound and unbound lfuns
3024 // Items in this list is tagged by its source.
3025 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3027 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3029 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3030 KeyMap::UserUnbind);
3031 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3032 user_bindinglist.end());
3033 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3034 user_unbindinglist.end());
3036 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3037 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3038 for (; it != it_end; ++it)
3039 insertShortcutItem(it->request, it->sequence, it->tag);
3041 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3042 on_shortcutsTW_itemSelectionChanged();
3043 on_searchLE_textEdited();
3044 shortcutsTW->resizeColumnToContents(0);
3049 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3051 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3056 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3058 // Hide rebound system settings that are empty
3059 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3063 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3065 item->setData(0, Qt::UserRole, QVariant(tag));
3069 case KeyMap::System:
3071 case KeyMap::UserBind:
3074 case KeyMap::UserUnbind:
3075 font.setStrikeOut(true);
3077 // this item is not displayed now.
3078 case KeyMap::UserExtraUnbind:
3079 font.setStrikeOut(true);
3082 item->setHidden(isAlwaysHidden(*item));
3083 item->setFont(1, font);
3087 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3088 KeySequence const & seq, KeyMap::ItemType tag)
3090 FuncCode const action = lfun.action();
3091 string const action_name = lyxaction.getActionName(action);
3092 QString const lfun_name = toqstr(from_utf8(action_name)
3093 + ' ' + lfun.argument());
3094 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3096 QTreeWidgetItem * newItem = nullptr;
3097 // for unbind items, try to find an existing item in the system bind list
3098 if (tag == KeyMap::UserUnbind) {
3099 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3100 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3101 for (auto const & item : items) {
3102 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3107 // if not found, this unbind item is KeyMap::UserExtraUnbind
3108 // Such an item is not displayed to avoid confusion (what is
3109 // unmatched removed?).
3115 switch(lyxaction.getActionType(action)) {
3116 case LyXAction::Hidden:
3118 case LyXAction::Edit:
3119 newItem = new QTreeWidgetItem(editItem_);
3121 case LyXAction::Math:
3122 newItem = new QTreeWidgetItem(mathItem_);
3124 case LyXAction::Buffer:
3125 newItem = new QTreeWidgetItem(bufferItem_);
3127 case LyXAction::Layout:
3128 newItem = new QTreeWidgetItem(layoutItem_);
3130 case LyXAction::System:
3131 newItem = new QTreeWidgetItem(systemItem_);
3134 // this should not happen
3135 newItem = new QTreeWidgetItem(shortcutsTW);
3137 newItem->setText(0, lfun_name);
3138 newItem->setText(1, shortcut);
3141 // record BindFile representation to recover KeySequence when needed.
3142 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3143 setItemType(newItem, tag);
3148 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3150 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3151 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3152 modifyPB->setEnabled(!items.isEmpty());
3153 if (items.isEmpty())
3156 if (itemType(*items[0]) == KeyMap::UserUnbind)
3157 removePB->setText(qt_("Res&tore"));
3159 removePB->setText(qt_("Remo&ve"));
3163 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3169 void PrefShortcuts::modifyShortcut()
3171 QTreeWidgetItem * item = shortcutsTW->currentItem();
3172 if (item->flags() & Qt::ItemIsSelectable) {
3173 shortcut_->lfunLE->setText(item->text(0));
3174 save_lfun_ = item->text(0).trimmed();
3175 shortcut_->shortcutWG->setText(item->text(1));
3177 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3178 shortcut_->shortcutWG->setKeySequence(seq);
3179 shortcut_->shortcutWG->setFocus();
3185 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3187 // list of items that match lfun
3188 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3189 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3190 for (auto const & item : items) {
3191 if (isAlwaysHidden(*item)) {
3192 setItemType(item, KeyMap::System);
3194 shortcutsTW->setCurrentItem(item);
3201 void PrefShortcuts::removeShortcut()
3203 // it seems that only one item can be selected, but I am
3204 // removing all selected items anyway.
3205 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3206 for (auto & item : items) {
3207 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3208 string lfun = fromqstr(item->text(0));
3209 FuncRequest const func = lyxaction.lookupFunc(lfun);
3211 switch (itemType(*item)) {
3212 case KeyMap::System: {
3213 // for system bind, we do not touch the item
3214 // but add an user unbind item
3215 user_unbind_.bind(shortcut, func);
3216 setItemType(item, KeyMap::UserUnbind);
3217 removePB->setText(qt_("Res&tore"));
3220 case KeyMap::UserBind: {
3221 // for user_bind, we remove this bind
3222 QTreeWidgetItem * parent = item->parent();
3223 int itemIdx = parent->indexOfChild(item);
3224 parent->takeChild(itemIdx);
3226 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3228 shortcutsTW->scrollToItem(parent);
3229 user_bind_.unbind(shortcut, func);
3230 // If this user binding hid an empty system binding, unhide the
3231 // latter and select it.
3232 unhideEmpty(item->text(0), true);
3235 case KeyMap::UserUnbind: {
3236 // for user_unbind, we remove the unbind, and the item
3237 // become KeyMap::System again.
3239 seq.parse(shortcut);
3240 // Ask the user to replace current binding
3241 if (!validateNewShortcut(func, seq, QString()))
3243 user_unbind_.unbind(shortcut, func);
3244 setItemType(item, KeyMap::System);
3245 removePB->setText(qt_("Remo&ve"));
3248 case KeyMap::UserExtraUnbind: {
3249 // for user unbind that is not in system bind file,
3250 // remove this unbind file
3251 QTreeWidgetItem * parent = item->parent();
3252 parent->takeChild(parent->indexOfChild(item));
3253 user_unbind_.unbind(shortcut, func);
3260 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3262 for (auto item : items) {
3263 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3264 string lfun = fromqstr(item->text(0));
3265 FuncRequest const func = lyxaction.lookupFunc(lfun);
3267 switch (itemType(*item)) {
3268 case KeyMap::System:
3269 // for system bind, we do not touch the item
3270 // but add an user unbind item
3271 user_unbind_.bind(shortcut, func);
3272 setItemType(item, KeyMap::UserUnbind);
3275 case KeyMap::UserBind: {
3276 // for user_bind, we remove this bind
3277 QTreeWidgetItem * parent = item->parent();
3278 int itemIdx = parent->indexOfChild(item);
3279 parent->takeChild(itemIdx);
3280 user_bind_.unbind(shortcut, func);
3281 unhideEmpty(item->text(0), false);
3291 void PrefShortcuts::selectBind()
3293 QString file = form_->browsebind(internalPath(bindFileED->text()));
3294 if (!file.isEmpty()) {
3295 bindFileED->setText(file);
3296 system_bind_ = KeyMap();
3297 system_bind_.read(fromqstr(file));
3298 updateShortcutsTW();
3303 void PrefShortcuts::on_modifyPB_pressed()
3309 void PrefShortcuts::on_newPB_pressed()
3311 shortcut_->lfunLE->clear();
3312 shortcut_->shortcutWG->reset();
3313 save_lfun_ = QString();
3318 void PrefShortcuts::on_removePB_pressed()
3325 void PrefShortcuts::on_searchLE_textEdited()
3327 if (searchLE->text().isEmpty()) {
3328 // show all hidden items
3329 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3331 (*it)->setHidden(isAlwaysHidden(**it));
3332 // close all categories
3333 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3334 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3337 // search both columns
3338 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3339 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3340 matched += shortcutsTW->findItems(searchLE->text(),
3341 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3343 // hide everyone (to avoid searching in matched QList repeatedly
3344 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3346 (*it++)->setHidden(true);
3347 // show matched items
3348 for (auto & item : matched)
3349 if (!isAlwaysHidden(*item)) {
3350 item->setHidden(false);
3352 item->parent()->setExpanded(true);
3357 docstring makeCmdString(FuncRequest const & f)
3359 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3360 if (!f.argument().empty())
3361 actionStr += " " + f.argument();
3366 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3368 FuncRequest res = user_bind_.getBinding(k);
3369 if (res != FuncRequest::unknown)
3371 res = system_bind_.getBinding(k);
3373 // Check if it is unbound. Note: user_unbind_ can only unbind one
3374 // FuncRequest per key sequence.
3375 if (user_unbind_.getBinding(k) == res)
3376 return FuncRequest::unknown;
3381 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3382 KeySequence const & k,
3383 QString const & lfun_to_modify)
3385 if (func.action() == LFUN_UNKNOWN_ACTION) {
3386 Alert::error(_("Failed to create shortcut"),
3387 _("Unknown or invalid LyX function"));
3391 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3392 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3393 // and how it is used in GuiPrefs::shortcutOkPressed.
3394 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3395 Alert::error(_("Failed to create shortcut"),
3396 _("This LyX function is hidden and cannot be bound."));
3400 if (k.length() == 0) {
3401 Alert::error(_("Failed to create shortcut"),
3402 _("Invalid or empty key sequence"));
3406 FuncRequest oldBinding = currentBinding(k);
3407 if (oldBinding == func)
3408 // nothing to change
3411 // make sure this key isn't already bound---and, if so, prompt user
3412 // (exclude the lfun the user already wants to modify)
3413 docstring const action_string = makeCmdString(oldBinding);
3414 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3415 && lfun_to_modify != toqstr(action_string)) {
3416 docstring const new_action_string = makeCmdString(func);
3417 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3419 "Are you sure you want to unbind the "
3420 "current shortcut and bind it to %3$s?"),
3421 k.print(KeySequence::ForGui), action_string,
3423 int ret = Alert::prompt(_("Redefine shortcut?"),
3424 text, 0, 1, _("&Redefine"), _("&Cancel"));
3427 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3428 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3429 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3430 deactivateShortcuts(items);
3436 void PrefShortcuts::shortcutOkPressed()
3438 QString const new_lfun = shortcut_->lfunLE->text();
3439 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3440 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3442 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3443 // "modify", or is empty if they clicked "new" (which I do not really like)
3444 if (!validateNewShortcut(func, k, save_lfun_))
3447 if (!save_lfun_.isEmpty()) {
3448 // real modification of the lfun's shortcut,
3449 // so remove the previous one
3450 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3451 deactivateShortcuts(to_modify);
3454 shortcut_->accept();
3456 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3458 user_bind_.bind(&k, func);
3459 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3461 item->parent()->setExpanded(true);
3462 shortcutsTW->setCurrentItem(item);
3463 shortcutsTW->scrollToItem(item);
3465 Alert::error(_("Failed to create shortcut"),
3466 _("Can not insert shortcut to the list"));
3472 void PrefShortcuts::shortcutCancelPressed()
3474 shortcut_->shortcutWG->reset();
3478 void PrefShortcuts::shortcutClearPressed()
3480 shortcut_->shortcutWG->reset();
3484 void PrefShortcuts::shortcutRemovePressed()
3486 shortcut_->shortcutWG->removeFromSequence();
3490 /////////////////////////////////////////////////////////////////////
3494 /////////////////////////////////////////////////////////////////////
3496 PrefIdentity::PrefIdentity(GuiPreferences * form)
3497 : PrefModule(QString(), N_("Identity"), form)
3501 connect(nameED, SIGNAL(textChanged(QString)),
3502 this, SIGNAL(changed()));
3503 connect(emailED, SIGNAL(textChanged(QString)),
3504 this, SIGNAL(changed()));
3505 connect(initialsED, SIGNAL(textChanged(QString)),
3506 this, SIGNAL(changed()));
3508 nameED->setValidator(new NoNewLineValidator(nameED));
3509 emailED->setValidator(new NoNewLineValidator(emailED));
3510 initialsED->setValidator(new NoNewLineValidator(initialsED));
3514 void PrefIdentity::applyRC(LyXRC & rc) const
3516 rc.user_name = fromqstr(nameED->text());
3517 rc.user_email = fromqstr(emailED->text());
3518 rc.user_initials = fromqstr(initialsED->text());
3522 void PrefIdentity::updateRC(LyXRC const & rc)
3524 nameED->setText(toqstr(rc.user_name));
3525 emailED->setText(toqstr(rc.user_email));
3526 initialsED->setText(toqstr(rc.user_initials));
3531 /////////////////////////////////////////////////////////////////////
3535 /////////////////////////////////////////////////////////////////////
3537 GuiPreferences::GuiPreferences(GuiView & lv)
3538 : GuiDialog(lv, "prefs", qt_("Preferences"))
3542 QDialog::setModal(false);
3544 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3545 this, SLOT(slotButtonBox(QAbstractButton *)));
3547 addModule(new PrefUserInterface(this));
3548 addModule(new PrefDocHandling(this));
3549 addModule(new PrefEdit(this));
3550 addModule(new PrefShortcuts(this));
3551 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3552 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3553 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3554 addModule(screenfonts);
3555 addModule(new PrefColors(this));
3556 addModule(new PrefDisplay(this));
3557 addModule(new PrefInput(this));
3558 addModule(new PrefCompletion(this));
3560 addModule(new PrefPaths(this));
3562 addModule(new PrefIdentity(this));
3564 addModule(new PrefLanguage(this));
3565 addModule(new PrefSpellchecker(this));
3567 PrefOutput * output = new PrefOutput(this);
3569 addModule(new PrefLatex(this));
3571 PrefConverters * converters = new PrefConverters(this);
3572 PrefFileformats * formats = new PrefFileformats(this);
3573 connect(formats, SIGNAL(formatsChanged()),
3574 converters, SLOT(updateGui()));
3575 addModule(converters);
3578 prefsPS->setCurrentPanel("User Interface");
3580 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3581 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3582 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3583 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3584 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3586 guilyxfiles_ = new GuiLyXFiles(lv);
3587 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3588 this, SLOT(slotFileSelected(QString)));
3592 void GuiPreferences::addModule(PrefModule * module)
3594 LASSERT(module, return);
3595 if (module->category().isEmpty())
3596 prefsPS->addPanel(module, module->title());
3598 prefsPS->addPanel(module, module->title(), module->category());
3599 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3600 modules_.push_back(module);
3604 void GuiPreferences::change_adaptor()
3610 void GuiPreferences::applyRC(LyXRC & rc) const
3612 size_t end = modules_.size();
3613 for (size_t i = 0; i != end; ++i)
3614 modules_[i]->applyRC(rc);
3618 void GuiPreferences::updateRC(LyXRC const & rc)
3620 size_t const end = modules_.size();
3621 for (size_t i = 0; i != end; ++i)
3622 modules_[i]->updateRC(rc);
3626 void GuiPreferences::applyView()
3632 bool GuiPreferences::initialiseParams(string const &)
3635 formats_ = theFormats();
3636 converters_ = theConverters();
3637 converters_.update(formats_);
3638 movers_ = theMovers();
3642 // Make sure that the bc is in the INITIAL state
3643 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3650 void GuiPreferences::dispatchParams()
3653 rc_.write(ss, true);
3654 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3655 // issue prefsApplied signal. This will update the
3656 // localized screen font sizes.
3658 // FIXME: these need lfuns
3660 Author const & author =
3661 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3662 from_utf8(rc_.user_initials));
3663 theBufferList().recordCurrentAuthor(author);
3665 theFormats() = formats_;
3667 theConverters() = converters_;
3668 theConverters().update(formats_);
3669 theConverters().buildGraph();
3670 theBufferList().invalidateConverterCache();
3672 theMovers() = movers_;
3674 for (string const & color : colors_)
3675 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3679 if (!tempSaveCB->isChecked())
3680 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3684 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3686 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3690 void GuiPreferences::slotFileSelected(QString const file)
3696 QString GuiPreferences::browseLibFile(QString const & dir,
3697 QString const & name, QString const & ext)
3701 guilyxfiles_->passParams(fromqstr(dir));
3702 guilyxfiles_->selectItem(name);
3703 guilyxfiles_->exec();
3705 QString const result = uifile_;
3707 // remove the extension if it is the default one
3708 QString noextresult;
3709 if (getExtension(result) == ext)
3710 noextresult = removeExtension(result);
3712 noextresult = result;
3714 // remove the directory, if it is the default one
3715 QString const file = onlyFileName(noextresult);
3716 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3723 QString GuiPreferences::browsebind(QString const & file)
3725 return browseLibFile("bind", file, "bind");
3729 QString GuiPreferences::browseUI(QString const & file)
3731 return browseLibFile("ui", file, "ui");
3735 QString GuiPreferences::browsekbmap(QString const & file)
3737 return browseLibFile("kbd", file, "kmap");
3741 QString GuiPreferences::browse(QString const & file,
3742 QString const & title) const
3744 return browseFile(file, title, QStringList(), true);
3748 } // namespace frontend
3751 #include "moc_GuiPrefs.cpp"