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 <QFontDatabase>
60 #include <QHeaderView>
62 #include <QMessageBox>
63 #include <QPushButton>
66 #include <QStyleFactory>
67 #include <QTreeWidget>
68 #include <QTreeWidgetItem>
79 using namespace lyx::support;
80 using namespace lyx::support::os;
84 /////////////////////////////////////////////////////////////////////
88 /////////////////////////////////////////////////////////////////////
92 QString const catLookAndFeel = N_("Look & Feel");
93 QString const catEditing = N_("Editing");
94 QString const catLanguage = N_("Language Settings");
95 QString const catOutput = N_("Output");
96 QString const catFiles = N_("File Handling");
98 static void parseFontName(QString const & mangled0,
99 string & name, string & foundry)
101 string mangled = fromqstr(mangled0);
102 size_t const idx = mangled.find('[');
103 if (idx == string::npos || idx == 0) {
107 name = mangled.substr(0, idx - 1);
108 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
113 static void setComboxFont(QComboBox * cb, string const & family,
114 string const & foundry)
116 QString fontname = toqstr(family);
117 if (!foundry.empty())
118 fontname += " [" + toqstr(foundry) + ']';
120 for (int i = 0; i != cb->count(); ++i) {
121 if (cb->itemText(i) == fontname) {
122 cb->setCurrentIndex(i);
127 // Try matching without foundry name
129 // We count in reverse in order to prefer the Xft foundry
130 for (int i = cb->count(); --i >= 0;) {
131 string name, fnt_foundry;
132 parseFontName(cb->itemText(i), name, fnt_foundry);
133 if (compare_ascii_no_case(name, family) == 0) {
134 cb->setCurrentIndex(i);
139 // family alone can contain e.g. "Helvetica [Adobe]"
140 string tmpname, tmpfoundry;
141 parseFontName(toqstr(family), tmpname, tmpfoundry);
143 // We count in reverse in order to prefer the Xft foundry
144 for (int i = cb->count(); --i >= 0; ) {
145 string name, fnt_foundry;
146 parseFontName(cb->itemText(i), name, fnt_foundry);
147 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
148 cb->setCurrentIndex(i);
153 // Bleh, default fonts, and the names couldn't be found. Hack
158 QString const font_family = toqstr(family);
159 if (font_family == guiApp->romanFontName()) {
160 font.setStyleHint(QFont::Serif);
161 font.setFamily(font_family);
162 } else if (font_family == guiApp->sansFontName()) {
163 font.setStyleHint(QFont::SansSerif);
164 font.setFamily(font_family);
165 } else if (font_family == guiApp->typewriterFontName()) {
166 font.setStyleHint(QFont::TypeWriter);
167 font.setFamily(font_family);
169 LYXERR0("FAILED to find the default font: '"
170 << foundry << "', '" << family << '\'');
174 QFontInfo info(font);
175 string default_font_name, dummyfoundry;
176 parseFontName(info.family(), default_font_name, dummyfoundry);
177 LYXERR0("Apparent font is " << default_font_name);
179 for (int i = 0; i < cb->count(); ++i) {
180 LYXERR0("Looking at " << cb->itemText(i));
181 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
182 default_font_name) == 0) {
183 cb->setCurrentIndex(i);
188 LYXERR0("FAILED to find the font: '"
189 << foundry << "', '" << family << '\'');
193 /////////////////////////////////////////////////////////////////////
197 /////////////////////////////////////////////////////////////////////
199 PrefOutput::PrefOutput(GuiPreferences * form)
200 : PrefModule(catOutput, N_("General[[settings]]"), form)
204 dviCB->setValidator(new NoNewLineValidator(dviCB));
205 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
207 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
208 this, SIGNAL(changed()));
209 connect(overwriteCO, SIGNAL(activated(int)),
210 this, SIGNAL(changed()));
211 connect(dviCB, SIGNAL(editTextChanged(QString)),
212 this, SIGNAL(changed()));
213 connect(pdfCB, SIGNAL(editTextChanged(QString)),
214 this, SIGNAL(changed()));
215 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
216 this, SIGNAL(changed()));
217 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
218 this, SIGNAL(changed()));
219 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
220 this, SIGNAL(changed()));
222 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
223 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
224 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
227 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
228 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
229 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
230 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
232 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
233 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
234 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
235 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
236 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
237 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
238 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
242 void PrefOutput::applyRC(LyXRC & rc) const
244 rc.plaintext_linelen = plaintextLinelengthSB->value();
245 rc.forward_search_dvi = fromqstr(dviCB->currentText());
246 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
248 switch (overwriteCO->currentIndex()) {
250 rc.export_overwrite = NO_FILES;
253 rc.export_overwrite = MAIN_FILE;
256 rc.export_overwrite = ALL_FILES;
260 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
261 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
262 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
266 void PrefOutput::updateRC(LyXRC const & rc)
268 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
269 dviCB->setEditText(toqstr(rc.forward_search_dvi));
270 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
272 switch (rc.export_overwrite) {
274 overwriteCO->setCurrentIndex(0);
277 overwriteCO->setCurrentIndex(1);
280 overwriteCO->setCurrentIndex(2);
284 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
285 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
286 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
290 /////////////////////////////////////////////////////////////////////
294 /////////////////////////////////////////////////////////////////////
296 PrefInput::PrefInput(GuiPreferences * form)
297 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
301 connect(keymapCB, SIGNAL(clicked()),
302 this, SIGNAL(changed()));
303 connect(firstKeymapED, SIGNAL(textChanged(QString)),
304 this, SIGNAL(changed()));
305 connect(secondKeymapED, SIGNAL(textChanged(QString)),
306 this, SIGNAL(changed()));
307 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
308 this, SIGNAL(changed()));
309 connect(scrollzoomEnableCB, SIGNAL(clicked()),
310 this, SIGNAL(changed()));
311 connect(scrollzoomValueCO, SIGNAL(activated(int)),
312 this, SIGNAL(changed()));
313 connect(dontswapCB, SIGNAL(toggled(bool)),
314 this, SIGNAL(changed()));
315 connect(mmPasteCB, SIGNAL(toggled(bool)),
316 this, SIGNAL(changed()));
318 // reveal checkbox for switching Ctrl and Meta on Mac:
320 dontswapCB->setVisible(true);
322 dontswapCB->setVisible(false);
327 void PrefInput::applyRC(LyXRC & rc) const
329 // FIXME: can derive CB from the two EDs
330 rc.use_kbmap = keymapCB->isChecked();
331 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
332 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
333 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
334 if (scrollzoomEnableCB->isChecked()) {
335 switch (scrollzoomValueCO->currentIndex()) {
337 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
340 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
343 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
347 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
349 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
350 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
354 void PrefInput::updateRC(LyXRC const & rc)
356 // FIXME: can derive CB from the two EDs
357 keymapCB->setChecked(rc.use_kbmap);
358 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
359 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
360 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
361 switch (rc.scroll_wheel_zoom) {
362 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
363 scrollzoomEnableCB->setChecked(false);
365 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
366 scrollzoomEnableCB->setChecked(true);
367 scrollzoomValueCO->setCurrentIndex(0);
369 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
370 scrollzoomEnableCB->setChecked(true);
371 scrollzoomValueCO->setCurrentIndex(1);
373 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
374 scrollzoomEnableCB->setChecked(true);
375 scrollzoomValueCO->setCurrentIndex(2);
378 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
379 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
383 QString PrefInput::testKeymap(QString const & keymap)
385 return form_->browsekbmap(internalPath(keymap));
389 void PrefInput::on_firstKeymapPB_clicked(bool)
391 QString const file = testKeymap(firstKeymapED->text());
393 firstKeymapED->setText(file);
397 void PrefInput::on_secondKeymapPB_clicked(bool)
399 QString const file = testKeymap(secondKeymapED->text());
401 secondKeymapED->setText(file);
405 void PrefInput::on_keymapCB_toggled(bool keymap)
407 firstKeymapLA->setEnabled(keymap);
408 secondKeymapLA->setEnabled(keymap);
409 firstKeymapED->setEnabled(keymap);
410 secondKeymapED->setEnabled(keymap);
411 firstKeymapPB->setEnabled(keymap);
412 secondKeymapPB->setEnabled(keymap);
416 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
418 scrollzoomValueCO->setEnabled(enabled);
422 /////////////////////////////////////////////////////////////////////
426 /////////////////////////////////////////////////////////////////////
428 PrefCompletion::PrefCompletion(GuiPreferences * form)
429 : PrefModule(catEditing, N_("Input Completion"), form)
433 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
434 this, SIGNAL(changed()));
435 connect(inlineMathCB, SIGNAL(clicked()),
436 this, SIGNAL(changed()));
437 connect(inlineTextCB, SIGNAL(clicked()),
438 this, SIGNAL(changed()));
439 connect(inlineDotsCB, SIGNAL(clicked()),
440 this, SIGNAL(changed()));
441 connect(popupDelaySB, SIGNAL(valueChanged(double)),
442 this, SIGNAL(changed()));
443 connect(popupMathCB, SIGNAL(clicked()),
444 this, SIGNAL(changed()));
445 connect(autocorrectionCB, SIGNAL(clicked()),
446 this, SIGNAL(changed()));
447 connect(popupTextCB, SIGNAL(clicked()),
448 this, SIGNAL(changed()));
449 connect(popupAfterCompleteCB, SIGNAL(clicked()),
450 this, SIGNAL(changed()));
451 connect(cursorTextCB, SIGNAL(clicked()),
452 this, SIGNAL(changed()));
453 connect(minlengthSB, SIGNAL(valueChanged(int)),
454 this, SIGNAL(changed()));
458 void PrefCompletion::on_inlineTextCB_clicked()
464 void PrefCompletion::on_popupTextCB_clicked()
470 void PrefCompletion::enableCB()
472 cursorTextCB->setEnabled(
473 popupTextCB->isChecked() || inlineTextCB->isChecked());
477 void PrefCompletion::applyRC(LyXRC & rc) const
479 rc.completion_inline_delay = inlineDelaySB->value();
480 rc.completion_inline_math = inlineMathCB->isChecked();
481 rc.completion_inline_text = inlineTextCB->isChecked();
482 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
483 rc.completion_popup_delay = popupDelaySB->value();
484 rc.completion_popup_math = popupMathCB->isChecked();
485 rc.autocorrection_math = autocorrectionCB->isChecked();
486 rc.completion_popup_text = popupTextCB->isChecked();
487 rc.completion_cursor_text = cursorTextCB->isChecked();
488 rc.completion_popup_after_complete =
489 popupAfterCompleteCB->isChecked();
490 rc.completion_minlength = minlengthSB->value();
494 void PrefCompletion::updateRC(LyXRC const & rc)
496 inlineDelaySB->setValue(rc.completion_inline_delay);
497 inlineMathCB->setChecked(rc.completion_inline_math);
498 inlineTextCB->setChecked(rc.completion_inline_text);
499 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
500 popupDelaySB->setValue(rc.completion_popup_delay);
501 popupMathCB->setChecked(rc.completion_popup_math);
502 autocorrectionCB->setChecked(rc.autocorrection_math);
503 popupTextCB->setChecked(rc.completion_popup_text);
504 cursorTextCB->setChecked(rc.completion_cursor_text);
505 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
507 minlengthSB->setValue(rc.completion_minlength);
512 /////////////////////////////////////////////////////////////////////
516 /////////////////////////////////////////////////////////////////////
518 PrefLatex::PrefLatex(GuiPreferences * form)
519 : PrefModule(catOutput, N_("LaTeX"), form)
523 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
524 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
525 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
526 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
527 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
528 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
529 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
531 connect(latexChecktexED, SIGNAL(textChanged(QString)),
532 this, SIGNAL(changed()));
533 connect(latexBibtexCO, SIGNAL(activated(int)),
534 this, SIGNAL(changed()));
535 connect(latexBibtexED, SIGNAL(textChanged(QString)),
536 this, SIGNAL(changed()));
537 connect(latexJBibtexCO, SIGNAL(activated(int)),
538 this, SIGNAL(changed()));
539 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
540 this, SIGNAL(changed()));
541 connect(latexIndexCO, SIGNAL(activated(int)),
542 this, SIGNAL(changed()));
543 connect(latexIndexED, SIGNAL(textChanged(QString)),
544 this, SIGNAL(changed()));
545 connect(latexJIndexED, SIGNAL(textChanged(QString)),
546 this, SIGNAL(changed()));
547 connect(latexAutoresetCB, SIGNAL(clicked()),
548 this, SIGNAL(changed()));
549 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
550 this, SIGNAL(changed()));
551 connect(latexNomenclED, SIGNAL(textChanged(QString)),
552 this, SIGNAL(changed()));
554 #if defined(__CYGWIN__) || defined(_WIN32)
555 pathCB->setVisible(true);
556 connect(pathCB, SIGNAL(clicked()),
557 this, SIGNAL(changed()));
559 pathCB->setVisible(false);
564 void PrefLatex::on_latexBibtexCO_activated(int n)
566 QString const bibtex = latexBibtexCO->itemData(n).toString();
567 if (bibtex.isEmpty()) {
568 latexBibtexED->clear();
569 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
572 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
573 it != bibtex_alternatives.end(); ++it) {
574 QString const bib = toqstr(*it);
575 int ind = bib.indexOf(" ");
576 QString sel_command = bib.left(ind);
577 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
578 if (bibtex == sel_command) {
580 latexBibtexED->clear();
582 latexBibtexED->setText(sel_options.trimmed());
585 latexBibtexOptionsLA->setText(qt_("&Options:"));
589 void PrefLatex::on_latexJBibtexCO_activated(int n)
591 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
592 if (jbibtex.isEmpty()) {
593 latexJBibtexED->clear();
594 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
597 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
598 it != jbibtex_alternatives.end(); ++it) {
599 QString const bib = toqstr(*it);
600 int ind = bib.indexOf(" ");
601 QString sel_command = bib.left(ind);
602 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
603 if (jbibtex == sel_command) {
605 latexJBibtexED->clear();
607 latexJBibtexED->setText(sel_options.trimmed());
610 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
614 void PrefLatex::on_latexIndexCO_activated(int n)
616 QString const index = latexIndexCO->itemData(n).toString();
617 if (index.isEmpty()) {
618 latexIndexED->clear();
619 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
622 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
623 it != index_alternatives.end(); ++it) {
624 QString const idx = toqstr(*it);
625 int ind = idx.indexOf(" ");
626 QString sel_command = idx.left(ind);
627 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
628 if (index == sel_command) {
630 latexIndexED->clear();
632 latexIndexED->setText(sel_options.trimmed());
635 latexIndexOptionsLA->setText(qt_("Op&tions:"));
639 void PrefLatex::applyRC(LyXRC & rc) const
641 // If bibtex is not empty, bibopt contains the options, otherwise
642 // it is a customized bibtex command with options.
643 QString const bibtex = latexBibtexCO->itemData(
644 latexBibtexCO->currentIndex()).toString();
645 QString const bibopt = latexBibtexED->text();
646 if (bibtex.isEmpty())
647 rc.bibtex_command = fromqstr(bibopt);
648 else if (bibopt.isEmpty())
649 rc.bibtex_command = fromqstr(bibtex);
651 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
653 // If jbibtex is not empty, jbibopt contains the options, otherwise
654 // it is a customized bibtex command with options.
655 QString const jbibtex = latexJBibtexCO->itemData(
656 latexJBibtexCO->currentIndex()).toString();
657 QString const jbibopt = latexJBibtexED->text();
658 if (jbibtex.isEmpty())
659 rc.jbibtex_command = fromqstr(jbibopt);
660 else if (jbibopt.isEmpty())
661 rc.jbibtex_command = fromqstr(jbibtex);
663 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
665 // If index is not empty, idxopt contains the options, otherwise
666 // it is a customized index command with options.
667 QString const index = latexIndexCO->itemData(
668 latexIndexCO->currentIndex()).toString();
669 QString const idxopt = latexIndexED->text();
671 rc.index_command = fromqstr(idxopt);
672 else if (idxopt.isEmpty())
673 rc.index_command = fromqstr(index);
675 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
677 rc.chktex_command = fromqstr(latexChecktexED->text());
678 rc.jindex_command = fromqstr(latexJIndexED->text());
679 rc.nomencl_command = fromqstr(latexNomenclED->text());
680 rc.auto_reset_options = latexAutoresetCB->isChecked();
681 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
682 #if defined(__CYGWIN__) || defined(_WIN32)
683 rc.windows_style_tex_paths = pathCB->isChecked();
688 void PrefLatex::updateRC(LyXRC const & rc)
690 latexBibtexCO->clear();
692 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
693 latexBibtexCO->addItem(qt_("Custom"), QString());
694 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
695 it != rc.bibtex_alternatives.end(); ++it) {
696 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
697 latexBibtexCO->addItem(command, command);
700 bibtex_alternatives = rc.bibtex_alternatives;
702 QString const bib = toqstr(rc.bibtex_command);
703 int ind = bib.indexOf(" ");
704 QString sel_command = bib.left(ind);
705 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
707 int pos = latexBibtexCO->findData(sel_command);
709 latexBibtexCO->setCurrentIndex(pos);
710 latexBibtexED->setText(sel_options.trimmed());
711 latexBibtexOptionsLA->setText(qt_("&Options:"));
713 latexBibtexED->setText(toqstr(rc.bibtex_command));
714 latexBibtexCO->setCurrentIndex(0);
715 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
718 latexJBibtexCO->clear();
720 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
721 latexJBibtexCO->addItem(qt_("Custom"), QString());
722 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
723 it != rc.jbibtex_alternatives.end(); ++it) {
724 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
725 latexJBibtexCO->addItem(command, command);
728 jbibtex_alternatives = rc.jbibtex_alternatives;
730 QString const jbib = toqstr(rc.jbibtex_command);
731 ind = jbib.indexOf(" ");
732 sel_command = jbib.left(ind);
733 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
735 pos = latexJBibtexCO->findData(sel_command);
737 latexJBibtexCO->setCurrentIndex(pos);
738 latexJBibtexED->setText(sel_options.trimmed());
739 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
741 latexJBibtexED->setText(toqstr(rc.bibtex_command));
742 latexJBibtexCO->setCurrentIndex(0);
743 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
746 latexIndexCO->clear();
748 latexIndexCO->addItem(qt_("Custom"), QString());
749 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
750 it != rc.index_alternatives.end(); ++it) {
751 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
752 latexIndexCO->addItem(command, command);
755 index_alternatives = rc.index_alternatives;
757 QString const idx = toqstr(rc.index_command);
758 ind = idx.indexOf(" ");
759 sel_command = idx.left(ind);
760 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
762 pos = latexIndexCO->findData(sel_command);
764 latexIndexCO->setCurrentIndex(pos);
765 latexIndexED->setText(sel_options.trimmed());
766 latexIndexOptionsLA->setText(qt_("Op&tions:"));
768 latexIndexED->setText(toqstr(rc.index_command));
769 latexIndexCO->setCurrentIndex(0);
770 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
773 latexChecktexED->setText(toqstr(rc.chktex_command));
774 latexJIndexED->setText(toqstr(rc.jindex_command));
775 latexNomenclED->setText(toqstr(rc.nomencl_command));
776 latexAutoresetCB->setChecked(rc.auto_reset_options);
777 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
778 #if defined(__CYGWIN__) || defined(_WIN32)
779 pathCB->setChecked(rc.windows_style_tex_paths);
784 /////////////////////////////////////////////////////////////////////
788 /////////////////////////////////////////////////////////////////////
790 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
791 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
795 #if QT_VERSION < 0x050e00
796 connect(screenRomanCO, SIGNAL(activated(QString)),
797 this, SLOT(selectRoman(QString)));
798 connect(screenSansCO, SIGNAL(activated(QString)),
799 this, SLOT(selectSans(QString)));
800 connect(screenTypewriterCO, SIGNAL(activated(QString)),
801 this, SLOT(selectTypewriter(QString)));
803 connect(screenRomanCO, SIGNAL(textActivated(QString)),
804 this, SLOT(selectRoman(QString)));
805 connect(screenSansCO, SIGNAL(textActivated(QString)),
806 this, SLOT(selectSans(QString)));
807 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
808 this, SLOT(selectTypewriter(QString)));
811 #if QT_VERSION >= 0x060000
812 const QStringList families(QFontDatabase::families());
814 QFontDatabase fontdb;
815 const QStringList families(fontdb.families());
817 for (auto const & family : families) {
818 screenRomanCO->addItem(family);
819 screenSansCO->addItem(family);
820 screenTypewriterCO->addItem(family);
822 #if QT_VERSION < 0x050e00
823 connect(screenRomanCO, SIGNAL(activated(QString)),
824 this, SIGNAL(changed()));
825 connect(screenSansCO, SIGNAL(activated(QString)),
826 this, SIGNAL(changed()));
827 connect(screenTypewriterCO, SIGNAL(activated(QString)),
828 this, SIGNAL(changed()));
830 connect(screenRomanCO, SIGNAL(textActivated(QString)),
831 this, SIGNAL(changed()));
832 connect(screenSansCO, SIGNAL(textActivated(QString)),
833 this, SIGNAL(changed()));
834 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
835 this, SIGNAL(changed()));
837 connect(screenZoomSB, SIGNAL(valueChanged(int)),
838 this, SIGNAL(changed()));
839 connect(screenTinyED, SIGNAL(textChanged(QString)),
840 this, SIGNAL(changed()));
841 connect(screenSmallestED, SIGNAL(textChanged(QString)),
842 this, SIGNAL(changed()));
843 connect(screenSmallerED, SIGNAL(textChanged(QString)),
844 this, SIGNAL(changed()));
845 connect(screenSmallED, SIGNAL(textChanged(QString)),
846 this, SIGNAL(changed()));
847 connect(screenNormalED, SIGNAL(textChanged(QString)),
848 this, SIGNAL(changed()));
849 connect(screenLargeED, SIGNAL(textChanged(QString)),
850 this, SIGNAL(changed()));
851 connect(screenLargerED, SIGNAL(textChanged(QString)),
852 this, SIGNAL(changed()));
853 connect(screenLargestED, SIGNAL(textChanged(QString)),
854 this, SIGNAL(changed()));
855 connect(screenHugeED, SIGNAL(textChanged(QString)),
856 this, SIGNAL(changed()));
857 connect(screenHugerED, SIGNAL(textChanged(QString)),
858 this, SIGNAL(changed()));
860 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
861 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
862 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
863 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
864 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
865 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
866 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
867 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
868 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
869 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
873 void PrefScreenFonts::applyRC(LyXRC & rc) const
875 LyXRC const oldrc = rc;
877 parseFontName(screenRomanCO->currentText(),
878 rc.roman_font_name, rc.roman_font_foundry);
879 parseFontName(screenSansCO->currentText(),
880 rc.sans_font_name, rc.sans_font_foundry);
881 parseFontName(screenTypewriterCO->currentText(),
882 rc.typewriter_font_name, rc.typewriter_font_foundry);
884 rc.defaultZoom = screenZoomSB->value();
885 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
886 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
887 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
888 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
889 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
890 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
891 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
892 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
893 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
894 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
898 void PrefScreenFonts::updateRC(LyXRC const & rc)
900 setComboxFont(screenRomanCO, rc.roman_font_name,
901 rc.roman_font_foundry);
902 setComboxFont(screenSansCO, rc.sans_font_name,
903 rc.sans_font_foundry);
904 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
905 rc.typewriter_font_foundry);
907 selectRoman(screenRomanCO->currentText());
908 selectSans(screenSansCO->currentText());
909 selectTypewriter(screenTypewriterCO->currentText());
911 screenZoomSB->setValue(rc.defaultZoom);
912 updateScreenFontSizes(rc);
916 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
918 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
919 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
920 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
921 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
922 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
923 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
924 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
925 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
926 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
927 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
931 void PrefScreenFonts::selectRoman(const QString & name)
933 screenRomanFE->set(QFont(name), name);
934 screenFontsChanged();
938 void PrefScreenFonts::selectSans(const QString & name)
940 screenSansFE->set(QFont(name), name);
941 screenFontsChanged();
945 void PrefScreenFonts::selectTypewriter(const QString & name)
947 screenTypewriterFE->set(QFont(name), name);
948 screenFontsChanged();
952 void PrefScreenFonts::screenFontsChanged()
954 int w = max(screenRomanFE->minWidth(), screenSansFE->minWidth());
955 w = max(screenTypewriterFE->minWidth(), w);
956 screenRomanFE->setFixedWidth(w);
957 screenSansFE->setFixedWidth(w);
958 screenTypewriterFE->setFixedWidth(w);
962 /////////////////////////////////////////////////////////////////////
966 /////////////////////////////////////////////////////////////////////
969 PrefColors::PrefColors(GuiPreferences * form)
970 : PrefModule(catLookAndFeel, N_("Colors"), form)
974 // FIXME: all of this initialization should be put into the controller.
975 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
976 // for some discussion of why that is not trivial.
977 QPixmap icon(32, 32);
978 for (int i = 0; i < Color_ignore; ++i) {
979 ColorCode lc = static_cast<ColorCode>(i);
986 || lc == Color_darkgray
989 || lc == Color_lightgray
991 || lc == Color_magenta
993 || lc == Color_orange
995 || lc == Color_purple
998 || lc == Color_violet
999 || lc == Color_yellow
1000 || lc == Color_inherit
1001 || lc == Color_ignore)
1003 lcolors_.push_back(lc);
1005 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1006 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1007 vector<ColorCode>::const_iterator const end = lcolors_.end();
1008 for (; cit != end; ++cit) {
1009 (void) new QListWidgetItem(QIcon(icon),
1010 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1012 curcolors_.resize(lcolors_.size());
1013 newcolors_.resize(lcolors_.size());
1014 // End initialization
1016 connect(colorChangePB, SIGNAL(clicked()),
1017 this, SLOT(changeColor()));
1018 connect(colorResetPB, SIGNAL(clicked()),
1019 this, SLOT(resetColor()));
1020 connect(colorResetAllPB, SIGNAL(clicked()),
1021 this, SLOT(resetAllColor()));
1022 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1023 this, SLOT(changeLyxObjectsSelection()));
1024 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1025 this, SLOT(changeColor()));
1026 connect(syscolorsCB, SIGNAL(toggled(bool)),
1027 this, SIGNAL(changed()));
1028 connect(syscolorsCB, SIGNAL(toggled(bool)),
1029 this, SLOT(changeSysColor()));
1033 void PrefColors::applyRC(LyXRC & rc) const
1037 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1038 if (curcolors_[i] != newcolors_[i])
1039 form_->setColor(lcolors_[i], newcolors_[i]);
1040 rc.use_system_colors = syscolorsCB->isChecked();
1042 if (oldrc.use_system_colors != rc.use_system_colors)
1043 guiApp->colorCache().clear();
1047 void PrefColors::updateRC(LyXRC const & rc)
1049 for (size_type i = 0; i < lcolors_.size(); ++i) {
1050 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1051 QPixmap coloritem(32, 32);
1052 coloritem.fill(color);
1053 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1054 newcolors_[i] = curcolors_[i] = color.name();
1056 syscolorsCB->setChecked(rc.use_system_colors);
1057 changeLyxObjectsSelection();
1059 setDisabledResets();
1063 void PrefColors::changeColor()
1065 int const row = lyxObjectsLW->currentRow();
1071 QString const color = newcolors_[size_t(row)];
1072 QColor const c = form_->getColor(QColor(color));
1074 if (setColor(row, c, color)) {
1075 setDisabledResets();
1082 void PrefColors::resetColor()
1084 int const row = lyxObjectsLW->currentRow();
1090 QString const color = newcolors_[size_t(row)];
1091 QColor const c = getDefaultColorByRow(row);
1093 if (setColor(row, c, color)) {
1094 setDisabledResets();
1101 void PrefColors::resetAllColor()
1103 bool isChanged = false;
1105 colorResetAllPB->setDisabled(true);
1107 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1108 QString const color = newcolors_[size_t(irow)];
1109 QColor const c = getDefaultColorByRow(irow);
1111 if (setColor(irow, c, color))
1116 setDisabledResets();
1123 bool PrefColors::setColor(int const row, QColor const & new_color,
1124 QString const & old_color)
1126 if (new_color.isValid() && new_color.name() != old_color) {
1127 newcolors_[size_t(row)] = new_color.name();
1128 QPixmap coloritem(32, 32);
1129 coloritem.fill(new_color);
1130 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1137 void PrefColors::setDisabledResets()
1139 int const row = lyxObjectsLW->currentRow();
1140 // set disable reset buttons ...
1142 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1144 colorResetAllPB->setDisabled(true);
1146 // ... in between process qt events to give quicker visual feedback to the user ...
1147 guiApp->processEvents();
1149 // ... set disable Reset All button
1150 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1151 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1152 colorResetAllPB->setDisabled(false);
1153 // the break condition might hide performance issues
1154 // if a non-default color is at the top of the list
1161 bool PrefColors::isDefaultColor(int const row, QString const & color)
1163 return color == getDefaultColorByRow(row).name();
1167 QColor PrefColors::getDefaultColorByRow(int const row)
1169 ColorSet const defaultcolor;
1170 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1171 guiApp->colorCache().isDarkMode()).c_str();
1175 void PrefColors::changeSysColor()
1177 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1178 // skip colors that are taken from system palette
1179 bool const disable = syscolorsCB->isChecked()
1180 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1182 QListWidgetItem * const item = lyxObjectsLW->item(row);
1183 Qt::ItemFlags const flags = item->flags();
1186 item->setFlags(flags & ~Qt::ItemIsEnabled);
1188 item->setFlags(flags | Qt::ItemIsEnabled);
1193 void PrefColors::changeLyxObjectsSelection()
1195 int currentRow = lyxObjectsLW->currentRow();
1196 colorChangePB->setDisabled(currentRow < 0);
1199 colorResetPB->setDisabled(true);
1201 colorResetPB->setDisabled(
1202 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1206 /////////////////////////////////////////////////////////////////////
1210 /////////////////////////////////////////////////////////////////////
1212 PrefDisplay::PrefDisplay(GuiPreferences * form)
1213 : PrefModule(catLookAndFeel, N_("Display"), form)
1216 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1217 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1218 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1219 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1220 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1224 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1226 previewSizeSB->setEnabled(index != 0);
1230 void PrefDisplay::applyRC(LyXRC & rc) const
1232 switch (instantPreviewCO->currentIndex()) {
1234 rc.preview = LyXRC::PREVIEW_OFF;
1237 rc.preview = LyXRC::PREVIEW_NO_MATH;
1240 rc.preview = LyXRC::PREVIEW_ON;
1244 rc.display_graphics = displayGraphicsCB->isChecked();
1245 rc.preview_scale_factor = previewSizeSB->value();
1246 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1247 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1249 // FIXME!! The graphics cache no longer has a changeDisplay method.
1251 if (old_value != rc.display_graphics) {
1252 graphics::GCache & gc = graphics::GCache::get();
1259 void PrefDisplay::updateRC(LyXRC const & rc)
1261 switch (rc.preview) {
1262 case LyXRC::PREVIEW_OFF:
1263 instantPreviewCO->setCurrentIndex(0);
1265 case LyXRC::PREVIEW_NO_MATH :
1266 instantPreviewCO->setCurrentIndex(1);
1268 case LyXRC::PREVIEW_ON :
1269 instantPreviewCO->setCurrentIndex(2);
1273 displayGraphicsCB->setChecked(rc.display_graphics);
1274 previewSizeSB->setValue(rc.preview_scale_factor);
1275 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1276 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1277 previewSizeSB->setEnabled(
1279 && rc.preview != LyXRC::PREVIEW_OFF);
1283 /////////////////////////////////////////////////////////////////////
1287 /////////////////////////////////////////////////////////////////////
1289 PrefPaths::PrefPaths(GuiPreferences * form)
1290 : PrefModule(QString(), N_("Paths"), form)
1294 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1295 connect(workingDirED, SIGNAL(textChanged(QString)),
1296 this, SIGNAL(changed()));
1298 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1299 connect(templateDirED, SIGNAL(textChanged(QString)),
1300 this, SIGNAL(changed()));
1302 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1303 connect(exampleDirED, SIGNAL(textChanged(QString)),
1304 this, SIGNAL(changed()));
1306 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1307 connect(backupDirED, SIGNAL(textChanged(QString)),
1308 this, SIGNAL(changed()));
1310 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1311 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1312 this, SIGNAL(changed()));
1314 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1315 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1316 this, SIGNAL(changed()));
1318 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1319 connect(tempDirED, SIGNAL(textChanged(QString)),
1320 this, SIGNAL(changed()));
1322 #if defined(USE_HUNSPELL)
1323 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1324 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1325 this, SIGNAL(changed()));
1327 hunspellDirPB->setEnabled(false);
1328 hunspellDirED->setEnabled(false);
1331 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1332 this, SIGNAL(changed()));
1334 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1335 this, SIGNAL(changed()));
1337 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1338 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1342 void PrefPaths::applyRC(LyXRC & rc) const
1344 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1345 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1346 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1347 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1348 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1349 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1350 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1351 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1352 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1353 // FIXME: should be a checkbox only
1354 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1358 void PrefPaths::updateRC(LyXRC const & rc)
1360 workingDirED->setText(toqstr(external_path(rc.document_path)));
1361 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1362 templateDirED->setText(toqstr(external_path(rc.template_path)));
1363 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1364 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1365 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1366 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1367 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1368 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1369 // FIXME: should be a checkbox only
1370 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1374 void PrefPaths::selectExampledir()
1376 QString file = form_->browseDir(internalPath(exampleDirED->text()),
1377 qt_("Select directory for example files"));
1378 if (!file.isEmpty())
1379 exampleDirED->setText(file);
1383 void PrefPaths::selectTemplatedir()
1385 QString file = form_->browseDir(internalPath(templateDirED->text()),
1386 qt_("Select a document templates directory"));
1387 if (!file.isEmpty())
1388 templateDirED->setText(file);
1392 void PrefPaths::selectTempdir()
1394 QString file = form_->browseDir(internalPath(tempDirED->text()),
1395 qt_("Select a temporary directory"));
1396 if (!file.isEmpty())
1397 tempDirED->setText(file);
1401 void PrefPaths::selectBackupdir()
1403 QString file = form_->browseDir(internalPath(backupDirED->text()),
1404 qt_("Select a backups directory"));
1405 if (!file.isEmpty())
1406 backupDirED->setText(file);
1410 void PrefPaths::selectWorkingdir()
1412 QString file = form_->browseDir(internalPath(workingDirED->text()),
1413 qt_("Select a document directory"));
1414 if (!file.isEmpty())
1415 workingDirED->setText(file);
1419 void PrefPaths::selectThesaurusdir()
1421 QString file = form_->browseDir(internalPath(thesaurusDirED->text()),
1422 qt_("Set the path to the thesaurus dictionaries"));
1423 if (!file.isEmpty())
1424 thesaurusDirED->setText(file);
1428 void PrefPaths::selectHunspelldir()
1430 QString file = form_->browseDir(internalPath(hunspellDirED->text()),
1431 qt_("Set the path to the Hunspell dictionaries"));
1432 if (!file.isEmpty())
1433 hunspellDirED->setText(file);
1437 void PrefPaths::selectLyxPipe()
1439 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1440 qt_("Give a filename for the LyX server pipe"));
1441 if (!file.isEmpty())
1442 lyxserverDirED->setText(file);
1446 /////////////////////////////////////////////////////////////////////
1450 /////////////////////////////////////////////////////////////////////
1452 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1453 : PrefModule(catLanguage, N_("Spellchecker"), form)
1457 // FIXME: this check should test the target platform (darwin)
1458 #if defined(USE_MACOSX_PACKAGING)
1459 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1460 #define CONNECT_APPLESPELL
1462 #undef CONNECT_APPLESPELL
1464 #if defined(USE_ASPELL)
1465 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1467 #if defined(USE_ENCHANT)
1468 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1470 #if defined(USE_HUNSPELL)
1471 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1474 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1475 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1476 this, SIGNAL(changed()));
1477 connect(altLanguageED, SIGNAL(textChanged(QString)),
1478 this, SIGNAL(changed()));
1479 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1480 this, SIGNAL(changed()));
1481 connect(compoundWordCB, SIGNAL(clicked()),
1482 this, SIGNAL(changed()));
1483 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1484 this, SIGNAL(changed()));
1485 connect(spellcheckNotesCB, SIGNAL(clicked()),
1486 this, SIGNAL(changed()));
1488 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1489 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1491 spellcheckerCB->setEnabled(false);
1492 altLanguageED->setEnabled(false);
1493 escapeCharactersED->setEnabled(false);
1494 compoundWordCB->setEnabled(false);
1495 spellcheckContinuouslyCB->setEnabled(false);
1496 spellcheckNotesCB->setEnabled(false);
1501 void PrefSpellchecker::applyRC(LyXRC & rc) const
1503 string const speller = fromqstr(spellcheckerCB->
1504 itemData(spellcheckerCB->currentIndex()).toString());
1505 if (!speller.empty())
1506 rc.spellchecker = speller;
1507 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1508 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1509 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1510 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1511 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1515 void PrefSpellchecker::updateRC(LyXRC const & rc)
1517 spellcheckerCB->setCurrentIndex(
1518 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1519 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1520 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1521 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1522 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1523 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1527 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1529 QString spellchecker = spellcheckerCB->itemData(index).toString();
1531 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1536 /////////////////////////////////////////////////////////////////////
1540 /////////////////////////////////////////////////////////////////////
1543 PrefConverters::PrefConverters(GuiPreferences * form)
1544 : PrefModule(catFiles, N_("Converters"), form)
1548 connect(converterNewPB, SIGNAL(clicked()),
1549 this, SLOT(updateConverter()));
1550 connect(converterRemovePB, SIGNAL(clicked()),
1551 this, SLOT(removeConverter()));
1552 connect(converterModifyPB, SIGNAL(clicked()),
1553 this, SLOT(updateConverter()));
1554 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1555 this, SLOT(switchConverter()));
1556 #if QT_VERSION < 0x050e00
1557 connect(converterFromCO, SIGNAL(activated(QString)),
1558 this, SLOT(changeConverter()));
1559 connect(converterToCO, SIGNAL(activated(QString)),
1560 this, SLOT(changeConverter()));
1562 connect(converterFromCO, SIGNAL(textActivated(QString)),
1563 this, SLOT(changeConverter()));
1564 connect(converterToCO, SIGNAL(textActivated(QString)),
1565 this, SLOT(changeConverter()));
1567 connect(converterED, SIGNAL(textEdited(QString)),
1568 this, SLOT(changeConverter()));
1569 connect(converterFlagED, SIGNAL(textEdited(QString)),
1570 this, SLOT(changeConverter()));
1571 connect(converterNewPB, SIGNAL(clicked()),
1572 this, SIGNAL(changed()));
1573 connect(converterRemovePB, SIGNAL(clicked()),
1574 this, SIGNAL(changed()));
1575 connect(converterModifyPB, SIGNAL(clicked()),
1576 this, SIGNAL(changed()));
1577 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1578 this, SIGNAL(changed()));
1579 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1580 this, SIGNAL(changed()));
1582 converterED->setValidator(new NoNewLineValidator(converterED));
1583 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1584 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1585 //converterDefGB->setFocusProxy(convertersLW);
1589 void PrefConverters::applyRC(LyXRC & rc) const
1591 rc.use_converter_cache = cacheCB->isChecked();
1592 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1593 rc.use_converter_needauth = needauthCB->isChecked();
1594 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1598 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1599 cb->blockSignals(true);
1600 cb->setChecked(checked);
1601 cb->blockSignals(false);
1605 void PrefConverters::updateRC(LyXRC const & rc)
1607 cacheCB->setChecked(rc.use_converter_cache);
1608 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1609 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1611 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1616 void PrefConverters::updateGui()
1618 QString const pattern("%1 -> %2");
1619 form_->formats().sort();
1620 form_->converters().update(form_->formats());
1621 // save current selection
1624 .arg(converterFromCO->currentText())
1625 .arg(converterToCO->currentText());
1627 converterFromCO->clear();
1628 converterToCO->clear();
1630 for (Format const & f : form_->formats()) {
1631 QString const name = toqstr(translateIfPossible(f.prettyname()));
1632 converterFromCO->addItem(name);
1633 converterToCO->addItem(name);
1636 // currentRowChanged(int) is also triggered when updating the listwidget
1637 // block signals to avoid unnecessary calls to switchConverter()
1638 convertersLW->blockSignals(true);
1639 convertersLW->clear();
1641 for (Converter const & c : form_->converters()) {
1642 QString const name =
1644 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1645 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1646 int type = form_->converters().getNumber(c.From()->name(),
1648 new QListWidgetItem(name, convertersLW, type);
1650 convertersLW->sortItems(Qt::AscendingOrder);
1651 convertersLW->blockSignals(false);
1653 // restore selection
1654 if (current != pattern.arg(QString()).arg(QString())) {
1655 QList<QListWidgetItem *> const item =
1656 convertersLW->findItems(current, Qt::MatchExactly);
1657 if (!item.isEmpty())
1658 convertersLW->setCurrentItem(item.at(0));
1661 // select first element if restoring failed
1662 if (convertersLW->currentRow() == -1)
1663 convertersLW->setCurrentRow(0);
1669 void PrefConverters::switchConverter()
1671 int const cnr = convertersLW->currentItem()->type();
1672 Converter const & c(form_->converters().get(cnr));
1673 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1674 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1675 converterED->setText(toqstr(c.command()));
1676 converterFlagED->setText(toqstr(c.flags()));
1682 void PrefConverters::changeConverter()
1688 void PrefConverters::updateButtons()
1690 if (form_->formats().empty())
1692 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1693 Format const & to = form_->formats().get(converterToCO->currentIndex());
1694 int const sel = form_->converters().getNumber(from.name(), to.name());
1695 bool const known = sel >= 0;
1696 bool const valid = !(converterED->text().isEmpty()
1697 || from.name() == to.name());
1702 if (convertersLW->count() > 0) {
1703 int const cnr = convertersLW->currentItem()->type();
1704 Converter const & c = form_->converters().get(cnr);
1705 old_command = c.command();
1706 old_flag = c.flags();
1709 string const new_command = fromqstr(converterED->text());
1710 string const new_flag = fromqstr(converterFlagED->text());
1712 bool modified = (old_command != new_command || old_flag != new_flag);
1714 converterModifyPB->setEnabled(valid && known && modified);
1715 converterNewPB->setEnabled(valid && !known);
1716 converterRemovePB->setEnabled(known);
1718 maxAgeLE->setEnabled(cacheCB->isChecked());
1719 maxAgeLA->setEnabled(cacheCB->isChecked());
1724 // specify unique from/to or it doesn't appear. This is really bad UI
1725 // this is why we can use the same function for both new and modify
1726 void PrefConverters::updateConverter()
1728 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1729 Format const & to = form_->formats().get(converterToCO->currentIndex());
1730 string const flags = fromqstr(converterFlagED->text());
1731 string const command = fromqstr(converterED->text());
1733 Converter const * old =
1734 form_->converters().getConverter(from.name(), to.name());
1735 form_->converters().add(from.name(), to.name(), command, flags);
1738 form_->converters().updateLast(form_->formats());
1742 // Remove all files created by this converter from the cache, since
1743 // the modified converter might create different files.
1744 ConverterCache::get().remove_all(from.name(), to.name());
1748 void PrefConverters::removeConverter()
1750 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1751 Format const & to = form_->formats().get(converterToCO->currentIndex());
1752 form_->converters().erase(from.name(), to.name());
1756 // Remove all files created by this converter from the cache, since
1757 // a possible new converter might create different files.
1758 ConverterCache::get().remove_all(from.name(), to.name());
1762 void PrefConverters::on_cacheCB_stateChanged(int state)
1764 maxAgeLE->setEnabled(state == Qt::Checked);
1765 maxAgeLA->setEnabled(state == Qt::Checked);
1770 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1772 needauthCB->setEnabled(!checked);
1776 void PrefConverters::on_needauthCB_toggled(bool checked)
1783 int ret = frontend::Alert::prompt(
1784 _("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!"),
1785 0, 0, _("&No"), _("&Yes"));
1789 setCheckboxBlockSignals(needauthCB, true);
1793 /////////////////////////////////////////////////////////////////////
1797 /////////////////////////////////////////////////////////////////////
1799 class FormatValidator : public QValidator
1802 FormatValidator(QWidget *, Formats const & f);
1803 void fixup(QString & input) const override;
1804 QValidator::State validate(QString & input, int & pos) const override;
1806 virtual QString toString(Format const & format) const = 0;
1808 Formats const & formats_;
1812 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1813 : QValidator(parent), formats_(f)
1818 void FormatValidator::fixup(QString & input) const
1820 Formats::const_iterator cit = formats_.begin();
1821 Formats::const_iterator end = formats_.end();
1822 for (; cit != end; ++cit) {
1823 QString const name = toString(*cit);
1824 if (distance(formats_.begin(), cit) == nr()) {
1832 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1834 Formats::const_iterator cit = formats_.begin();
1835 Formats::const_iterator end = formats_.end();
1836 bool unknown = true;
1837 for (; unknown && cit != end; ++cit) {
1838 QString const name = toString(*cit);
1839 if (distance(formats_.begin(), cit) != nr())
1840 unknown = name != input;
1843 if (unknown && !input.isEmpty())
1844 return QValidator::Acceptable;
1846 return QValidator::Intermediate;
1850 int FormatValidator::nr() const
1852 QComboBox * p = qobject_cast<QComboBox *>(parent());
1853 return p->itemData(p->currentIndex()).toInt();
1857 /////////////////////////////////////////////////////////////////////
1859 // FormatNameValidator
1861 /////////////////////////////////////////////////////////////////////
1863 class FormatNameValidator : public FormatValidator
1866 FormatNameValidator(QWidget * parent, Formats const & f)
1867 : FormatValidator(parent, f)
1870 QString toString(Format const & format) const override
1872 return toqstr(format.name());
1877 /////////////////////////////////////////////////////////////////////
1879 // FormatPrettynameValidator
1881 /////////////////////////////////////////////////////////////////////
1883 class FormatPrettynameValidator : public FormatValidator
1886 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1887 : FormatValidator(parent, f)
1890 QString toString(Format const & format) const override
1892 return toqstr(translateIfPossible(format.prettyname()));
1897 /////////////////////////////////////////////////////////////////////
1901 /////////////////////////////////////////////////////////////////////
1903 PrefFileformats::PrefFileformats(GuiPreferences * form)
1904 : PrefModule(catFiles, N_("File Formats"), form)
1908 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
1909 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
1910 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
1911 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
1912 editorED->setValidator(new NoNewLineValidator(editorED));
1913 viewerED->setValidator(new NoNewLineValidator(viewerED));
1914 copierED->setValidator(new NoNewLineValidator(copierED));
1916 connect(documentCB, SIGNAL(clicked()),
1917 this, SLOT(setFlags()));
1918 connect(vectorCB, SIGNAL(clicked()),
1919 this, SLOT(setFlags()));
1920 connect(exportMenuCB, SIGNAL(clicked()),
1921 this, SLOT(setFlags()));
1922 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
1923 this, SLOT(updatePrettyname()));
1924 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
1925 this, SIGNAL(changed()));
1926 #if QT_VERSION < 0x050e00
1927 connect(defaultFormatCB, SIGNAL(activated(QString)),
1928 this, SIGNAL(changed()));
1929 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
1930 this, SIGNAL(changed()));
1931 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
1932 this, SIGNAL(changed()));
1934 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
1935 this, SIGNAL(changed()));
1936 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
1937 this, SIGNAL(changed()));
1938 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
1939 this, SIGNAL(changed()));
1941 connect(viewerCO, SIGNAL(activated(int)),
1942 this, SIGNAL(changed()));
1943 connect(editorCO, SIGNAL(activated(int)),
1944 this, SIGNAL(changed()));
1950 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
1952 if (shortcut.empty())
1955 string l10n_format =
1956 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
1957 return split(l10n_format, '|');
1963 void PrefFileformats::applyRC(LyXRC & rc) const
1965 QString const default_format = defaultFormatCB->itemData(
1966 defaultFormatCB->currentIndex()).toString();
1967 rc.default_view_format = fromqstr(default_format);
1968 QString const default_otf_format = defaultOTFFormatCB->itemData(
1969 defaultOTFFormatCB->currentIndex()).toString();
1970 rc.default_otf_view_format = fromqstr(default_otf_format);
1971 QString const default_platex_format = defaultPlatexFormatCB->itemData(
1972 defaultPlatexFormatCB->currentIndex()).toString();
1973 rc.default_platex_view_format = fromqstr(default_platex_format);
1977 void PrefFileformats::updateRC(LyXRC const & rc)
1979 viewer_alternatives = rc.viewer_alternatives;
1980 editor_alternatives = rc.editor_alternatives;
1981 bool const init = defaultFormatCB->currentText().isEmpty();
1985 defaultFormatCB->findData(toqstr(rc.default_view_format));
1986 defaultFormatCB->setCurrentIndex(pos);
1987 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
1988 defaultOTFFormatCB->setCurrentIndex(pos);
1989 defaultOTFFormatCB->setCurrentIndex(pos);
1990 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
1991 defaultPlatexFormatCB->setCurrentIndex(pos);
1992 defaultPlatexFormatCB->setCurrentIndex(pos);
1997 void PrefFileformats::updateView()
1999 QString const current = formatsCB->currentText();
2000 QString const current_def = defaultFormatCB->currentText();
2001 QString const current_def_otf = defaultOTFFormatCB->currentText();
2002 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2004 // update comboboxes with formats
2005 formatsCB->blockSignals(true);
2006 defaultFormatCB->blockSignals(true);
2007 defaultOTFFormatCB->blockSignals(true);
2008 defaultPlatexFormatCB->blockSignals(true);
2010 defaultFormatCB->clear();
2011 defaultOTFFormatCB->clear();
2012 defaultPlatexFormatCB->clear();
2013 form_->formats().sort();
2014 for (Format const & f : form_->formats()) {
2015 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2016 formatsCB->addItem(prettyname,
2017 QVariant(form_->formats().getNumber(f.name())));
2018 if (f.viewer().empty())
2020 if (form_->converters().isReachable("xhtml", f.name())
2021 || form_->converters().isReachable("dviluatex", f.name())
2022 || form_->converters().isReachable("luatex", f.name())
2023 || form_->converters().isReachable("xetex", f.name())) {
2024 defaultFormatCB->addItem(prettyname,
2025 QVariant(toqstr(f.name())));
2026 defaultOTFFormatCB->addItem(prettyname,
2027 QVariant(toqstr(f.name())));
2029 if (form_->converters().isReachable("latex", f.name())
2030 || form_->converters().isReachable("pdflatex", f.name()))
2031 defaultFormatCB->addItem(prettyname,
2032 QVariant(toqstr(f.name())));
2033 if (form_->converters().isReachable("platex", f.name()))
2034 defaultPlatexFormatCB->addItem(prettyname,
2035 QVariant(toqstr(f.name())));
2039 // restore selections
2040 int item = formatsCB->findText(current, Qt::MatchExactly);
2041 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2042 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2043 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2044 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2045 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2046 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2047 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2048 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2049 formatsCB->blockSignals(false);
2050 defaultFormatCB->blockSignals(false);
2051 defaultOTFFormatCB->blockSignals(false);
2052 defaultPlatexFormatCB->blockSignals(false);
2056 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2058 if (form_->formats().empty())
2060 int const nr = formatsCB->itemData(i).toInt();
2061 Format const f = form_->formats().get(nr);
2063 formatED->setText(toqstr(f.name()));
2064 copierED->setText(toqstr(form_->movers().command(f.name())));
2065 extensionsED->setText(toqstr(f.extensions()));
2066 mimeED->setText(toqstr(f.mime()));
2067 shortcutED->setText(
2068 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2069 documentCB->setChecked((f.documentFormat()));
2070 vectorCB->setChecked((f.vectorFormat()));
2071 exportMenuCB->setChecked((f.inExportMenu()));
2072 exportMenuCB->setEnabled((f.documentFormat()));
2078 void PrefFileformats::setFlags()
2080 int flags = Format::none;
2081 if (documentCB->isChecked())
2082 flags |= Format::document;
2083 if (vectorCB->isChecked())
2084 flags |= Format::vector;
2085 if (exportMenuCB->isChecked())
2086 flags |= Format::export_menu;
2087 currentFormat().setFlags(flags);
2088 exportMenuCB->setEnabled(documentCB->isChecked());
2093 void PrefFileformats::on_copierED_textEdited(const QString & s)
2095 string const fmt = fromqstr(formatED->text());
2096 form_->movers().set(fmt, fromqstr(s));
2101 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2103 currentFormat().setExtensions(fromqstr(s));
2108 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2110 currentFormat().setViewer(fromqstr(s));
2115 void PrefFileformats::on_editorED_textEdited(const QString & s)
2117 currentFormat().setEditor(fromqstr(s));
2122 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2124 currentFormat().setMime(fromqstr(s));
2129 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2131 string const new_shortcut = fromqstr(s);
2132 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2133 currentFormat().shortcut()))
2135 currentFormat().setShortcut(new_shortcut);
2140 void PrefFileformats::on_formatED_editingFinished()
2142 string const newname = fromqstr(formatED->displayText());
2143 string const oldname = currentFormat().name();
2144 if (newname == oldname)
2146 if (form_->converters().formatIsUsed(oldname)) {
2147 Alert::error(_("Format in use"),
2148 _("You cannot change a format's short name "
2149 "if the format is used by a converter. "
2150 "Please remove the converter first."));
2155 currentFormat().setName(newname);
2160 void PrefFileformats::on_formatED_textChanged(const QString &)
2162 QString t = formatED->text();
2164 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2165 setValid(formatLA, valid);
2169 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2171 QString t = formatsCB->currentText();
2173 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2174 setValid(formatsLA, valid);
2178 void PrefFileformats::updatePrettyname()
2180 QString const newname = formatsCB->currentText();
2181 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2184 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2192 void updateComboBox(LyXRC::Alternatives const & alts,
2193 string const & fmt, QComboBox * combo)
2195 LyXRC::Alternatives::const_iterator it =
2197 if (it != alts.end()) {
2198 LyXRC::CommandSet const & cmds = it->second;
2199 LyXRC::CommandSet::const_iterator sit =
2201 LyXRC::CommandSet::const_iterator const sen =
2203 for (; sit != sen; ++sit) {
2204 QString const qcmd = toqstr(*sit);
2205 combo->addItem(qcmd, qcmd);
2212 void PrefFileformats::updateViewers()
2214 Format const f = currentFormat();
2215 viewerCO->blockSignals(true);
2217 viewerCO->addItem(qt_("None"), QString());
2218 if (os::canAutoOpenFile(f.extension(), os::VIEW))
2219 viewerCO->addItem(qt_("System Default"), QString("auto"));
2220 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2221 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2222 viewerCO->blockSignals(false);
2224 int pos = viewerCO->findData(toqstr(f.viewer()));
2227 viewerED->setEnabled(false);
2228 viewerCO->setCurrentIndex(pos);
2230 viewerED->setEnabled(true);
2231 viewerED->setText(toqstr(f.viewer()));
2232 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2237 void PrefFileformats::updateEditors()
2239 Format const f = currentFormat();
2240 editorCO->blockSignals(true);
2242 editorCO->addItem(qt_("None"), QString());
2243 if (os::canAutoOpenFile(f.extension(), os::EDIT))
2244 editorCO->addItem(qt_("System Default"), QString("auto"));
2245 updateComboBox(editor_alternatives, f.name(), editorCO);
2246 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2247 editorCO->blockSignals(false);
2249 int pos = editorCO->findData(toqstr(f.editor()));
2252 editorED->setEnabled(false);
2253 editorCO->setCurrentIndex(pos);
2255 editorED->setEnabled(true);
2256 editorED->setText(toqstr(f.editor()));
2257 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2262 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2264 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2265 viewerED->setEnabled(custom);
2267 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2271 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2273 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2274 editorED->setEnabled(custom);
2276 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2280 Format & PrefFileformats::currentFormat()
2282 int const i = formatsCB->currentIndex();
2283 int const nr = formatsCB->itemData(i).toInt();
2284 return form_->formats().get(nr);
2288 void PrefFileformats::on_formatNewPB_clicked()
2290 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2292 formatsCB->setCurrentIndex(0);
2293 formatsCB->setFocus(Qt::OtherFocusReason);
2297 void PrefFileformats::on_formatRemovePB_clicked()
2299 int const i = formatsCB->currentIndex();
2300 int const nr = formatsCB->itemData(i).toInt();
2301 string const current_text = form_->formats().get(nr).name();
2302 if (form_->converters().formatIsUsed(current_text)) {
2303 Alert::error(_("Format in use"),
2304 _("Cannot remove a Format used by a Converter. "
2305 "Remove the converter first."));
2309 form_->formats().erase(current_text);
2312 on_formatsCB_editTextChanged(formatsCB->currentText());
2317 /////////////////////////////////////////////////////////////////////
2321 /////////////////////////////////////////////////////////////////////
2323 PrefLanguage::PrefLanguage(GuiPreferences * form)
2324 : PrefModule(catLanguage, N_("Language"), form)
2328 connect(visualCursorRB, SIGNAL(clicked()),
2329 this, SIGNAL(changed()));
2330 connect(logicalCursorRB, SIGNAL(clicked()),
2331 this, SIGNAL(changed()));
2332 connect(markForeignCB, SIGNAL(clicked()),
2333 this, SIGNAL(changed()));
2334 connect(respectOSkbdCB, SIGNAL(clicked()),
2335 this, SIGNAL(changed()));
2336 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2337 this, SIGNAL(changed()));
2338 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2339 this, SIGNAL(changed()));
2340 connect(languagePackageCO, SIGNAL(activated(int)),
2341 this, SIGNAL(changed()));
2342 connect(languagePackageED, SIGNAL(textChanged(QString)),
2343 this, SIGNAL(changed()));
2344 connect(globalCB, SIGNAL(clicked()),
2345 this, SIGNAL(changed()));
2346 connect(startCommandED, SIGNAL(textChanged(QString)),
2347 this, SIGNAL(changed()));
2348 connect(endCommandED, SIGNAL(textChanged(QString)),
2349 this, SIGNAL(changed()));
2350 connect(uiLanguageCO, SIGNAL(activated(int)),
2351 this, SIGNAL(changed()));
2352 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2353 this, SIGNAL(changed()));
2354 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2355 this, SIGNAL(changed()));
2356 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2357 this, SIGNAL(changed()));
2359 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2360 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2361 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2363 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2364 defaultDecimalSepED->setMaxLength(1);
2366 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2367 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2369 QAbstractItemModel * language_model = guiApp->languageModel();
2370 language_model->sort(0);
2371 uiLanguageCO->blockSignals(true);
2372 uiLanguageCO->clear();
2373 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2374 for (int i = 0; i != language_model->rowCount(); ++i) {
2375 QModelIndex index = language_model->index(i, 0);
2376 // Filter the list based on the available translation and add
2377 // each language code only once
2378 string const name = fromqstr(index.data(Qt::UserRole).toString());
2379 Language const * lang = languages.getLanguage(name);
2382 // never remove the currently selected language
2383 if (name != form->rc().gui_language
2384 && name != lyxrc.gui_language
2385 && (!Messages::available(lang->code())
2386 || !lang->hasGuiSupport()))
2388 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2389 index.data(Qt::UserRole).toString());
2391 uiLanguageCO->blockSignals(false);
2393 // FIXME: restore this when it works (see discussion in #6450).
2394 respectOSkbdCB->hide();
2398 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2400 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2401 qt_("The change of user interface language will be fully "
2402 "effective only after a restart."));
2406 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2409 languagePackageED->setText(save_langpack_);
2410 else if (!languagePackageED->text().isEmpty()) {
2411 save_langpack_ = languagePackageED->text();
2412 languagePackageED->clear();
2414 languagePackageED->setEnabled(i == 2);
2418 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2420 defaultDecimalSepED->setEnabled(i == 1);
2424 void PrefLanguage::applyRC(LyXRC & rc) const
2426 rc.visual_cursor = visualCursorRB->isChecked();
2427 rc.mark_foreign_language = markForeignCB->isChecked();
2428 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2429 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2430 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2431 int const p = languagePackageCO->currentIndex();
2433 rc.language_package_selection = LyXRC::LP_AUTO;
2435 rc.language_package_selection = LyXRC::LP_BABEL;
2437 rc.language_package_selection = LyXRC::LP_CUSTOM;
2439 rc.language_package_selection = LyXRC::LP_NONE;
2440 rc.language_custom_package = fromqstr(languagePackageED->text());
2441 rc.language_global_options = globalCB->isChecked();
2442 rc.language_command_begin = fromqstr(startCommandED->text());
2443 rc.language_command_end = fromqstr(endCommandED->text());
2444 rc.gui_language = fromqstr(
2445 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2446 if (defaultDecimalSepCO->currentIndex() == 0)
2447 rc.default_decimal_sep = "locale";
2449 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2450 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2454 void PrefLanguage::updateRC(LyXRC const & rc)
2456 if (rc.visual_cursor)
2457 visualCursorRB->setChecked(true);
2459 logicalCursorRB->setChecked(true);
2460 markForeignCB->setChecked(rc.mark_foreign_language);
2461 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2462 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2463 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2464 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2465 if (languagePackageCO->currentIndex() == 2) {
2466 languagePackageED->setText(toqstr(rc.language_custom_package));
2467 languagePackageED->setEnabled(true);
2469 languagePackageED->clear();
2470 save_langpack_ = toqstr(rc.language_custom_package);
2471 languagePackageED->setEnabled(false);
2473 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2474 globalCB->setChecked(rc.language_global_options);
2475 startCommandED->setText(toqstr(rc.language_command_begin));
2476 endCommandED->setText(toqstr(rc.language_command_end));
2477 if (rc.default_decimal_sep == "locale") {
2478 defaultDecimalSepCO->setCurrentIndex(0);
2479 defaultDecimalSepED->clear();
2481 defaultDecimalSepCO->setCurrentIndex(1);
2482 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2484 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2485 defaultLengthUnitCO->setCurrentIndex(pos);
2487 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2488 uiLanguageCO->blockSignals(true);
2489 uiLanguageCO->setCurrentIndex(pos);
2490 uiLanguageCO->blockSignals(false);
2494 /////////////////////////////////////////////////////////////////////
2496 // PrefUserInterface
2498 /////////////////////////////////////////////////////////////////////
2500 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2501 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2505 connect(uiFilePB, SIGNAL(clicked()),
2506 this, SLOT(selectUi()));
2507 connect(uiFileED, SIGNAL(textChanged(QString)),
2508 this, SIGNAL(changed()));
2509 connect(iconSetCO, SIGNAL(activated(int)),
2510 this, SIGNAL(changed()));
2511 connect(uiStyleCO, SIGNAL(activated(int)),
2512 this, SIGNAL(changed()));
2513 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2514 this, SIGNAL(changed()));
2515 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2516 this, SIGNAL(changed()));
2517 connect(tooltipCB, SIGNAL(toggled(bool)),
2518 this, SIGNAL(changed()));
2519 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2520 this, SIGNAL(changed()));
2521 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2522 this, SIGNAL(changed()));
2523 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2524 this, SIGNAL(changed()));
2525 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2526 this, SIGNAL(changed()));
2527 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2528 this, SIGNAL(changed()));
2529 lastfilesSB->setMaximum(maxlastfiles);
2531 iconSetCO->addItem(qt_("Default"), QString());
2532 iconSetCO->addItem(qt_("Classic"), "classic");
2533 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2535 uiStyleCO->addItem(qt_("Default"), toqstr("default"));
2536 for (auto const & style : QStyleFactory::keys())
2537 uiStyleCO->addItem(style, style.toLower());
2539 if (guiApp->platformName() != "xcb"
2540 && !guiApp->platformName().contains("wayland"))
2541 useSystemThemeIconsCB->hide();
2545 void PrefUserInterface::applyRC(LyXRC & rc) const
2547 rc.icon_set = fromqstr(iconSetCO->itemData(
2548 iconSetCO->currentIndex()).toString());
2550 QString const uistyle = uiStyleCO->itemData(
2551 uiStyleCO->currentIndex()).toString();
2552 if (rc.ui_style != fromqstr(uistyle)) {
2553 rc.ui_style = fromqstr(uistyle);
2554 if (rc.ui_style == "default")
2555 // FIXME: This should work with frontend::GuiApplication::setStyle(QString())
2556 // Qt bug https://bugreports.qt.io/browse/QTBUG-58268
2557 frontend::Alert::warning(_("Restart needed"),
2558 _("Resetting the user interface style to 'Default'"
2559 " requires a restart of LyX."));
2561 frontend::GuiApplication::setStyle(uistyle);
2564 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2565 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2566 rc.num_lastfiles = lastfilesSB->value();
2567 rc.use_tooltip = tooltipCB->isChecked();
2568 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2569 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2570 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2571 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2572 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2576 void PrefUserInterface::updateRC(LyXRC const & rc)
2578 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2581 iconSetCO->setCurrentIndex(iconset);
2582 int uistyle = uiStyleCO->findData(toqstr(rc.ui_style));
2585 uiStyleCO->setCurrentIndex(uistyle);
2586 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2587 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2588 lastfilesSB->setValue(rc.num_lastfiles);
2589 tooltipCB->setChecked(rc.use_tooltip);
2590 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2591 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2592 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2593 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2594 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2598 void PrefUserInterface::selectUi()
2600 QString file = form_->browseUI(internalPath(uiFileED->text()));
2601 if (!file.isEmpty())
2602 uiFileED->setText(file);
2606 /////////////////////////////////////////////////////////////////////
2608 // PrefDocumentHandling
2610 /////////////////////////////////////////////////////////////////////
2612 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2613 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2617 connect(autoSaveCB, SIGNAL(toggled(bool)),
2618 autoSaveSB, SLOT(setEnabled(bool)));
2619 connect(autoSaveCB, SIGNAL(toggled(bool)),
2620 TextLabel1, SLOT(setEnabled(bool)));
2621 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2622 this, SIGNAL(changed()));
2623 connect(singleInstanceCB, SIGNAL(clicked()),
2624 this, SIGNAL(changed()));
2625 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2626 this, SIGNAL(changed()));
2627 connect(closeLastViewCO, SIGNAL(activated(int)),
2628 this, SIGNAL(changed()));
2629 connect(restoreCursorCB, SIGNAL(clicked()),
2630 this, SIGNAL(changed()));
2631 connect(loadSessionCB, SIGNAL(clicked()),
2632 this, SIGNAL(changed()));
2633 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2634 this, SIGNAL(changed()));
2635 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2636 this, SIGNAL(changed()));
2637 connect(autoSaveCB, SIGNAL(clicked()),
2638 this, SIGNAL(changed()));
2639 connect(backupCB, SIGNAL(clicked()),
2640 this, SIGNAL(changed()));
2641 connect(saveCompressedCB, SIGNAL(clicked()),
2642 this, SIGNAL(changed()));
2643 connect(saveOriginCB, SIGNAL(clicked()),
2644 this, SIGNAL(changed()));
2648 void PrefDocHandling::applyRC(LyXRC & rc) const
2650 rc.use_lastfilepos = restoreCursorCB->isChecked();
2651 rc.load_session = loadSessionCB->isChecked();
2652 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2653 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2654 rc.make_backup = backupCB->isChecked();
2655 rc.save_compressed = saveCompressedCB->isChecked();
2656 rc.save_origin = saveOriginCB->isChecked();
2657 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2658 rc.single_instance = singleInstanceCB->isChecked();
2659 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2661 switch (closeLastViewCO->currentIndex()) {
2663 rc.close_buffer_with_last_view = "yes";
2666 rc.close_buffer_with_last_view = "no";
2669 rc.close_buffer_with_last_view = "ask";
2677 void PrefDocHandling::updateRC(LyXRC const & rc)
2679 restoreCursorCB->setChecked(rc.use_lastfilepos);
2680 loadSessionCB->setChecked(rc.load_session);
2681 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2682 // convert to minutes
2683 bool autosave = rc.autosave > 0;
2684 int mins = rc.autosave / 60;
2687 autoSaveSB->setValue(mins);
2688 autoSaveCB->setChecked(autosave);
2689 autoSaveSB->setEnabled(autosave);
2690 backupCB->setChecked(rc.make_backup);
2691 saveCompressedCB->setChecked(rc.save_compressed);
2692 saveOriginCB->setChecked(rc.save_origin);
2693 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2694 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2695 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2696 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2697 if (rc.close_buffer_with_last_view == "yes")
2698 closeLastViewCO->setCurrentIndex(0);
2699 else if (rc.close_buffer_with_last_view == "no")
2700 closeLastViewCO->setCurrentIndex(1);
2701 else if (rc.close_buffer_with_last_view == "ask")
2702 closeLastViewCO->setCurrentIndex(2);
2703 if (rc.backupdir_path.empty())
2704 backupCB->setToolTip(qt_("If this is checked, a backup of the document is created "
2705 "in the current working directory. "
2706 "The backup file has the same name but the suffix '.lyx~'. "
2707 "Note that these files are hidden by default by some file managers. "
2708 "A dedicated backup directory can be set in the 'Paths' section."));
2710 docstring const tip = bformat(_("If this is checked, a backup of the document is created "
2711 "in the backup directory (%1$s). "
2712 "The backup file has the full original path and name as file name "
2713 "and the suffix \'.lyx~\' (e.g., !mydir!filename.lyx~). "
2714 "Note that these files are hidden by default by some file managers."),
2715 FileName(rc.backupdir_path).absoluteFilePath());
2716 backupCB->setToolTip(toqstr(tip));
2721 void PrefDocHandling::on_clearSessionPB_clicked()
2723 guiApp->clearSession();
2728 /////////////////////////////////////////////////////////////////////
2732 /////////////////////////////////////////////////////////////////////
2734 PrefEdit::PrefEdit(GuiPreferences * form)
2735 : PrefModule(catEditing, N_("Control"), form)
2739 connect(cursorFollowsCB, SIGNAL(clicked()),
2740 this, SIGNAL(changed()));
2741 connect(scrollBelowCB, SIGNAL(clicked()),
2742 this, SIGNAL(changed()));
2743 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2744 this, SIGNAL(changed()));
2745 connect(copyCTMarkupCB, SIGNAL(clicked()),
2746 this, SIGNAL(changed()));
2747 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2748 this, SIGNAL(changed()));
2749 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2750 this, SIGNAL(changed()));
2751 connect(macroEditStyleCO, SIGNAL(activated(int)),
2752 this, SIGNAL(changed()));
2753 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2754 this, SIGNAL(changed()));
2755 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2756 this, SIGNAL(changed()));
2757 connect(screenWidthLE, SIGNAL(textChanged(QString)),
2758 this, SIGNAL(changed()));
2759 connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
2760 this, SIGNAL(changed()));
2764 void PrefEdit::on_screenLimitCB_toggled(bool const state)
2766 screenWidthLE->setEnabled(state);
2767 screenWidthUnitCO->setEnabled(state);
2772 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2774 citationSearchLE->setEnabled(state);
2775 citationSearchLA->setEnabled(state);
2780 void PrefEdit::applyRC(LyXRC & rc) const
2782 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2783 rc.scroll_below_document = scrollBelowCB->isChecked();
2784 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2785 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2786 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2787 rc.group_layouts = groupEnvironmentsCB->isChecked();
2788 switch (macroEditStyleCO->currentIndex()) {
2789 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2790 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2791 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2793 rc.cursor_width = cursorWidthSB->value();
2794 rc.citation_search = citationSearchCB->isChecked();
2795 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2796 rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO));
2797 rc.screen_limit = screenLimitCB->isChecked();
2801 void PrefEdit::updateRC(LyXRC const & rc)
2803 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2804 scrollBelowCB->setChecked(rc.scroll_below_document);
2805 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2806 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2807 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2808 groupEnvironmentsCB->setChecked(rc.group_layouts);
2809 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2810 cursorWidthSB->setValue(rc.cursor_width);
2811 citationSearchCB->setChecked(rc.citation_search);
2812 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2813 citationSearchLE->setEnabled(rc.citation_search);
2814 citationSearchLA->setEnabled(rc.citation_search);
2815 lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
2816 screenWidthUnitCO->setEnabled(rc.screen_limit);
2817 screenLimitCB->setChecked(rc.screen_limit);
2818 screenWidthLE->setEnabled(rc.screen_limit);
2822 /////////////////////////////////////////////////////////////////////
2826 /////////////////////////////////////////////////////////////////////
2829 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2831 Ui::shortcutUi::setupUi(this);
2832 QDialog::setModal(true);
2833 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2834 on_lfunLE_textChanged();
2838 void GuiShortcutDialog::on_lfunLE_textChanged()
2840 QPushButton * ok = buttonBox->button(QDialogButtonBox::Ok);
2841 ok->setEnabled(!lfunLE->text().isEmpty());
2845 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2846 : PrefModule(catEditing, N_("Shortcuts"), form),
2847 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2848 systemItem_(nullptr)
2852 shortcutsTW->setColumnCount(2);
2853 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2854 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2855 shortcutsTW->setSortingEnabled(true);
2856 // Multi-selection can be annoying.
2857 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2859 connect(bindFilePB, SIGNAL(clicked()),
2860 this, SLOT(selectBind()));
2861 connect(bindFileED, SIGNAL(textChanged(QString)),
2862 this, SIGNAL(changed()));
2864 shortcut_ = new GuiShortcutDialog(this);
2865 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2866 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2867 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2869 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2870 this, SIGNAL(changed()));
2871 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2872 shortcut_, SLOT(reject()));
2873 connect(shortcut_->clearPB, SIGNAL(clicked()),
2874 this, SLOT(shortcutClearPressed()));
2875 connect(shortcut_->removePB, SIGNAL(clicked()),
2876 this, SLOT(shortcutRemovePressed()));
2877 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2878 this, SLOT(shortcutOkPressed()));
2879 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2880 this, SLOT(shortcutCancelPressed()));
2884 void PrefShortcuts::applyRC(LyXRC & rc) const
2886 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2887 // write user_bind and user_unbind to .lyx/bind/user.bind
2888 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2889 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2890 lyxerr << "LyX could not create the user bind directory '"
2891 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2894 if (!bind_dir.isDirWritable()) {
2895 lyxerr << "LyX could not write to the user bind directory '"
2896 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2899 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2900 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2901 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2902 // immediately apply the keybindings. Why this is not done before?
2903 // The good thing is that the menus are updated automatically.
2904 theTopLevelKeymap().clear();
2905 theTopLevelKeymap().read("site");
2906 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2907 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2911 void PrefShortcuts::updateRC(LyXRC const & rc)
2913 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2915 system_bind_.clear();
2917 user_unbind_.clear();
2918 system_bind_.read("site");
2919 system_bind_.read(rc.bind_file);
2920 // \unbind in user.bind is added to user_unbind_
2921 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2922 updateShortcutsTW();
2926 void PrefShortcuts::updateShortcutsTW()
2928 shortcutsTW->clear();
2930 editItem_ = new QTreeWidgetItem(shortcutsTW);
2931 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2932 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
2934 mathItem_ = new QTreeWidgetItem(shortcutsTW);
2935 mathItem_->setText(0, qt_("Mathematical Symbols"));
2936 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
2938 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
2939 bufferItem_->setText(0, qt_("Document and Window"));
2940 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
2942 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
2943 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
2944 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
2946 systemItem_ = new QTreeWidgetItem(shortcutsTW);
2947 systemItem_->setText(0, qt_("System and Miscellaneous"));
2948 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
2950 // listBindings(unbound=true) lists all bound and unbound lfuns
2951 // Items in this list is tagged by its source.
2952 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
2954 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
2956 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
2957 KeyMap::UserUnbind);
2958 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
2959 user_bindinglist.end());
2960 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
2961 user_unbindinglist.end());
2963 KeyMap::BindingList::const_iterator it = bindinglist.begin();
2964 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
2965 for (; it != it_end; ++it)
2966 insertShortcutItem(it->request, it->sequence, it->tag);
2968 shortcutsTW->sortItems(0, Qt::AscendingOrder);
2969 on_shortcutsTW_itemSelectionChanged();
2970 on_searchLE_textEdited();
2971 shortcutsTW->resizeColumnToContents(0);
2976 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
2978 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
2983 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
2985 // Hide rebound system settings that are empty
2986 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
2990 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
2992 item->setData(0, Qt::UserRole, QVariant(tag));
2996 case KeyMap::System:
2998 case KeyMap::UserBind:
3001 case KeyMap::UserUnbind:
3002 font.setStrikeOut(true);
3004 // this item is not displayed now.
3005 case KeyMap::UserExtraUnbind:
3006 font.setStrikeOut(true);
3009 item->setHidden(isAlwaysHidden(*item));
3010 item->setFont(1, font);
3014 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3015 KeySequence const & seq, KeyMap::ItemType tag)
3017 FuncCode const action = lfun.action();
3018 string const action_name = lyxaction.getActionName(action);
3019 QString const lfun_name = toqstr(from_utf8(action_name)
3020 + ' ' + lfun.argument());
3021 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3023 QTreeWidgetItem * newItem = nullptr;
3024 // for unbind items, try to find an existing item in the system bind list
3025 if (tag == KeyMap::UserUnbind) {
3026 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3027 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3028 for (auto const & item : items) {
3029 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3034 // if not found, this unbind item is KeyMap::UserExtraUnbind
3035 // Such an item is not displayed to avoid confusion (what is
3036 // unmatched removed?).
3042 switch(lyxaction.getActionType(action)) {
3043 case LyXAction::Hidden:
3045 case LyXAction::Edit:
3046 newItem = new QTreeWidgetItem(editItem_);
3048 case LyXAction::Math:
3049 newItem = new QTreeWidgetItem(mathItem_);
3051 case LyXAction::Buffer:
3052 newItem = new QTreeWidgetItem(bufferItem_);
3054 case LyXAction::Layout:
3055 newItem = new QTreeWidgetItem(layoutItem_);
3057 case LyXAction::System:
3058 newItem = new QTreeWidgetItem(systemItem_);
3061 // this should not happen
3062 newItem = new QTreeWidgetItem(shortcutsTW);
3064 newItem->setText(0, lfun_name);
3065 newItem->setText(1, shortcut);
3068 // record BindFile representation to recover KeySequence when needed.
3069 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3070 setItemType(newItem, tag);
3075 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3077 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3078 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3079 modifyPB->setEnabled(!items.isEmpty());
3080 if (items.isEmpty())
3083 if (itemType(*items[0]) == KeyMap::UserUnbind)
3084 removePB->setText(qt_("Res&tore"));
3086 removePB->setText(qt_("Remo&ve"));
3090 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3096 void PrefShortcuts::modifyShortcut()
3098 QTreeWidgetItem * item = shortcutsTW->currentItem();
3099 if (item->flags() & Qt::ItemIsSelectable) {
3100 shortcut_->lfunLE->setText(item->text(0));
3101 save_lfun_ = item->text(0).trimmed();
3102 shortcut_->shortcutWG->setText(item->text(1));
3104 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3105 shortcut_->shortcutWG->setKeySequence(seq);
3106 shortcut_->shortcutWG->setFocus();
3112 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3114 // list of items that match lfun
3115 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3116 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3117 for (auto const & item : items) {
3118 if (isAlwaysHidden(*item)) {
3119 setItemType(item, KeyMap::System);
3121 shortcutsTW->setCurrentItem(item);
3128 void PrefShortcuts::removeShortcut()
3130 // it seems that only one item can be selected, but I am
3131 // removing all selected items anyway.
3132 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3133 for (auto & item : items) {
3134 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3135 string lfun = fromqstr(item->text(0));
3136 FuncRequest const func = lyxaction.lookupFunc(lfun);
3138 switch (itemType(*item)) {
3139 case KeyMap::System: {
3140 // for system bind, we do not touch the item
3141 // but add an user unbind item
3142 user_unbind_.bind(shortcut, func);
3143 setItemType(item, KeyMap::UserUnbind);
3144 removePB->setText(qt_("Res&tore"));
3147 case KeyMap::UserBind: {
3148 // for user_bind, we remove this bind
3149 QTreeWidgetItem * parent = item->parent();
3150 int itemIdx = parent->indexOfChild(item);
3151 parent->takeChild(itemIdx);
3153 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3155 shortcutsTW->scrollToItem(parent);
3156 user_bind_.unbind(shortcut, func);
3157 // If this user binding hid an empty system binding, unhide the
3158 // latter and select it.
3159 unhideEmpty(item->text(0), true);
3162 case KeyMap::UserUnbind: {
3163 // for user_unbind, we remove the unbind, and the item
3164 // become KeyMap::System again.
3166 seq.parse(shortcut);
3167 // Ask the user to replace current binding
3168 if (!validateNewShortcut(func, seq, QString()))
3170 user_unbind_.unbind(shortcut, func);
3171 setItemType(item, KeyMap::System);
3172 removePB->setText(qt_("Remo&ve"));
3175 case KeyMap::UserExtraUnbind: {
3176 // for user unbind that is not in system bind file,
3177 // remove this unbind file
3178 QTreeWidgetItem * parent = item->parent();
3179 parent->takeChild(parent->indexOfChild(item));
3180 user_unbind_.unbind(shortcut, func);
3187 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3189 for (auto item : items) {
3190 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3191 string lfun = fromqstr(item->text(0));
3192 FuncRequest const func = lyxaction.lookupFunc(lfun);
3194 switch (itemType(*item)) {
3195 case KeyMap::System:
3196 // for system bind, we do not touch the item
3197 // but add an user unbind item
3198 user_unbind_.bind(shortcut, func);
3199 setItemType(item, KeyMap::UserUnbind);
3202 case KeyMap::UserBind: {
3203 // for user_bind, we remove this bind
3204 QTreeWidgetItem * parent = item->parent();
3205 int itemIdx = parent->indexOfChild(item);
3206 parent->takeChild(itemIdx);
3207 user_bind_.unbind(shortcut, func);
3208 unhideEmpty(item->text(0), false);
3218 void PrefShortcuts::selectBind()
3220 QString file = form_->browsebind(internalPath(bindFileED->text()));
3221 if (!file.isEmpty()) {
3222 bindFileED->setText(file);
3223 system_bind_ = KeyMap();
3224 system_bind_.read(fromqstr(file));
3225 updateShortcutsTW();
3230 void PrefShortcuts::on_modifyPB_pressed()
3236 void PrefShortcuts::on_newPB_pressed()
3238 shortcut_->lfunLE->clear();
3239 shortcut_->shortcutWG->reset();
3240 save_lfun_ = QString();
3245 void PrefShortcuts::on_removePB_pressed()
3252 void PrefShortcuts::on_searchLE_textEdited()
3254 if (searchLE->text().isEmpty()) {
3255 // show all hidden items
3256 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3258 (*it)->setHidden(isAlwaysHidden(**it));
3259 // close all categories
3260 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3261 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3264 // search both columns
3265 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3266 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3267 matched += shortcutsTW->findItems(searchLE->text(),
3268 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3270 // hide everyone (to avoid searching in matched QList repeatedly
3271 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3273 (*it++)->setHidden(true);
3274 // show matched items
3275 for (auto & item : matched)
3276 if (!isAlwaysHidden(*item)) {
3277 item->setHidden(false);
3279 item->parent()->setExpanded(true);
3284 docstring makeCmdString(FuncRequest const & f)
3286 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3287 if (!f.argument().empty())
3288 actionStr += " " + f.argument();
3293 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3295 FuncRequest res = user_bind_.getBinding(k);
3296 if (res != FuncRequest::unknown)
3298 res = system_bind_.getBinding(k);
3300 // Check if it is unbound. Note: user_unbind_ can only unbind one
3301 // FuncRequest per key sequence.
3302 if (user_unbind_.getBinding(k) == res)
3303 return FuncRequest::unknown;
3308 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3309 KeySequence const & k,
3310 QString const & lfun_to_modify)
3312 if (func.action() == LFUN_UNKNOWN_ACTION) {
3313 Alert::error(_("Failed to create shortcut"),
3314 _("Unknown or invalid LyX function"));
3318 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3319 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3320 // and how it is used in GuiPrefs::shortcutOkPressed.
3321 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3322 Alert::error(_("Failed to create shortcut"),
3323 _("This LyX function is hidden and cannot be bound."));
3327 if (k.length() == 0) {
3328 Alert::error(_("Failed to create shortcut"),
3329 _("Invalid or empty key sequence"));
3333 FuncRequest oldBinding = currentBinding(k);
3334 if (oldBinding == func)
3335 // nothing to change
3338 // Check whether the key sequence is a prefix for other shortcuts.
3339 if (oldBinding == FuncRequest::prefix) {
3340 docstring const new_action_string = makeCmdString(func);
3341 docstring const text = bformat(_("Shortcut `%1$s' is already a prefix for other commands.\n"
3342 "Are you sure you want to unbind these commands and bind it to %2$s?"),
3343 k.print(KeySequence::ForGui), new_action_string);
3344 int ret = Alert::prompt(_("Redefine shortcut?"),
3345 text, 0, 1, _("&Redefine"), _("&Cancel"));
3348 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3349 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3350 Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchRecursive), 1);
3351 deactivateShortcuts(items);
3355 // make sure this key isn't already bound---and, if so, prompt user
3356 // (exclude the lfun the user already wants to modify)
3357 docstring const action_string = makeCmdString(oldBinding);
3358 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3359 && lfun_to_modify != toqstr(action_string)) {
3360 docstring const new_action_string = makeCmdString(func);
3361 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3363 "Are you sure you want to unbind the "
3364 "current shortcut and bind it to %3$s?"),
3365 k.print(KeySequence::ForGui), action_string,
3367 int ret = Alert::prompt(_("Redefine shortcut?"),
3368 text, 0, 1, _("&Redefine"), _("&Cancel"));
3371 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3372 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3373 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3374 deactivateShortcuts(items);
3380 void PrefShortcuts::shortcutOkPressed()
3382 QString const new_lfun = shortcut_->lfunLE->text();
3383 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3384 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3386 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3387 // "modify", or is empty if they clicked "new" (which I do not really like)
3388 if (!validateNewShortcut(func, k, save_lfun_))
3391 if (!save_lfun_.isEmpty()) {
3392 // real modification of the lfun's shortcut,
3393 // so remove the previous one
3394 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3395 deactivateShortcuts(to_modify);
3398 shortcut_->accept();
3400 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3402 user_bind_.bind(&k, func);
3403 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3405 item->parent()->setExpanded(true);
3406 shortcutsTW->setCurrentItem(item);
3407 shortcutsTW->scrollToItem(item);
3409 Alert::error(_("Failed to create shortcut"),
3410 _("Can not insert shortcut to the list"));
3416 void PrefShortcuts::shortcutCancelPressed()
3418 shortcut_->shortcutWG->reset();
3422 void PrefShortcuts::shortcutClearPressed()
3424 shortcut_->shortcutWG->reset();
3428 void PrefShortcuts::shortcutRemovePressed()
3430 shortcut_->shortcutWG->removeFromSequence();
3434 /////////////////////////////////////////////////////////////////////
3438 /////////////////////////////////////////////////////////////////////
3440 PrefIdentity::PrefIdentity(GuiPreferences * form)
3441 : PrefModule(QString(), N_("Identity"), form)
3445 connect(nameED, SIGNAL(textChanged(QString)),
3446 this, SIGNAL(changed()));
3447 connect(emailED, SIGNAL(textChanged(QString)),
3448 this, SIGNAL(changed()));
3449 connect(initialsED, SIGNAL(textChanged(QString)),
3450 this, SIGNAL(changed()));
3452 nameED->setValidator(new NoNewLineValidator(nameED));
3453 emailED->setValidator(new NoNewLineValidator(emailED));
3454 initialsED->setValidator(new NoNewLineValidator(initialsED));
3458 void PrefIdentity::applyRC(LyXRC & rc) const
3460 rc.user_name = fromqstr(nameED->text());
3461 rc.user_email = fromqstr(emailED->text());
3462 rc.user_initials = fromqstr(initialsED->text());
3466 void PrefIdentity::updateRC(LyXRC const & rc)
3468 nameED->setText(toqstr(rc.user_name));
3469 emailED->setText(toqstr(rc.user_email));
3470 initialsED->setText(toqstr(rc.user_initials));
3475 /////////////////////////////////////////////////////////////////////
3479 /////////////////////////////////////////////////////////////////////
3481 GuiPreferences::GuiPreferences(GuiView & lv)
3482 : GuiDialog(lv, "prefs", qt_("Preferences"))
3486 QDialog::setModal(false);
3488 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3489 this, SLOT(slotButtonBox(QAbstractButton *)));
3491 addModule(new PrefUserInterface(this));
3492 addModule(new PrefDocHandling(this));
3493 addModule(new PrefEdit(this));
3494 addModule(new PrefShortcuts(this));
3495 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3496 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3497 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3498 addModule(screenfonts);
3499 addModule(new PrefColors(this));
3500 addModule(new PrefDisplay(this));
3501 addModule(new PrefInput(this));
3502 addModule(new PrefCompletion(this));
3504 addModule(new PrefPaths(this));
3506 addModule(new PrefIdentity(this));
3508 addModule(new PrefLanguage(this));
3509 addModule(new PrefSpellchecker(this));
3511 PrefOutput * output = new PrefOutput(this);
3513 addModule(new PrefLatex(this));
3515 PrefConverters * converters = new PrefConverters(this);
3516 PrefFileformats * formats = new PrefFileformats(this);
3517 connect(formats, SIGNAL(formatsChanged()),
3518 converters, SLOT(updateGui()));
3519 addModule(converters);
3522 prefsPS->setCurrentPanel("User Interface");
3524 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3525 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3526 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3527 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3528 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3530 guilyxfiles_ = new GuiLyXFiles(lv);
3531 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3532 this, SLOT(slotFileSelected(QString)));
3536 void GuiPreferences::addModule(PrefModule * module)
3538 LASSERT(module, return);
3539 if (module->category().isEmpty())
3540 prefsPS->addPanel(module, module->title());
3542 prefsPS->addPanel(module, module->title(), module->category());
3543 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3544 modules_.push_back(module);
3548 void GuiPreferences::change_adaptor()
3554 void GuiPreferences::applyRC(LyXRC & rc) const
3556 size_t end = modules_.size();
3557 for (size_t i = 0; i != end; ++i)
3558 modules_[i]->applyRC(rc);
3562 void GuiPreferences::updateRC(LyXRC const & rc)
3564 size_t const end = modules_.size();
3565 for (size_t i = 0; i != end; ++i)
3566 modules_[i]->updateRC(rc);
3570 void GuiPreferences::applyView()
3576 bool GuiPreferences::initialiseParams(string const &)
3579 formats_ = theFormats();
3580 converters_ = theConverters();
3581 converters_.update(formats_);
3582 movers_ = theMovers();
3586 // Make sure that the bc is in the INITIAL state
3587 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3594 void GuiPreferences::dispatchParams()
3597 rc_.write(ss, true);
3598 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3599 // issue prefsApplied signal. This will update the
3600 // localized screen font sizes.
3602 // FIXME: these need lfuns
3604 Author const & author =
3605 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3606 from_utf8(rc_.user_initials));
3607 theBufferList().recordCurrentAuthor(author);
3609 theFormats() = formats_;
3611 theConverters() = converters_;
3612 theConverters().update(formats_);
3613 theConverters().buildGraph();
3614 theBufferList().invalidateConverterCache();
3616 theMovers() = movers_;
3618 for (string const & color : colors_)
3619 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3623 if (!tempSaveCB->isChecked())
3624 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3628 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3630 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3634 void GuiPreferences::slotFileSelected(QString const file)
3640 QString GuiPreferences::browseLibFile(QString const & dir,
3641 QString const & name, QString const & ext)
3645 guilyxfiles_->passParams(fromqstr(dir));
3646 guilyxfiles_->selectItem(name);
3647 guilyxfiles_->exec();
3649 if (frontend::guiApp->platformName() == "cocoa") {
3650 QWidget * dialog_ = asQWidget();
3652 dialog_->activateWindow();
3655 QString const result = uifile_;
3657 // remove the extension if it is the default one
3658 QString noextresult;
3659 if (getExtension(result) == ext)
3660 noextresult = removeExtension(result);
3662 noextresult = result;
3664 // remove the directory, if it is the default one
3665 QString const file = onlyFileName(noextresult);
3666 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3673 QString GuiPreferences::browsebind(QString const & file)
3675 return browseLibFile("bind", file, "bind");
3679 QString GuiPreferences::browseUI(QString const & file)
3681 return browseLibFile("ui", file, "ui");
3685 QString GuiPreferences::browsekbmap(QString const & file)
3687 return browseLibFile("kbd", file, "kmap");
3691 QString GuiPreferences::browse(QString const & file,
3692 QString const & title)
3694 return browseFile(file, title, QStringList(), true);
3698 } // namespace frontend
3701 #include "moc_GuiPrefs.cpp"