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 static void activatePrefsWindow(GuiPreferences * form_)
195 if (guiApp->platformName() == "cocoa") {
196 QWidget * dialog_ = form_->asQWidget();
198 dialog_->activateWindow();
203 /////////////////////////////////////////////////////////////////////
207 /////////////////////////////////////////////////////////////////////
209 PrefOutput::PrefOutput(GuiPreferences * form)
210 : PrefModule(catOutput, N_("General[[settings]]"), form)
214 dviCB->setValidator(new NoNewLineValidator(dviCB));
215 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
217 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
218 this, SIGNAL(changed()));
219 connect(overwriteCO, SIGNAL(activated(int)),
220 this, SIGNAL(changed()));
221 connect(dviCB, SIGNAL(editTextChanged(QString)),
222 this, SIGNAL(changed()));
223 connect(pdfCB, SIGNAL(editTextChanged(QString)),
224 this, SIGNAL(changed()));
225 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
226 this, SIGNAL(changed()));
227 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
228 this, SIGNAL(changed()));
229 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
230 this, SIGNAL(changed()));
232 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
233 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
234 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
237 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
238 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
239 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
240 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
242 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
243 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
244 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
245 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
246 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
247 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
248 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
252 void PrefOutput::applyRC(LyXRC & rc) const
254 rc.plaintext_linelen = plaintextLinelengthSB->value();
255 rc.forward_search_dvi = fromqstr(dviCB->currentText());
256 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
258 switch (overwriteCO->currentIndex()) {
260 rc.export_overwrite = NO_FILES;
263 rc.export_overwrite = MAIN_FILE;
266 rc.export_overwrite = ALL_FILES;
270 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
271 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
272 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
276 void PrefOutput::updateRC(LyXRC const & rc)
278 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
279 dviCB->setEditText(toqstr(rc.forward_search_dvi));
280 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
282 switch (rc.export_overwrite) {
284 overwriteCO->setCurrentIndex(0);
287 overwriteCO->setCurrentIndex(1);
290 overwriteCO->setCurrentIndex(2);
294 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
295 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
296 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
300 /////////////////////////////////////////////////////////////////////
304 /////////////////////////////////////////////////////////////////////
306 PrefInput::PrefInput(GuiPreferences * form)
307 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
311 connect(keymapCB, SIGNAL(clicked()),
312 this, SIGNAL(changed()));
313 connect(firstKeymapED, SIGNAL(textChanged(QString)),
314 this, SIGNAL(changed()));
315 connect(secondKeymapED, SIGNAL(textChanged(QString)),
316 this, SIGNAL(changed()));
317 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
318 this, SIGNAL(changed()));
319 connect(scrollzoomEnableCB, SIGNAL(clicked()),
320 this, SIGNAL(changed()));
321 connect(scrollzoomValueCO, SIGNAL(activated(int)),
322 this, SIGNAL(changed()));
323 connect(dontswapCB, SIGNAL(toggled(bool)),
324 this, SIGNAL(changed()));
325 connect(mmPasteCB, SIGNAL(toggled(bool)),
326 this, SIGNAL(changed()));
328 // reveal checkbox for switching Ctrl and Meta on Mac:
330 dontswapCB->setVisible(true);
332 dontswapCB->setVisible(false);
337 void PrefInput::applyRC(LyXRC & rc) const
339 // FIXME: can derive CB from the two EDs
340 rc.use_kbmap = keymapCB->isChecked();
341 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
342 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
343 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
344 if (scrollzoomEnableCB->isChecked()) {
345 switch (scrollzoomValueCO->currentIndex()) {
347 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
350 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
353 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
357 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
359 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
360 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
364 void PrefInput::updateRC(LyXRC const & rc)
366 // FIXME: can derive CB from the two EDs
367 keymapCB->setChecked(rc.use_kbmap);
368 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
369 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
370 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
371 switch (rc.scroll_wheel_zoom) {
372 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
373 scrollzoomEnableCB->setChecked(false);
375 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
376 scrollzoomEnableCB->setChecked(true);
377 scrollzoomValueCO->setCurrentIndex(0);
379 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
380 scrollzoomEnableCB->setChecked(true);
381 scrollzoomValueCO->setCurrentIndex(1);
383 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
384 scrollzoomEnableCB->setChecked(true);
385 scrollzoomValueCO->setCurrentIndex(2);
388 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
389 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
393 QString PrefInput::testKeymap(QString const & keymap)
395 return form_->browsekbmap(internalPath(keymap));
399 void PrefInput::on_firstKeymapPB_clicked(bool)
401 QString const file = testKeymap(firstKeymapED->text());
403 firstKeymapED->setText(file);
407 void PrefInput::on_secondKeymapPB_clicked(bool)
409 QString const file = testKeymap(secondKeymapED->text());
411 secondKeymapED->setText(file);
415 void PrefInput::on_keymapCB_toggled(bool keymap)
417 firstKeymapLA->setEnabled(keymap);
418 secondKeymapLA->setEnabled(keymap);
419 firstKeymapED->setEnabled(keymap);
420 secondKeymapED->setEnabled(keymap);
421 firstKeymapPB->setEnabled(keymap);
422 secondKeymapPB->setEnabled(keymap);
426 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
428 scrollzoomValueCO->setEnabled(enabled);
432 /////////////////////////////////////////////////////////////////////
436 /////////////////////////////////////////////////////////////////////
438 PrefCompletion::PrefCompletion(GuiPreferences * form)
439 : PrefModule(catEditing, N_("Input Completion"), form)
443 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
444 this, SIGNAL(changed()));
445 connect(inlineMathCB, SIGNAL(clicked()),
446 this, SIGNAL(changed()));
447 connect(inlineTextCB, SIGNAL(clicked()),
448 this, SIGNAL(changed()));
449 connect(inlineDotsCB, SIGNAL(clicked()),
450 this, SIGNAL(changed()));
451 connect(popupDelaySB, SIGNAL(valueChanged(double)),
452 this, SIGNAL(changed()));
453 connect(popupMathCB, SIGNAL(clicked()),
454 this, SIGNAL(changed()));
455 connect(autocorrectionCB, SIGNAL(clicked()),
456 this, SIGNAL(changed()));
457 connect(popupTextCB, SIGNAL(clicked()),
458 this, SIGNAL(changed()));
459 connect(popupAfterCompleteCB, SIGNAL(clicked()),
460 this, SIGNAL(changed()));
461 connect(cursorTextCB, SIGNAL(clicked()),
462 this, SIGNAL(changed()));
463 connect(minlengthSB, SIGNAL(valueChanged(int)),
464 this, SIGNAL(changed()));
468 void PrefCompletion::on_inlineTextCB_clicked()
474 void PrefCompletion::on_popupTextCB_clicked()
480 void PrefCompletion::enableCB()
482 cursorTextCB->setEnabled(
483 popupTextCB->isChecked() || inlineTextCB->isChecked());
487 void PrefCompletion::applyRC(LyXRC & rc) const
489 rc.completion_inline_delay = inlineDelaySB->value();
490 rc.completion_inline_math = inlineMathCB->isChecked();
491 rc.completion_inline_text = inlineTextCB->isChecked();
492 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
493 rc.completion_popup_delay = popupDelaySB->value();
494 rc.completion_popup_math = popupMathCB->isChecked();
495 rc.autocorrection_math = autocorrectionCB->isChecked();
496 rc.completion_popup_text = popupTextCB->isChecked();
497 rc.completion_cursor_text = cursorTextCB->isChecked();
498 rc.completion_popup_after_complete =
499 popupAfterCompleteCB->isChecked();
500 rc.completion_minlength = minlengthSB->value();
504 void PrefCompletion::updateRC(LyXRC const & rc)
506 inlineDelaySB->setValue(rc.completion_inline_delay);
507 inlineMathCB->setChecked(rc.completion_inline_math);
508 inlineTextCB->setChecked(rc.completion_inline_text);
509 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
510 popupDelaySB->setValue(rc.completion_popup_delay);
511 popupMathCB->setChecked(rc.completion_popup_math);
512 autocorrectionCB->setChecked(rc.autocorrection_math);
513 popupTextCB->setChecked(rc.completion_popup_text);
514 cursorTextCB->setChecked(rc.completion_cursor_text);
515 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
517 minlengthSB->setValue(rc.completion_minlength);
522 /////////////////////////////////////////////////////////////////////
526 /////////////////////////////////////////////////////////////////////
528 PrefLatex::PrefLatex(GuiPreferences * form)
529 : PrefModule(catOutput, N_("LaTeX"), form)
533 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
534 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
535 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
536 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
537 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
538 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
539 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
541 connect(latexChecktexED, SIGNAL(textChanged(QString)),
542 this, SIGNAL(changed()));
543 connect(latexBibtexCO, SIGNAL(activated(int)),
544 this, SIGNAL(changed()));
545 connect(latexBibtexED, SIGNAL(textChanged(QString)),
546 this, SIGNAL(changed()));
547 connect(latexJBibtexCO, SIGNAL(activated(int)),
548 this, SIGNAL(changed()));
549 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
550 this, SIGNAL(changed()));
551 connect(latexIndexCO, SIGNAL(activated(int)),
552 this, SIGNAL(changed()));
553 connect(latexIndexED, SIGNAL(textChanged(QString)),
554 this, SIGNAL(changed()));
555 connect(latexJIndexED, SIGNAL(textChanged(QString)),
556 this, SIGNAL(changed()));
557 connect(latexAutoresetCB, SIGNAL(clicked()),
558 this, SIGNAL(changed()));
559 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
560 this, SIGNAL(changed()));
561 connect(latexNomenclED, SIGNAL(textChanged(QString)),
562 this, SIGNAL(changed()));
564 #if defined(__CYGWIN__) || defined(_WIN32)
565 pathCB->setVisible(true);
566 connect(pathCB, SIGNAL(clicked()),
567 this, SIGNAL(changed()));
569 pathCB->setVisible(false);
574 void PrefLatex::on_latexBibtexCO_activated(int n)
576 QString const bibtex = latexBibtexCO->itemData(n).toString();
577 if (bibtex.isEmpty()) {
578 latexBibtexED->clear();
579 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
582 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
583 it != bibtex_alternatives.end(); ++it) {
584 QString const bib = toqstr(*it);
585 int ind = bib.indexOf(" ");
586 QString sel_command = bib.left(ind);
587 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
588 if (bibtex == sel_command) {
590 latexBibtexED->clear();
592 latexBibtexED->setText(sel_options.trimmed());
595 latexBibtexOptionsLA->setText(qt_("&Options:"));
599 void PrefLatex::on_latexJBibtexCO_activated(int n)
601 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
602 if (jbibtex.isEmpty()) {
603 latexJBibtexED->clear();
604 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
607 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
608 it != jbibtex_alternatives.end(); ++it) {
609 QString const bib = toqstr(*it);
610 int ind = bib.indexOf(" ");
611 QString sel_command = bib.left(ind);
612 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
613 if (jbibtex == sel_command) {
615 latexJBibtexED->clear();
617 latexJBibtexED->setText(sel_options.trimmed());
620 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
624 void PrefLatex::on_latexIndexCO_activated(int n)
626 QString const index = latexIndexCO->itemData(n).toString();
627 if (index.isEmpty()) {
628 latexIndexED->clear();
629 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
632 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
633 it != index_alternatives.end(); ++it) {
634 QString const idx = toqstr(*it);
635 int ind = idx.indexOf(" ");
636 QString sel_command = idx.left(ind);
637 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
638 if (index == sel_command) {
640 latexIndexED->clear();
642 latexIndexED->setText(sel_options.trimmed());
645 latexIndexOptionsLA->setText(qt_("Op&tions:"));
649 void PrefLatex::applyRC(LyXRC & rc) const
651 // If bibtex is not empty, bibopt contains the options, otherwise
652 // it is a customized bibtex command with options.
653 QString const bibtex = latexBibtexCO->itemData(
654 latexBibtexCO->currentIndex()).toString();
655 QString const bibopt = latexBibtexED->text();
656 if (bibtex.isEmpty())
657 rc.bibtex_command = fromqstr(bibopt);
658 else if (bibopt.isEmpty())
659 rc.bibtex_command = fromqstr(bibtex);
661 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
663 // If jbibtex is not empty, jbibopt contains the options, otherwise
664 // it is a customized bibtex command with options.
665 QString const jbibtex = latexJBibtexCO->itemData(
666 latexJBibtexCO->currentIndex()).toString();
667 QString const jbibopt = latexJBibtexED->text();
668 if (jbibtex.isEmpty())
669 rc.jbibtex_command = fromqstr(jbibopt);
670 else if (jbibopt.isEmpty())
671 rc.jbibtex_command = fromqstr(jbibtex);
673 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
675 // If index is not empty, idxopt contains the options, otherwise
676 // it is a customized index command with options.
677 QString const index = latexIndexCO->itemData(
678 latexIndexCO->currentIndex()).toString();
679 QString const idxopt = latexIndexED->text();
681 rc.index_command = fromqstr(idxopt);
682 else if (idxopt.isEmpty())
683 rc.index_command = fromqstr(index);
685 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
687 rc.chktex_command = fromqstr(latexChecktexED->text());
688 rc.jindex_command = fromqstr(latexJIndexED->text());
689 rc.nomencl_command = fromqstr(latexNomenclED->text());
690 rc.auto_reset_options = latexAutoresetCB->isChecked();
691 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
692 #if defined(__CYGWIN__) || defined(_WIN32)
693 rc.windows_style_tex_paths = pathCB->isChecked();
698 void PrefLatex::updateRC(LyXRC const & rc)
700 latexBibtexCO->clear();
702 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
703 latexBibtexCO->addItem(qt_("Custom"), QString());
704 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
705 it != rc.bibtex_alternatives.end(); ++it) {
706 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
707 latexBibtexCO->addItem(command, command);
710 bibtex_alternatives = rc.bibtex_alternatives;
712 QString const bib = toqstr(rc.bibtex_command);
713 int ind = bib.indexOf(" ");
714 QString sel_command = bib.left(ind);
715 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
717 int pos = latexBibtexCO->findData(sel_command);
719 latexBibtexCO->setCurrentIndex(pos);
720 latexBibtexED->setText(sel_options.trimmed());
721 latexBibtexOptionsLA->setText(qt_("&Options:"));
723 latexBibtexED->setText(toqstr(rc.bibtex_command));
724 latexBibtexCO->setCurrentIndex(0);
725 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
728 latexJBibtexCO->clear();
730 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
731 latexJBibtexCO->addItem(qt_("Custom"), QString());
732 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
733 it != rc.jbibtex_alternatives.end(); ++it) {
734 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
735 latexJBibtexCO->addItem(command, command);
738 jbibtex_alternatives = rc.jbibtex_alternatives;
740 QString const jbib = toqstr(rc.jbibtex_command);
741 ind = jbib.indexOf(" ");
742 sel_command = jbib.left(ind);
743 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
745 pos = latexJBibtexCO->findData(sel_command);
747 latexJBibtexCO->setCurrentIndex(pos);
748 latexJBibtexED->setText(sel_options.trimmed());
749 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
751 latexJBibtexED->setText(toqstr(rc.bibtex_command));
752 latexJBibtexCO->setCurrentIndex(0);
753 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
756 latexIndexCO->clear();
758 latexIndexCO->addItem(qt_("Custom"), QString());
759 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
760 it != rc.index_alternatives.end(); ++it) {
761 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
762 latexIndexCO->addItem(command, command);
765 index_alternatives = rc.index_alternatives;
767 QString const idx = toqstr(rc.index_command);
768 ind = idx.indexOf(" ");
769 sel_command = idx.left(ind);
770 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
772 pos = latexIndexCO->findData(sel_command);
774 latexIndexCO->setCurrentIndex(pos);
775 latexIndexED->setText(sel_options.trimmed());
776 latexIndexOptionsLA->setText(qt_("Op&tions:"));
778 latexIndexED->setText(toqstr(rc.index_command));
779 latexIndexCO->setCurrentIndex(0);
780 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
783 latexChecktexED->setText(toqstr(rc.chktex_command));
784 latexJIndexED->setText(toqstr(rc.jindex_command));
785 latexNomenclED->setText(toqstr(rc.nomencl_command));
786 latexAutoresetCB->setChecked(rc.auto_reset_options);
787 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
788 #if defined(__CYGWIN__) || defined(_WIN32)
789 pathCB->setChecked(rc.windows_style_tex_paths);
794 /////////////////////////////////////////////////////////////////////
798 /////////////////////////////////////////////////////////////////////
800 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
801 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
805 #if QT_VERSION < 0x050e00
806 connect(screenRomanCO, SIGNAL(activated(QString)),
807 this, SLOT(selectRoman(QString)));
808 connect(screenSansCO, SIGNAL(activated(QString)),
809 this, SLOT(selectSans(QString)));
810 connect(screenTypewriterCO, SIGNAL(activated(QString)),
811 this, SLOT(selectTypewriter(QString)));
813 connect(screenRomanCO, SIGNAL(textActivated(QString)),
814 this, SLOT(selectRoman(QString)));
815 connect(screenSansCO, SIGNAL(textActivated(QString)),
816 this, SLOT(selectSans(QString)));
817 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
818 this, SLOT(selectTypewriter(QString)));
821 #if QT_VERSION >= 0x060000
822 const QStringList families(QFontDatabase::families());
824 QFontDatabase fontdb;
825 const QStringList families(fontdb.families());
827 for (auto const & family : families) {
828 screenRomanCO->addItem(family);
829 screenSansCO->addItem(family);
830 screenTypewriterCO->addItem(family);
832 #if QT_VERSION < 0x050e00
833 connect(screenRomanCO, SIGNAL(activated(QString)),
834 this, SIGNAL(changed()));
835 connect(screenSansCO, SIGNAL(activated(QString)),
836 this, SIGNAL(changed()));
837 connect(screenTypewriterCO, SIGNAL(activated(QString)),
838 this, SIGNAL(changed()));
840 connect(screenRomanCO, SIGNAL(textActivated(QString)),
841 this, SIGNAL(changed()));
842 connect(screenSansCO, SIGNAL(textActivated(QString)),
843 this, SIGNAL(changed()));
844 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
845 this, SIGNAL(changed()));
847 connect(screenZoomSB, SIGNAL(valueChanged(int)),
848 this, SIGNAL(changed()));
849 connect(screenTinyED, SIGNAL(textChanged(QString)),
850 this, SIGNAL(changed()));
851 connect(screenSmallestED, SIGNAL(textChanged(QString)),
852 this, SIGNAL(changed()));
853 connect(screenSmallerED, SIGNAL(textChanged(QString)),
854 this, SIGNAL(changed()));
855 connect(screenSmallED, SIGNAL(textChanged(QString)),
856 this, SIGNAL(changed()));
857 connect(screenNormalED, SIGNAL(textChanged(QString)),
858 this, SIGNAL(changed()));
859 connect(screenLargeED, SIGNAL(textChanged(QString)),
860 this, SIGNAL(changed()));
861 connect(screenLargerED, SIGNAL(textChanged(QString)),
862 this, SIGNAL(changed()));
863 connect(screenLargestED, SIGNAL(textChanged(QString)),
864 this, SIGNAL(changed()));
865 connect(screenHugeED, SIGNAL(textChanged(QString)),
866 this, SIGNAL(changed()));
867 connect(screenHugerED, SIGNAL(textChanged(QString)),
868 this, SIGNAL(changed()));
870 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
871 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
872 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
873 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
874 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
875 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
876 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
877 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
878 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
879 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
883 void PrefScreenFonts::applyRC(LyXRC & rc) const
885 LyXRC const oldrc = rc;
887 parseFontName(screenRomanCO->currentText(),
888 rc.roman_font_name, rc.roman_font_foundry);
889 parseFontName(screenSansCO->currentText(),
890 rc.sans_font_name, rc.sans_font_foundry);
891 parseFontName(screenTypewriterCO->currentText(),
892 rc.typewriter_font_name, rc.typewriter_font_foundry);
894 rc.defaultZoom = screenZoomSB->value();
895 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
896 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
897 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
898 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
899 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
900 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
901 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
902 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
903 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
904 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
908 void PrefScreenFonts::updateRC(LyXRC const & rc)
910 setComboxFont(screenRomanCO, rc.roman_font_name,
911 rc.roman_font_foundry);
912 setComboxFont(screenSansCO, rc.sans_font_name,
913 rc.sans_font_foundry);
914 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
915 rc.typewriter_font_foundry);
917 selectRoman(screenRomanCO->currentText());
918 selectSans(screenSansCO->currentText());
919 selectTypewriter(screenTypewriterCO->currentText());
921 screenZoomSB->setValue(rc.defaultZoom);
922 updateScreenFontSizes(rc);
926 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
928 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
929 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
930 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
931 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
932 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
933 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
934 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
935 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
936 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
937 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
941 void PrefScreenFonts::selectRoman(const QString & name)
943 screenRomanFE->set(QFont(name), name);
944 screenFontsChanged();
948 void PrefScreenFonts::selectSans(const QString & name)
950 screenSansFE->set(QFont(name), name);
951 screenFontsChanged();
955 void PrefScreenFonts::selectTypewriter(const QString & name)
957 screenTypewriterFE->set(QFont(name), name);
958 screenFontsChanged();
962 void PrefScreenFonts::screenFontsChanged()
964 int w = max(screenRomanFE->minWidth(), screenSansFE->minWidth());
965 w = max(screenTypewriterFE->minWidth(), w);
966 screenRomanFE->setFixedWidth(w);
967 screenSansFE->setFixedWidth(w);
968 screenTypewriterFE->setFixedWidth(w);
972 /////////////////////////////////////////////////////////////////////
976 /////////////////////////////////////////////////////////////////////
979 PrefColors::PrefColors(GuiPreferences * form)
980 : PrefModule(catLookAndFeel, N_("Colors"), form)
984 // FIXME: all of this initialization should be put into the controller.
985 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
986 // for some discussion of why that is not trivial.
987 QPixmap icon(32, 32);
988 for (int i = 0; i < Color_ignore; ++i) {
989 ColorCode lc = static_cast<ColorCode>(i);
996 || lc == Color_darkgray
999 || lc == Color_lightgray
1001 || lc == Color_magenta
1002 || lc == Color_olive
1003 || lc == Color_orange
1005 || lc == Color_purple
1008 || lc == Color_violet
1009 || lc == Color_yellow
1010 || lc == Color_inherit
1011 || lc == Color_ignore)
1013 lcolors_.push_back(lc);
1015 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1016 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1017 vector<ColorCode>::const_iterator const end = lcolors_.end();
1018 for (; cit != end; ++cit) {
1019 (void) new QListWidgetItem(QIcon(icon),
1020 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1022 curcolors_.resize(lcolors_.size());
1023 newcolors_.resize(lcolors_.size());
1024 // End initialization
1026 connect(colorChangePB, SIGNAL(clicked()),
1027 this, SLOT(changeColor()));
1028 connect(colorResetPB, SIGNAL(clicked()),
1029 this, SLOT(resetColor()));
1030 connect(colorResetAllPB, SIGNAL(clicked()),
1031 this, SLOT(resetAllColor()));
1032 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1033 this, SLOT(changeLyxObjectsSelection()));
1034 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1035 this, SLOT(changeColor()));
1036 connect(syscolorsCB, SIGNAL(toggled(bool)),
1037 this, SIGNAL(changed()));
1038 connect(syscolorsCB, SIGNAL(toggled(bool)),
1039 this, SLOT(changeSysColor()));
1043 void PrefColors::applyRC(LyXRC & rc) const
1047 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1048 if (curcolors_[i] != newcolors_[i])
1049 form_->setColor(lcolors_[i], newcolors_[i]);
1050 rc.use_system_colors = syscolorsCB->isChecked();
1052 if (oldrc.use_system_colors != rc.use_system_colors)
1053 guiApp->colorCache().clear();
1057 void PrefColors::updateRC(LyXRC const & rc)
1059 for (size_type i = 0; i < lcolors_.size(); ++i) {
1060 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1061 QPixmap coloritem(32, 32);
1062 coloritem.fill(color);
1063 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1064 newcolors_[i] = curcolors_[i] = color.name();
1066 syscolorsCB->setChecked(rc.use_system_colors);
1067 changeLyxObjectsSelection();
1069 setDisabledResets();
1073 void PrefColors::changeColor()
1075 int const row = lyxObjectsLW->currentRow();
1081 QString const color = newcolors_[size_t(row)];
1082 QColor const c = form_->getColor(QColor(color));
1084 if (setColor(row, c, color)) {
1085 setDisabledResets();
1092 void PrefColors::resetColor()
1094 int const row = lyxObjectsLW->currentRow();
1100 QString const color = newcolors_[size_t(row)];
1101 QColor const c = getDefaultColorByRow(row);
1103 if (setColor(row, c, color)) {
1104 setDisabledResets();
1111 void PrefColors::resetAllColor()
1113 bool isChanged = false;
1115 colorResetAllPB->setDisabled(true);
1117 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1118 QString const color = newcolors_[size_t(irow)];
1119 QColor const c = getDefaultColorByRow(irow);
1121 if (setColor(irow, c, color))
1126 setDisabledResets();
1133 bool PrefColors::setColor(int const row, QColor const & new_color,
1134 QString const & old_color)
1136 if (new_color.isValid() && new_color.name() != old_color) {
1137 newcolors_[size_t(row)] = new_color.name();
1138 QPixmap coloritem(32, 32);
1139 coloritem.fill(new_color);
1140 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1147 void PrefColors::setDisabledResets()
1149 int const row = lyxObjectsLW->currentRow();
1150 // set disable reset buttons ...
1152 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1154 colorResetAllPB->setDisabled(true);
1156 // ... in between process qt events to give quicker visual feedback to the user ...
1157 guiApp->processEvents();
1159 // ... set disable Reset All button
1160 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1161 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1162 colorResetAllPB->setDisabled(false);
1163 // the break condition might hide performance issues
1164 // if a non-default color is at the top of the list
1171 bool PrefColors::isDefaultColor(int const row, QString const & color)
1173 return color == getDefaultColorByRow(row).name();
1177 QColor PrefColors::getDefaultColorByRow(int const row)
1179 ColorSet const defaultcolor;
1180 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1181 guiApp->colorCache().isDarkMode()).c_str();
1185 void PrefColors::changeSysColor()
1187 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1188 // skip colors that are taken from system palette
1189 bool const disable = syscolorsCB->isChecked()
1190 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1192 QListWidgetItem * const item = lyxObjectsLW->item(row);
1193 Qt::ItemFlags const flags = item->flags();
1196 item->setFlags(flags & ~Qt::ItemIsEnabled);
1198 item->setFlags(flags | Qt::ItemIsEnabled);
1203 void PrefColors::changeLyxObjectsSelection()
1205 int currentRow = lyxObjectsLW->currentRow();
1206 colorChangePB->setDisabled(currentRow < 0);
1209 colorResetPB->setDisabled(true);
1211 colorResetPB->setDisabled(
1212 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1216 /////////////////////////////////////////////////////////////////////
1220 /////////////////////////////////////////////////////////////////////
1222 PrefDisplay::PrefDisplay(GuiPreferences * form)
1223 : PrefModule(catLookAndFeel, N_("Display"), form)
1226 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1227 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1228 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1229 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1230 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1234 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1236 previewSizeSB->setEnabled(index != 0);
1240 void PrefDisplay::applyRC(LyXRC & rc) const
1242 switch (instantPreviewCO->currentIndex()) {
1244 rc.preview = LyXRC::PREVIEW_OFF;
1247 rc.preview = LyXRC::PREVIEW_NO_MATH;
1250 rc.preview = LyXRC::PREVIEW_ON;
1254 rc.display_graphics = displayGraphicsCB->isChecked();
1255 rc.preview_scale_factor = previewSizeSB->value();
1256 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1257 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1259 // FIXME!! The graphics cache no longer has a changeDisplay method.
1261 if (old_value != rc.display_graphics) {
1262 graphics::GCache & gc = graphics::GCache::get();
1269 void PrefDisplay::updateRC(LyXRC const & rc)
1271 switch (rc.preview) {
1272 case LyXRC::PREVIEW_OFF:
1273 instantPreviewCO->setCurrentIndex(0);
1275 case LyXRC::PREVIEW_NO_MATH :
1276 instantPreviewCO->setCurrentIndex(1);
1278 case LyXRC::PREVIEW_ON :
1279 instantPreviewCO->setCurrentIndex(2);
1283 displayGraphicsCB->setChecked(rc.display_graphics);
1284 previewSizeSB->setValue(rc.preview_scale_factor);
1285 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1286 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1287 previewSizeSB->setEnabled(
1289 && rc.preview != LyXRC::PREVIEW_OFF);
1293 /////////////////////////////////////////////////////////////////////
1297 /////////////////////////////////////////////////////////////////////
1299 PrefPaths::PrefPaths(GuiPreferences * form)
1300 : PrefModule(QString(), N_("Paths"), form)
1304 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1305 connect(workingDirED, SIGNAL(textChanged(QString)),
1306 this, SIGNAL(changed()));
1308 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1309 connect(templateDirED, SIGNAL(textChanged(QString)),
1310 this, SIGNAL(changed()));
1312 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1313 connect(exampleDirED, SIGNAL(textChanged(QString)),
1314 this, SIGNAL(changed()));
1316 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1317 connect(backupDirED, SIGNAL(textChanged(QString)),
1318 this, SIGNAL(changed()));
1320 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1321 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1322 this, SIGNAL(changed()));
1324 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1325 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1326 this, SIGNAL(changed()));
1328 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1329 connect(tempDirED, SIGNAL(textChanged(QString)),
1330 this, SIGNAL(changed()));
1332 #if defined(USE_HUNSPELL)
1333 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1334 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1335 this, SIGNAL(changed()));
1337 hunspellDirPB->setEnabled(false);
1338 hunspellDirED->setEnabled(false);
1341 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1342 this, SIGNAL(changed()));
1344 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1345 this, SIGNAL(changed()));
1347 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1348 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1352 void PrefPaths::applyRC(LyXRC & rc) const
1354 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1355 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1356 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1357 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1358 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1359 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1360 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1361 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1362 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1363 // FIXME: should be a checkbox only
1364 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1368 void PrefPaths::updateRC(LyXRC const & rc)
1370 workingDirED->setText(toqstr(external_path(rc.document_path)));
1371 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1372 templateDirED->setText(toqstr(external_path(rc.template_path)));
1373 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1374 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1375 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1376 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1377 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1378 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1379 // FIXME: should be a checkbox only
1380 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1384 void PrefPaths::selectExampledir()
1386 QString file = form_->browseDir(internalPath(exampleDirED->text()),
1387 qt_("Select directory for example files"));
1388 if (!file.isEmpty())
1389 exampleDirED->setText(file);
1393 void PrefPaths::selectTemplatedir()
1395 QString file = form_->browseDir(internalPath(templateDirED->text()),
1396 qt_("Select a document templates directory"));
1397 if (!file.isEmpty())
1398 templateDirED->setText(file);
1402 void PrefPaths::selectTempdir()
1404 QString file = form_->browseDir(internalPath(tempDirED->text()),
1405 qt_("Select a temporary directory"));
1406 if (!file.isEmpty())
1407 tempDirED->setText(file);
1411 void PrefPaths::selectBackupdir()
1413 QString file = form_->browseDir(internalPath(backupDirED->text()),
1414 qt_("Select a backups directory"));
1415 if (!file.isEmpty())
1416 backupDirED->setText(file);
1420 void PrefPaths::selectWorkingdir()
1422 QString file = form_->browseDir(internalPath(workingDirED->text()),
1423 qt_("Select a document directory"));
1424 if (!file.isEmpty())
1425 workingDirED->setText(file);
1429 void PrefPaths::selectThesaurusdir()
1431 QString file = form_->browseDir(internalPath(thesaurusDirED->text()),
1432 qt_("Set the path to the thesaurus dictionaries"));
1433 if (!file.isEmpty())
1434 thesaurusDirED->setText(file);
1438 void PrefPaths::selectHunspelldir()
1440 QString file = form_->browseDir(internalPath(hunspellDirED->text()),
1441 qt_("Set the path to the Hunspell dictionaries"));
1442 if (!file.isEmpty())
1443 hunspellDirED->setText(file);
1447 void PrefPaths::selectLyxPipe()
1449 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1450 qt_("Give a filename for the LyX server pipe"));
1451 if (!file.isEmpty())
1452 lyxserverDirED->setText(file);
1456 /////////////////////////////////////////////////////////////////////
1460 /////////////////////////////////////////////////////////////////////
1462 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1463 : PrefModule(catLanguage, N_("Spellchecker"), form)
1467 // FIXME: this check should test the target platform (darwin)
1468 #if defined(USE_MACOSX_PACKAGING)
1469 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1470 #define CONNECT_APPLESPELL
1472 #undef CONNECT_APPLESPELL
1474 #if defined(USE_ASPELL)
1475 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1477 #if defined(USE_ENCHANT)
1478 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1480 #if defined(USE_HUNSPELL)
1481 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1484 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1485 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1486 this, SIGNAL(changed()));
1487 connect(altLanguageED, SIGNAL(textChanged(QString)),
1488 this, SIGNAL(changed()));
1489 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1490 this, SIGNAL(changed()));
1491 connect(compoundWordCB, SIGNAL(clicked()),
1492 this, SIGNAL(changed()));
1493 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1494 this, SIGNAL(changed()));
1495 connect(spellcheckNotesCB, SIGNAL(clicked()),
1496 this, SIGNAL(changed()));
1498 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1499 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1501 spellcheckerCB->setEnabled(false);
1502 altLanguageED->setEnabled(false);
1503 escapeCharactersED->setEnabled(false);
1504 compoundWordCB->setEnabled(false);
1505 spellcheckContinuouslyCB->setEnabled(false);
1506 spellcheckNotesCB->setEnabled(false);
1511 void PrefSpellchecker::applyRC(LyXRC & rc) const
1513 string const speller = fromqstr(spellcheckerCB->
1514 itemData(spellcheckerCB->currentIndex()).toString());
1515 if (!speller.empty())
1516 rc.spellchecker = speller;
1517 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1518 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1519 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1520 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1521 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1525 void PrefSpellchecker::updateRC(LyXRC const & rc)
1527 spellcheckerCB->setCurrentIndex(
1528 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1529 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1530 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1531 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1532 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1533 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1537 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1539 QString spellchecker = spellcheckerCB->itemData(index).toString();
1541 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1546 /////////////////////////////////////////////////////////////////////
1550 /////////////////////////////////////////////////////////////////////
1553 PrefConverters::PrefConverters(GuiPreferences * form)
1554 : PrefModule(catFiles, N_("Converters"), form)
1558 connect(converterNewPB, SIGNAL(clicked()),
1559 this, SLOT(updateConverter()));
1560 connect(converterRemovePB, SIGNAL(clicked()),
1561 this, SLOT(removeConverter()));
1562 connect(converterModifyPB, SIGNAL(clicked()),
1563 this, SLOT(updateConverter()));
1564 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1565 this, SLOT(switchConverter()));
1566 #if QT_VERSION < 0x050e00
1567 connect(converterFromCO, SIGNAL(activated(QString)),
1568 this, SLOT(changeConverter()));
1569 connect(converterToCO, SIGNAL(activated(QString)),
1570 this, SLOT(changeConverter()));
1572 connect(converterFromCO, SIGNAL(textActivated(QString)),
1573 this, SLOT(changeConverter()));
1574 connect(converterToCO, SIGNAL(textActivated(QString)),
1575 this, SLOT(changeConverter()));
1577 connect(converterED, SIGNAL(textEdited(QString)),
1578 this, SLOT(changeConverter()));
1579 connect(converterFlagED, SIGNAL(textEdited(QString)),
1580 this, SLOT(changeConverter()));
1581 connect(converterNewPB, SIGNAL(clicked()),
1582 this, SIGNAL(changed()));
1583 connect(converterRemovePB, SIGNAL(clicked()),
1584 this, SIGNAL(changed()));
1585 connect(converterModifyPB, SIGNAL(clicked()),
1586 this, SIGNAL(changed()));
1587 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1588 this, SIGNAL(changed()));
1589 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1590 this, SIGNAL(changed()));
1592 converterED->setValidator(new NoNewLineValidator(converterED));
1593 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1594 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1595 //converterDefGB->setFocusProxy(convertersLW);
1599 void PrefConverters::applyRC(LyXRC & rc) const
1601 rc.use_converter_cache = cacheCB->isChecked();
1602 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1603 rc.use_converter_needauth = needauthCB->isChecked();
1604 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1608 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1609 cb->blockSignals(true);
1610 cb->setChecked(checked);
1611 cb->blockSignals(false);
1615 void PrefConverters::updateRC(LyXRC const & rc)
1617 cacheCB->setChecked(rc.use_converter_cache);
1618 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1619 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1621 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1626 void PrefConverters::updateGui()
1628 QString const pattern("%1 -> %2");
1629 form_->formats().sort();
1630 form_->converters().update(form_->formats());
1631 // save current selection
1634 .arg(converterFromCO->currentText())
1635 .arg(converterToCO->currentText());
1637 converterFromCO->clear();
1638 converterToCO->clear();
1640 for (Format const & f : form_->formats()) {
1641 QString const name = toqstr(translateIfPossible(f.prettyname()));
1642 converterFromCO->addItem(name);
1643 converterToCO->addItem(name);
1646 // currentRowChanged(int) is also triggered when updating the listwidget
1647 // block signals to avoid unnecessary calls to switchConverter()
1648 convertersLW->blockSignals(true);
1649 convertersLW->clear();
1651 for (Converter const & c : form_->converters()) {
1652 QString const name =
1654 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1655 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1656 int type = form_->converters().getNumber(c.From()->name(),
1658 new QListWidgetItem(name, convertersLW, type);
1660 convertersLW->sortItems(Qt::AscendingOrder);
1661 convertersLW->blockSignals(false);
1663 // restore selection
1664 if (current != pattern.arg(QString()).arg(QString())) {
1665 QList<QListWidgetItem *> const item =
1666 convertersLW->findItems(current, Qt::MatchExactly);
1667 if (!item.isEmpty())
1668 convertersLW->setCurrentItem(item.at(0));
1671 // select first element if restoring failed
1672 if (convertersLW->currentRow() == -1)
1673 convertersLW->setCurrentRow(0);
1679 void PrefConverters::switchConverter()
1681 int const cnr = convertersLW->currentItem()->type();
1682 Converter const & c(form_->converters().get(cnr));
1683 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1684 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1685 converterED->setText(toqstr(c.command()));
1686 converterFlagED->setText(toqstr(c.flags()));
1692 void PrefConverters::changeConverter()
1698 void PrefConverters::updateButtons()
1700 if (form_->formats().empty())
1702 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1703 Format const & to = form_->formats().get(converterToCO->currentIndex());
1704 int const sel = form_->converters().getNumber(from.name(), to.name());
1705 bool const known = sel >= 0;
1706 bool const valid = !(converterED->text().isEmpty()
1707 || from.name() == to.name());
1712 if (convertersLW->count() > 0) {
1713 int const cnr = convertersLW->currentItem()->type();
1714 Converter const & c = form_->converters().get(cnr);
1715 old_command = c.command();
1716 old_flag = c.flags();
1719 string const new_command = fromqstr(converterED->text());
1720 string const new_flag = fromqstr(converterFlagED->text());
1722 bool modified = (old_command != new_command || old_flag != new_flag);
1724 converterModifyPB->setEnabled(valid && known && modified);
1725 converterNewPB->setEnabled(valid && !known);
1726 converterRemovePB->setEnabled(known);
1728 maxAgeLE->setEnabled(cacheCB->isChecked());
1729 maxAgeLA->setEnabled(cacheCB->isChecked());
1734 // specify unique from/to or it doesn't appear. This is really bad UI
1735 // this is why we can use the same function for both new and modify
1736 void PrefConverters::updateConverter()
1738 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1739 Format const & to = form_->formats().get(converterToCO->currentIndex());
1740 string const flags = fromqstr(converterFlagED->text());
1741 string const command = fromqstr(converterED->text());
1743 Converter const * old =
1744 form_->converters().getConverter(from.name(), to.name());
1745 form_->converters().add(from.name(), to.name(), command, flags);
1748 form_->converters().updateLast(form_->formats());
1752 // Remove all files created by this converter from the cache, since
1753 // the modified converter might create different files.
1754 ConverterCache::get().remove_all(from.name(), to.name());
1758 void PrefConverters::removeConverter()
1760 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1761 Format const & to = form_->formats().get(converterToCO->currentIndex());
1762 form_->converters().erase(from.name(), to.name());
1766 // Remove all files created by this converter from the cache, since
1767 // a possible new converter might create different files.
1768 ConverterCache::get().remove_all(from.name(), to.name());
1772 void PrefConverters::on_cacheCB_stateChanged(int state)
1774 maxAgeLE->setEnabled(state == Qt::Checked);
1775 maxAgeLA->setEnabled(state == Qt::Checked);
1780 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1782 needauthCB->setEnabled(!checked);
1786 void PrefConverters::on_needauthCB_toggled(bool checked)
1793 int ret = frontend::Alert::prompt(
1794 _("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!"),
1795 0, 0, _("&No"), _("&Yes"));
1796 activatePrefsWindow(form_);
1800 setCheckboxBlockSignals(needauthCB, true);
1804 /////////////////////////////////////////////////////////////////////
1808 /////////////////////////////////////////////////////////////////////
1810 class FormatValidator : public QValidator
1813 FormatValidator(QWidget *, Formats const & f);
1814 void fixup(QString & input) const override;
1815 QValidator::State validate(QString & input, int & pos) const override;
1817 virtual QString toString(Format const & format) const = 0;
1819 Formats const & formats_;
1823 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1824 : QValidator(parent), formats_(f)
1829 void FormatValidator::fixup(QString & input) const
1831 Formats::const_iterator cit = formats_.begin();
1832 Formats::const_iterator end = formats_.end();
1833 for (; cit != end; ++cit) {
1834 QString const name = toString(*cit);
1835 if (distance(formats_.begin(), cit) == nr()) {
1843 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1845 Formats::const_iterator cit = formats_.begin();
1846 Formats::const_iterator end = formats_.end();
1847 bool unknown = true;
1848 for (; unknown && cit != end; ++cit) {
1849 QString const name = toString(*cit);
1850 if (distance(formats_.begin(), cit) != nr())
1851 unknown = name != input;
1854 if (unknown && !input.isEmpty())
1855 return QValidator::Acceptable;
1857 return QValidator::Intermediate;
1861 int FormatValidator::nr() const
1863 QComboBox * p = qobject_cast<QComboBox *>(parent());
1864 return p->itemData(p->currentIndex()).toInt();
1868 /////////////////////////////////////////////////////////////////////
1870 // FormatNameValidator
1872 /////////////////////////////////////////////////////////////////////
1874 class FormatNameValidator : public FormatValidator
1877 FormatNameValidator(QWidget * parent, Formats const & f)
1878 : FormatValidator(parent, f)
1881 QString toString(Format const & format) const override
1883 return toqstr(format.name());
1888 /////////////////////////////////////////////////////////////////////
1890 // FormatPrettynameValidator
1892 /////////////////////////////////////////////////////////////////////
1894 class FormatPrettynameValidator : public FormatValidator
1897 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1898 : FormatValidator(parent, f)
1901 QString toString(Format const & format) const override
1903 return toqstr(translateIfPossible(format.prettyname()));
1908 /////////////////////////////////////////////////////////////////////
1912 /////////////////////////////////////////////////////////////////////
1914 PrefFileformats::PrefFileformats(GuiPreferences * form)
1915 : PrefModule(catFiles, N_("File Formats"), form)
1919 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
1920 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
1921 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
1922 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
1923 editorED->setValidator(new NoNewLineValidator(editorED));
1924 viewerED->setValidator(new NoNewLineValidator(viewerED));
1925 copierED->setValidator(new NoNewLineValidator(copierED));
1927 connect(documentCB, SIGNAL(clicked()),
1928 this, SLOT(setFlags()));
1929 connect(vectorCB, SIGNAL(clicked()),
1930 this, SLOT(setFlags()));
1931 connect(exportMenuCB, SIGNAL(clicked()),
1932 this, SLOT(setFlags()));
1933 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
1934 this, SLOT(updatePrettyname()));
1935 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
1936 this, SIGNAL(changed()));
1937 #if QT_VERSION < 0x050e00
1938 connect(defaultFormatCB, SIGNAL(activated(QString)),
1939 this, SIGNAL(changed()));
1940 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
1941 this, SIGNAL(changed()));
1942 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
1943 this, SIGNAL(changed()));
1945 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
1946 this, SIGNAL(changed()));
1947 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
1948 this, SIGNAL(changed()));
1949 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
1950 this, SIGNAL(changed()));
1952 connect(viewerCO, SIGNAL(activated(int)),
1953 this, SIGNAL(changed()));
1954 connect(editorCO, SIGNAL(activated(int)),
1955 this, SIGNAL(changed()));
1961 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
1963 if (shortcut.empty())
1966 string l10n_format =
1967 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
1968 return split(l10n_format, '|');
1974 void PrefFileformats::applyRC(LyXRC & rc) const
1976 QString const default_format = defaultFormatCB->itemData(
1977 defaultFormatCB->currentIndex()).toString();
1978 rc.default_view_format = fromqstr(default_format);
1979 QString const default_otf_format = defaultOTFFormatCB->itemData(
1980 defaultOTFFormatCB->currentIndex()).toString();
1981 rc.default_otf_view_format = fromqstr(default_otf_format);
1982 QString const default_platex_format = defaultPlatexFormatCB->itemData(
1983 defaultPlatexFormatCB->currentIndex()).toString();
1984 rc.default_platex_view_format = fromqstr(default_platex_format);
1988 void PrefFileformats::updateRC(LyXRC const & rc)
1990 viewer_alternatives = rc.viewer_alternatives;
1991 editor_alternatives = rc.editor_alternatives;
1992 bool const init = defaultFormatCB->currentText().isEmpty();
1996 defaultFormatCB->findData(toqstr(rc.default_view_format));
1997 defaultFormatCB->setCurrentIndex(pos);
1998 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
1999 defaultOTFFormatCB->setCurrentIndex(pos);
2000 defaultOTFFormatCB->setCurrentIndex(pos);
2001 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2002 defaultPlatexFormatCB->setCurrentIndex(pos);
2003 defaultPlatexFormatCB->setCurrentIndex(pos);
2008 void PrefFileformats::updateView()
2010 QString const current = formatsCB->currentText();
2011 QString const current_def = defaultFormatCB->currentText();
2012 QString const current_def_otf = defaultOTFFormatCB->currentText();
2013 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2015 // update comboboxes with formats
2016 formatsCB->blockSignals(true);
2017 defaultFormatCB->blockSignals(true);
2018 defaultOTFFormatCB->blockSignals(true);
2019 defaultPlatexFormatCB->blockSignals(true);
2021 defaultFormatCB->clear();
2022 defaultOTFFormatCB->clear();
2023 defaultPlatexFormatCB->clear();
2024 form_->formats().sort();
2025 for (Format const & f : form_->formats()) {
2026 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2027 formatsCB->addItem(prettyname,
2028 QVariant(form_->formats().getNumber(f.name())));
2029 if (f.viewer().empty())
2031 if (form_->converters().isReachable("xhtml", f.name())
2032 || form_->converters().isReachable("dviluatex", f.name())
2033 || form_->converters().isReachable("luatex", f.name())
2034 || form_->converters().isReachable("xetex", f.name())) {
2035 defaultFormatCB->addItem(prettyname,
2036 QVariant(toqstr(f.name())));
2037 defaultOTFFormatCB->addItem(prettyname,
2038 QVariant(toqstr(f.name())));
2040 if (form_->converters().isReachable("latex", f.name())
2041 || form_->converters().isReachable("pdflatex", f.name()))
2042 defaultFormatCB->addItem(prettyname,
2043 QVariant(toqstr(f.name())));
2044 if (form_->converters().isReachable("platex", f.name()))
2045 defaultPlatexFormatCB->addItem(prettyname,
2046 QVariant(toqstr(f.name())));
2050 // restore selections
2051 int item = formatsCB->findText(current, Qt::MatchExactly);
2052 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2053 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2054 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2055 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2056 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2057 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2058 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2059 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2060 formatsCB->blockSignals(false);
2061 defaultFormatCB->blockSignals(false);
2062 defaultOTFFormatCB->blockSignals(false);
2063 defaultPlatexFormatCB->blockSignals(false);
2067 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2069 if (form_->formats().empty())
2071 int const nr = formatsCB->itemData(i).toInt();
2072 Format const f = form_->formats().get(nr);
2074 formatED->setText(toqstr(f.name()));
2075 copierED->setText(toqstr(form_->movers().command(f.name())));
2076 extensionsED->setText(toqstr(f.extensions()));
2077 mimeED->setText(toqstr(f.mime()));
2078 shortcutED->setText(
2079 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2080 documentCB->setChecked((f.documentFormat()));
2081 vectorCB->setChecked((f.vectorFormat()));
2082 exportMenuCB->setChecked((f.inExportMenu()));
2083 exportMenuCB->setEnabled((f.documentFormat()));
2089 void PrefFileformats::setFlags()
2091 int flags = Format::none;
2092 if (documentCB->isChecked())
2093 flags |= Format::document;
2094 if (vectorCB->isChecked())
2095 flags |= Format::vector;
2096 if (exportMenuCB->isChecked())
2097 flags |= Format::export_menu;
2098 currentFormat().setFlags(flags);
2099 exportMenuCB->setEnabled(documentCB->isChecked());
2104 void PrefFileformats::on_copierED_textEdited(const QString & s)
2106 string const fmt = fromqstr(formatED->text());
2107 form_->movers().set(fmt, fromqstr(s));
2112 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2114 currentFormat().setExtensions(fromqstr(s));
2119 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2121 currentFormat().setViewer(fromqstr(s));
2126 void PrefFileformats::on_editorED_textEdited(const QString & s)
2128 currentFormat().setEditor(fromqstr(s));
2133 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2135 currentFormat().setMime(fromqstr(s));
2140 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2142 string const new_shortcut = fromqstr(s);
2143 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2144 currentFormat().shortcut()))
2146 currentFormat().setShortcut(new_shortcut);
2151 void PrefFileformats::on_formatED_editingFinished()
2153 string const newname = fromqstr(formatED->displayText());
2154 string const oldname = currentFormat().name();
2155 if (newname == oldname)
2157 if (form_->converters().formatIsUsed(oldname)) {
2158 Alert::error(_("Format in use"),
2159 _("You cannot change a format's short name "
2160 "if the format is used by a converter. "
2161 "Please remove the converter first."));
2162 activatePrefsWindow(form_);
2167 currentFormat().setName(newname);
2172 void PrefFileformats::on_formatED_textChanged(const QString &)
2174 QString t = formatED->text();
2176 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2177 setValid(formatLA, valid);
2181 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2183 QString t = formatsCB->currentText();
2185 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2186 setValid(formatsLA, valid);
2190 void PrefFileformats::updatePrettyname()
2192 QString const newname = formatsCB->currentText();
2193 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2196 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2204 void updateComboBox(LyXRC::Alternatives const & alts,
2205 string const & fmt, QComboBox * combo)
2207 LyXRC::Alternatives::const_iterator it =
2209 if (it != alts.end()) {
2210 LyXRC::CommandSet const & cmds = it->second;
2211 LyXRC::CommandSet::const_iterator sit =
2213 LyXRC::CommandSet::const_iterator const sen =
2215 for (; sit != sen; ++sit) {
2216 QString const qcmd = toqstr(*sit);
2217 combo->addItem(qcmd, qcmd);
2224 void PrefFileformats::updateViewers()
2226 Format const f = currentFormat();
2227 viewerCO->blockSignals(true);
2229 viewerCO->addItem(qt_("None"), QString());
2230 if (os::canAutoOpenFile(f.extension(), os::VIEW))
2231 viewerCO->addItem(qt_("System Default"), QString("auto"));
2232 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2233 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2234 viewerCO->blockSignals(false);
2236 int pos = viewerCO->findData(toqstr(f.viewer()));
2239 viewerED->setEnabled(false);
2240 viewerCO->setCurrentIndex(pos);
2242 viewerED->setEnabled(true);
2243 viewerED->setText(toqstr(f.viewer()));
2244 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2249 void PrefFileformats::updateEditors()
2251 Format const f = currentFormat();
2252 editorCO->blockSignals(true);
2254 editorCO->addItem(qt_("None"), QString());
2255 if (os::canAutoOpenFile(f.extension(), os::EDIT))
2256 editorCO->addItem(qt_("System Default"), QString("auto"));
2257 updateComboBox(editor_alternatives, f.name(), editorCO);
2258 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2259 editorCO->blockSignals(false);
2261 int pos = editorCO->findData(toqstr(f.editor()));
2264 editorED->setEnabled(false);
2265 editorCO->setCurrentIndex(pos);
2267 editorED->setEnabled(true);
2268 editorED->setText(toqstr(f.editor()));
2269 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2274 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2276 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2277 viewerED->setEnabled(custom);
2279 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2283 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2285 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2286 editorED->setEnabled(custom);
2288 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2292 Format & PrefFileformats::currentFormat()
2294 int const i = formatsCB->currentIndex();
2295 int const nr = formatsCB->itemData(i).toInt();
2296 return form_->formats().get(nr);
2300 void PrefFileformats::on_formatNewPB_clicked()
2302 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2304 formatsCB->setCurrentIndex(0);
2305 formatsCB->setFocus(Qt::OtherFocusReason);
2309 void PrefFileformats::on_formatRemovePB_clicked()
2311 int const i = formatsCB->currentIndex();
2312 int const nr = formatsCB->itemData(i).toInt();
2313 string const current_text = form_->formats().get(nr).name();
2314 if (form_->converters().formatIsUsed(current_text)) {
2315 Alert::error(_("Format in use"),
2316 _("Cannot remove a Format used by a Converter. "
2317 "Remove the converter first."));
2318 activatePrefsWindow(form_);
2322 form_->formats().erase(current_text);
2325 on_formatsCB_editTextChanged(formatsCB->currentText());
2330 /////////////////////////////////////////////////////////////////////
2334 /////////////////////////////////////////////////////////////////////
2336 PrefLanguage::PrefLanguage(GuiPreferences * form)
2337 : PrefModule(catLanguage, N_("Language"), form)
2341 connect(visualCursorRB, SIGNAL(clicked()),
2342 this, SIGNAL(changed()));
2343 connect(logicalCursorRB, SIGNAL(clicked()),
2344 this, SIGNAL(changed()));
2345 connect(markForeignCB, SIGNAL(clicked()),
2346 this, SIGNAL(changed()));
2347 connect(respectOSkbdCB, SIGNAL(clicked()),
2348 this, SIGNAL(changed()));
2349 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2350 this, SIGNAL(changed()));
2351 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2352 this, SIGNAL(changed()));
2353 connect(languagePackageCO, SIGNAL(activated(int)),
2354 this, SIGNAL(changed()));
2355 connect(languagePackageED, SIGNAL(textChanged(QString)),
2356 this, SIGNAL(changed()));
2357 connect(globalCB, SIGNAL(clicked()),
2358 this, SIGNAL(changed()));
2359 connect(startCommandED, SIGNAL(textChanged(QString)),
2360 this, SIGNAL(changed()));
2361 connect(endCommandED, SIGNAL(textChanged(QString)),
2362 this, SIGNAL(changed()));
2363 connect(uiLanguageCO, SIGNAL(activated(int)),
2364 this, SIGNAL(changed()));
2365 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2366 this, SIGNAL(changed()));
2367 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2368 this, SIGNAL(changed()));
2369 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2370 this, SIGNAL(changed()));
2372 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2373 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2374 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2376 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2377 defaultDecimalSepED->setMaxLength(1);
2379 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2380 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2382 QAbstractItemModel * language_model = guiApp->languageModel();
2383 language_model->sort(0);
2384 uiLanguageCO->blockSignals(true);
2385 uiLanguageCO->clear();
2386 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2387 for (int i = 0; i != language_model->rowCount(); ++i) {
2388 QModelIndex index = language_model->index(i, 0);
2389 // Filter the list based on the available translation and add
2390 // each language code only once
2391 string const name = fromqstr(index.data(Qt::UserRole).toString());
2392 Language const * lang = languages.getLanguage(name);
2395 // never remove the currently selected language
2396 if (name != form->rc().gui_language
2397 && name != lyxrc.gui_language
2398 && (!Messages::available(lang->code())
2399 || !lang->hasGuiSupport()))
2401 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2402 index.data(Qt::UserRole).toString());
2404 uiLanguageCO->blockSignals(false);
2406 // FIXME: restore this when it works (see discussion in #6450).
2407 respectOSkbdCB->hide();
2411 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2413 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2414 qt_("The change of user interface language will be fully "
2415 "effective only after a restart."));
2419 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2422 languagePackageED->setText(save_langpack_);
2423 else if (!languagePackageED->text().isEmpty()) {
2424 save_langpack_ = languagePackageED->text();
2425 languagePackageED->clear();
2427 languagePackageED->setEnabled(i == 2);
2431 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2433 defaultDecimalSepED->setEnabled(i == 1);
2437 void PrefLanguage::applyRC(LyXRC & rc) const
2439 rc.visual_cursor = visualCursorRB->isChecked();
2440 rc.mark_foreign_language = markForeignCB->isChecked();
2441 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2442 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2443 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2444 int const p = languagePackageCO->currentIndex();
2446 rc.language_package_selection = LyXRC::LP_AUTO;
2448 rc.language_package_selection = LyXRC::LP_BABEL;
2450 rc.language_package_selection = LyXRC::LP_CUSTOM;
2452 rc.language_package_selection = LyXRC::LP_NONE;
2453 rc.language_custom_package = fromqstr(languagePackageED->text());
2454 rc.language_global_options = globalCB->isChecked();
2455 rc.language_command_begin = fromqstr(startCommandED->text());
2456 rc.language_command_end = fromqstr(endCommandED->text());
2457 rc.gui_language = fromqstr(
2458 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2459 if (defaultDecimalSepCO->currentIndex() == 0)
2460 rc.default_decimal_sep = "locale";
2462 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2463 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2467 void PrefLanguage::updateRC(LyXRC const & rc)
2469 if (rc.visual_cursor)
2470 visualCursorRB->setChecked(true);
2472 logicalCursorRB->setChecked(true);
2473 markForeignCB->setChecked(rc.mark_foreign_language);
2474 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2475 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2476 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2477 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2478 if (languagePackageCO->currentIndex() == 2) {
2479 languagePackageED->setText(toqstr(rc.language_custom_package));
2480 languagePackageED->setEnabled(true);
2482 languagePackageED->clear();
2483 save_langpack_ = toqstr(rc.language_custom_package);
2484 languagePackageED->setEnabled(false);
2486 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2487 globalCB->setChecked(rc.language_global_options);
2488 startCommandED->setText(toqstr(rc.language_command_begin));
2489 endCommandED->setText(toqstr(rc.language_command_end));
2490 if (rc.default_decimal_sep == "locale") {
2491 defaultDecimalSepCO->setCurrentIndex(0);
2492 defaultDecimalSepED->clear();
2494 defaultDecimalSepCO->setCurrentIndex(1);
2495 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2497 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2498 defaultLengthUnitCO->setCurrentIndex(pos);
2500 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2501 uiLanguageCO->blockSignals(true);
2502 uiLanguageCO->setCurrentIndex(pos);
2503 uiLanguageCO->blockSignals(false);
2507 /////////////////////////////////////////////////////////////////////
2509 // PrefUserInterface
2511 /////////////////////////////////////////////////////////////////////
2513 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2514 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2518 connect(uiFilePB, SIGNAL(clicked()),
2519 this, SLOT(selectUi()));
2520 connect(uiFileED, SIGNAL(textChanged(QString)),
2521 this, SIGNAL(changed()));
2522 connect(iconSetCO, SIGNAL(activated(int)),
2523 this, SIGNAL(changed()));
2524 connect(uiStyleCO, SIGNAL(activated(int)),
2525 this, SIGNAL(changed()));
2526 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2527 this, SIGNAL(changed()));
2528 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2529 this, SIGNAL(changed()));
2530 connect(tooltipCB, SIGNAL(toggled(bool)),
2531 this, SIGNAL(changed()));
2532 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2533 this, SIGNAL(changed()));
2534 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2535 this, SIGNAL(changed()));
2536 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2537 this, SIGNAL(changed()));
2538 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2539 this, SIGNAL(changed()));
2540 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2541 this, SIGNAL(changed()));
2542 lastfilesSB->setMaximum(maxlastfiles);
2544 iconSetCO->addItem(qt_("Default"), QString());
2545 iconSetCO->addItem(qt_("Classic"), "classic");
2546 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2548 uiStyleCO->addItem(qt_("Default"), toqstr("default"));
2549 for (auto const & style : QStyleFactory::keys())
2550 uiStyleCO->addItem(style, style.toLower());
2552 if (guiApp->platformName() != "xcb"
2553 && !guiApp->platformName().contains("wayland"))
2554 useSystemThemeIconsCB->hide();
2558 void PrefUserInterface::applyRC(LyXRC & rc) const
2560 rc.icon_set = fromqstr(iconSetCO->itemData(
2561 iconSetCO->currentIndex()).toString());
2563 QString const uistyle = uiStyleCO->itemData(
2564 uiStyleCO->currentIndex()).toString();
2565 if (rc.ui_style != fromqstr(uistyle)) {
2566 rc.ui_style = fromqstr(uistyle);
2567 if (rc.ui_style == "default") {
2568 // FIXME: This should work with frontend::GuiApplication::setStyle(QString())
2569 // Qt bug https://bugreports.qt.io/browse/QTBUG-58268
2570 frontend::Alert::warning(_("Restart needed"),
2571 _("Resetting the user interface style to 'Default'"
2572 " requires a restart of LyX."));
2573 activatePrefsWindow(form_);
2576 frontend::GuiApplication::setStyle(uistyle);
2579 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2580 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2581 rc.num_lastfiles = lastfilesSB->value();
2582 rc.use_tooltip = tooltipCB->isChecked();
2583 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2584 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2585 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2586 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2587 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2591 void PrefUserInterface::updateRC(LyXRC const & rc)
2593 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2596 iconSetCO->setCurrentIndex(iconset);
2597 int uistyle = uiStyleCO->findData(toqstr(rc.ui_style));
2600 uiStyleCO->setCurrentIndex(uistyle);
2601 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2602 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2603 lastfilesSB->setValue(rc.num_lastfiles);
2604 tooltipCB->setChecked(rc.use_tooltip);
2605 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2606 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2607 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2608 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2609 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2613 void PrefUserInterface::selectUi()
2615 QString file = form_->browseUI(internalPath(uiFileED->text()));
2616 if (!file.isEmpty())
2617 uiFileED->setText(file);
2621 /////////////////////////////////////////////////////////////////////
2623 // PrefDocumentHandling
2625 /////////////////////////////////////////////////////////////////////
2627 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2628 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2632 connect(autoSaveCB, SIGNAL(toggled(bool)),
2633 autoSaveSB, SLOT(setEnabled(bool)));
2634 connect(autoSaveCB, SIGNAL(toggled(bool)),
2635 TextLabel1, SLOT(setEnabled(bool)));
2636 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2637 this, SIGNAL(changed()));
2638 connect(singleInstanceCB, SIGNAL(clicked()),
2639 this, SIGNAL(changed()));
2640 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2641 this, SIGNAL(changed()));
2642 connect(closeLastViewCO, SIGNAL(activated(int)),
2643 this, SIGNAL(changed()));
2644 connect(restoreCursorCB, SIGNAL(clicked()),
2645 this, SIGNAL(changed()));
2646 connect(loadSessionCB, SIGNAL(clicked()),
2647 this, SIGNAL(changed()));
2648 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2649 this, SIGNAL(changed()));
2650 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2651 this, SIGNAL(changed()));
2652 connect(autoSaveCB, SIGNAL(clicked()),
2653 this, SIGNAL(changed()));
2654 connect(backupCB, SIGNAL(clicked()),
2655 this, SIGNAL(changed()));
2656 connect(saveCompressedCB, SIGNAL(clicked()),
2657 this, SIGNAL(changed()));
2658 connect(saveOriginCB, SIGNAL(clicked()),
2659 this, SIGNAL(changed()));
2663 void PrefDocHandling::applyRC(LyXRC & rc) const
2665 rc.use_lastfilepos = restoreCursorCB->isChecked();
2666 rc.load_session = loadSessionCB->isChecked();
2667 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2668 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2669 rc.make_backup = backupCB->isChecked();
2670 rc.save_compressed = saveCompressedCB->isChecked();
2671 rc.save_origin = saveOriginCB->isChecked();
2672 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2673 rc.single_instance = singleInstanceCB->isChecked();
2674 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2676 switch (closeLastViewCO->currentIndex()) {
2678 rc.close_buffer_with_last_view = "yes";
2681 rc.close_buffer_with_last_view = "no";
2684 rc.close_buffer_with_last_view = "ask";
2692 void PrefDocHandling::updateRC(LyXRC const & rc)
2694 restoreCursorCB->setChecked(rc.use_lastfilepos);
2695 loadSessionCB->setChecked(rc.load_session);
2696 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2697 // convert to minutes
2698 bool autosave = rc.autosave > 0;
2699 int mins = rc.autosave / 60;
2702 autoSaveSB->setValue(mins);
2703 autoSaveCB->setChecked(autosave);
2704 autoSaveSB->setEnabled(autosave);
2705 backupCB->setChecked(rc.make_backup);
2706 saveCompressedCB->setChecked(rc.save_compressed);
2707 saveOriginCB->setChecked(rc.save_origin);
2708 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2709 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2710 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2711 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2712 if (rc.close_buffer_with_last_view == "yes")
2713 closeLastViewCO->setCurrentIndex(0);
2714 else if (rc.close_buffer_with_last_view == "no")
2715 closeLastViewCO->setCurrentIndex(1);
2716 else if (rc.close_buffer_with_last_view == "ask")
2717 closeLastViewCO->setCurrentIndex(2);
2718 if (rc.backupdir_path.empty())
2719 backupCB->setToolTip(qt_("If this is checked, a backup of the document is created "
2720 "in the current working directory. "
2721 "The backup file has the same name but the suffix '.lyx~'. "
2722 "Note that these files are hidden by default by some file managers. "
2723 "A dedicated backup directory can be set in the 'Paths' section."));
2725 docstring const tip = bformat(_("If this is checked, a backup of the document is created "
2726 "in the backup directory (%1$s). "
2727 "The backup file has the full original path and name as file name "
2728 "and the suffix \'.lyx~\' (e.g., !mydir!filename.lyx~). "
2729 "Note that these files are hidden by default by some file managers."),
2730 FileName(rc.backupdir_path).absoluteFilePath());
2731 backupCB->setToolTip(toqstr(tip));
2736 void PrefDocHandling::on_clearSessionPB_clicked()
2738 guiApp->clearSession();
2743 /////////////////////////////////////////////////////////////////////
2747 /////////////////////////////////////////////////////////////////////
2749 PrefEdit::PrefEdit(GuiPreferences * form)
2750 : PrefModule(catEditing, N_("Control"), form)
2754 connect(cursorFollowsCB, SIGNAL(clicked()),
2755 this, SIGNAL(changed()));
2756 connect(scrollBelowCB, SIGNAL(clicked()),
2757 this, SIGNAL(changed()));
2758 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2759 this, SIGNAL(changed()));
2760 connect(copyCTMarkupCB, SIGNAL(clicked()),
2761 this, SIGNAL(changed()));
2762 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2763 this, SIGNAL(changed()));
2764 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2765 this, SIGNAL(changed()));
2766 connect(macroEditStyleCO, SIGNAL(activated(int)),
2767 this, SIGNAL(changed()));
2768 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2769 this, SIGNAL(changed()));
2770 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2771 this, SIGNAL(changed()));
2772 connect(screenWidthLE, SIGNAL(textChanged(QString)),
2773 this, SIGNAL(changed()));
2774 connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
2775 this, SIGNAL(changed()));
2779 void PrefEdit::on_screenLimitCB_toggled(bool const state)
2781 screenWidthLE->setEnabled(state);
2782 screenWidthUnitCO->setEnabled(state);
2787 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2789 citationSearchLE->setEnabled(state);
2790 citationSearchLA->setEnabled(state);
2795 void PrefEdit::applyRC(LyXRC & rc) const
2797 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2798 rc.scroll_below_document = scrollBelowCB->isChecked();
2799 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2800 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2801 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2802 rc.group_layouts = groupEnvironmentsCB->isChecked();
2803 switch (macroEditStyleCO->currentIndex()) {
2804 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2805 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2806 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2808 rc.cursor_width = cursorWidthSB->value();
2809 rc.citation_search = citationSearchCB->isChecked();
2810 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2811 rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO));
2812 rc.screen_limit = screenLimitCB->isChecked();
2816 void PrefEdit::updateRC(LyXRC const & rc)
2818 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2819 scrollBelowCB->setChecked(rc.scroll_below_document);
2820 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2821 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2822 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2823 groupEnvironmentsCB->setChecked(rc.group_layouts);
2824 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2825 cursorWidthSB->setValue(rc.cursor_width);
2826 citationSearchCB->setChecked(rc.citation_search);
2827 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2828 citationSearchLE->setEnabled(rc.citation_search);
2829 citationSearchLA->setEnabled(rc.citation_search);
2830 lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
2831 screenWidthUnitCO->setEnabled(rc.screen_limit);
2832 screenLimitCB->setChecked(rc.screen_limit);
2833 screenWidthLE->setEnabled(rc.screen_limit);
2837 /////////////////////////////////////////////////////////////////////
2841 /////////////////////////////////////////////////////////////////////
2844 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2846 Ui::shortcutUi::setupUi(this);
2847 QDialog::setModal(true);
2848 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2849 on_lfunLE_textChanged();
2853 void GuiShortcutDialog::on_lfunLE_textChanged()
2855 QPushButton * ok = buttonBox->button(QDialogButtonBox::Ok);
2856 ok->setEnabled(!lfunLE->text().isEmpty());
2860 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2861 : PrefModule(catEditing, N_("Shortcuts"), form),
2862 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2863 systemItem_(nullptr)
2867 shortcutsTW->setColumnCount(2);
2868 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2869 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2870 shortcutsTW->setSortingEnabled(true);
2871 // Multi-selection can be annoying.
2872 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2874 connect(bindFilePB, SIGNAL(clicked()),
2875 this, SLOT(selectBind()));
2876 connect(bindFileED, SIGNAL(textChanged(QString)),
2877 this, SIGNAL(changed()));
2879 shortcut_ = new GuiShortcutDialog(this);
2880 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2881 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2882 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2884 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2885 this, SIGNAL(changed()));
2886 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2887 shortcut_, SLOT(reject()));
2888 connect(shortcut_->clearPB, SIGNAL(clicked()),
2889 this, SLOT(shortcutClearPressed()));
2890 connect(shortcut_->removePB, SIGNAL(clicked()),
2891 this, SLOT(shortcutRemovePressed()));
2892 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2893 this, SLOT(shortcutOkPressed()));
2894 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2895 this, SLOT(shortcutCancelPressed()));
2899 void PrefShortcuts::applyRC(LyXRC & rc) const
2901 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2902 // write user_bind and user_unbind to .lyx/bind/user.bind
2903 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2904 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2905 lyxerr << "LyX could not create the user bind directory '"
2906 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2909 if (!bind_dir.isDirWritable()) {
2910 lyxerr << "LyX could not write to the user bind directory '"
2911 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2914 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2915 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2916 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2917 // immediately apply the keybindings. Why this is not done before?
2918 // The good thing is that the menus are updated automatically.
2919 theTopLevelKeymap().clear();
2920 theTopLevelKeymap().read("site");
2921 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2922 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2926 void PrefShortcuts::updateRC(LyXRC const & rc)
2928 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2930 system_bind_.clear();
2932 user_unbind_.clear();
2933 system_bind_.read("site");
2934 system_bind_.read(rc.bind_file);
2935 // \unbind in user.bind is added to user_unbind_
2936 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2937 updateShortcutsTW();
2941 void PrefShortcuts::updateShortcutsTW()
2943 shortcutsTW->clear();
2945 editItem_ = new QTreeWidgetItem(shortcutsTW);
2946 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
2947 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
2949 mathItem_ = new QTreeWidgetItem(shortcutsTW);
2950 mathItem_->setText(0, qt_("Mathematical Symbols"));
2951 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
2953 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
2954 bufferItem_->setText(0, qt_("Document and Window"));
2955 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
2957 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
2958 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
2959 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
2961 systemItem_ = new QTreeWidgetItem(shortcutsTW);
2962 systemItem_->setText(0, qt_("System and Miscellaneous"));
2963 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
2965 // listBindings(unbound=true) lists all bound and unbound lfuns
2966 // Items in this list is tagged by its source.
2967 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
2969 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
2971 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
2972 KeyMap::UserUnbind);
2973 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
2974 user_bindinglist.end());
2975 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
2976 user_unbindinglist.end());
2978 KeyMap::BindingList::const_iterator it = bindinglist.begin();
2979 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
2980 for (; it != it_end; ++it)
2981 insertShortcutItem(it->request, it->sequence, it->tag);
2983 shortcutsTW->sortItems(0, Qt::AscendingOrder);
2984 on_shortcutsTW_itemSelectionChanged();
2985 on_searchLE_textEdited();
2986 shortcutsTW->resizeColumnToContents(0);
2991 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
2993 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
2998 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3000 // Hide rebound system settings that are empty
3001 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3005 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3007 item->setData(0, Qt::UserRole, QVariant(tag));
3011 case KeyMap::System:
3013 case KeyMap::UserBind:
3016 case KeyMap::UserUnbind:
3017 font.setStrikeOut(true);
3019 // this item is not displayed now.
3020 case KeyMap::UserExtraUnbind:
3021 font.setStrikeOut(true);
3024 item->setHidden(isAlwaysHidden(*item));
3025 item->setFont(1, font);
3029 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3030 KeySequence const & seq, KeyMap::ItemType tag)
3032 FuncCode const action = lfun.action();
3033 string const action_name = lyxaction.getActionName(action);
3034 QString const lfun_name = toqstr(from_utf8(action_name)
3035 + ' ' + lfun.argument());
3036 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3038 QTreeWidgetItem * newItem = nullptr;
3039 // for unbind items, try to find an existing item in the system bind list
3040 if (tag == KeyMap::UserUnbind) {
3041 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3042 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3043 for (auto const & item : items) {
3044 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3049 // if not found, this unbind item is KeyMap::UserExtraUnbind
3050 // Such an item is not displayed to avoid confusion (what is
3051 // unmatched removed?).
3057 switch(lyxaction.getActionType(action)) {
3058 case LyXAction::Hidden:
3060 case LyXAction::Edit:
3061 newItem = new QTreeWidgetItem(editItem_);
3063 case LyXAction::Math:
3064 newItem = new QTreeWidgetItem(mathItem_);
3066 case LyXAction::Buffer:
3067 newItem = new QTreeWidgetItem(bufferItem_);
3069 case LyXAction::Layout:
3070 newItem = new QTreeWidgetItem(layoutItem_);
3072 case LyXAction::System:
3073 newItem = new QTreeWidgetItem(systemItem_);
3076 // this should not happen
3077 newItem = new QTreeWidgetItem(shortcutsTW);
3079 newItem->setText(0, lfun_name);
3080 newItem->setText(1, shortcut);
3083 // record BindFile representation to recover KeySequence when needed.
3084 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3085 setItemType(newItem, tag);
3090 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3092 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3093 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3094 modifyPB->setEnabled(!items.isEmpty());
3095 if (items.isEmpty())
3098 if (itemType(*items[0]) == KeyMap::UserUnbind)
3099 removePB->setText(qt_("Res&tore"));
3101 removePB->setText(qt_("Remo&ve"));
3105 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3111 void PrefShortcuts::modifyShortcut()
3113 QTreeWidgetItem * item = shortcutsTW->currentItem();
3114 if (item->flags() & Qt::ItemIsSelectable) {
3115 shortcut_->lfunLE->setText(item->text(0));
3116 save_lfun_ = item->text(0).trimmed();
3117 shortcut_->shortcutWG->setText(item->text(1));
3119 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3120 shortcut_->shortcutWG->setKeySequence(seq);
3121 shortcut_->shortcutWG->setFocus();
3127 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3129 // list of items that match lfun
3130 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3131 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3132 for (auto const & item : items) {
3133 if (isAlwaysHidden(*item)) {
3134 setItemType(item, KeyMap::System);
3136 shortcutsTW->setCurrentItem(item);
3143 void PrefShortcuts::removeShortcut()
3145 // it seems that only one item can be selected, but I am
3146 // removing all selected items anyway.
3147 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3148 for (auto & item : items) {
3149 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3150 string lfun = fromqstr(item->text(0));
3151 FuncRequest const func = lyxaction.lookupFunc(lfun);
3153 switch (itemType(*item)) {
3154 case KeyMap::System: {
3155 // for system bind, we do not touch the item
3156 // but add an user unbind item
3157 user_unbind_.bind(shortcut, func);
3158 setItemType(item, KeyMap::UserUnbind);
3159 removePB->setText(qt_("Res&tore"));
3162 case KeyMap::UserBind: {
3163 // for user_bind, we remove this bind
3164 QTreeWidgetItem * parent = item->parent();
3165 int itemIdx = parent->indexOfChild(item);
3166 parent->takeChild(itemIdx);
3168 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3170 shortcutsTW->scrollToItem(parent);
3171 user_bind_.unbind(shortcut, func);
3172 // If this user binding hid an empty system binding, unhide the
3173 // latter and select it.
3174 unhideEmpty(item->text(0), true);
3177 case KeyMap::UserUnbind: {
3178 // for user_unbind, we remove the unbind, and the item
3179 // become KeyMap::System again.
3181 seq.parse(shortcut);
3182 // Ask the user to replace current binding
3183 if (!validateNewShortcut(func, seq, QString()))
3185 user_unbind_.unbind(shortcut, func);
3186 setItemType(item, KeyMap::System);
3187 removePB->setText(qt_("Remo&ve"));
3190 case KeyMap::UserExtraUnbind: {
3191 // for user unbind that is not in system bind file,
3192 // remove this unbind file
3193 QTreeWidgetItem * parent = item->parent();
3194 parent->takeChild(parent->indexOfChild(item));
3195 user_unbind_.unbind(shortcut, func);
3202 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3204 for (auto item : items) {
3205 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3206 string lfun = fromqstr(item->text(0));
3207 FuncRequest const func = lyxaction.lookupFunc(lfun);
3209 switch (itemType(*item)) {
3210 case KeyMap::System:
3211 // for system bind, we do not touch the item
3212 // but add an user unbind item
3213 user_unbind_.bind(shortcut, func);
3214 setItemType(item, KeyMap::UserUnbind);
3217 case KeyMap::UserBind: {
3218 // for user_bind, we remove this bind
3219 QTreeWidgetItem * parent = item->parent();
3220 int itemIdx = parent->indexOfChild(item);
3221 parent->takeChild(itemIdx);
3222 user_bind_.unbind(shortcut, func);
3223 unhideEmpty(item->text(0), false);
3233 void PrefShortcuts::selectBind()
3235 QString file = form_->browsebind(internalPath(bindFileED->text()));
3236 if (!file.isEmpty()) {
3237 bindFileED->setText(file);
3238 system_bind_ = KeyMap();
3239 system_bind_.read(fromqstr(file));
3240 updateShortcutsTW();
3245 void PrefShortcuts::on_modifyPB_pressed()
3251 void PrefShortcuts::on_newPB_pressed()
3253 shortcut_->lfunLE->clear();
3254 shortcut_->shortcutWG->reset();
3255 save_lfun_ = QString();
3260 void PrefShortcuts::on_removePB_pressed()
3267 void PrefShortcuts::on_searchLE_textEdited()
3269 if (searchLE->text().isEmpty()) {
3270 // show all hidden items
3271 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3273 (*it)->setHidden(isAlwaysHidden(**it));
3274 // close all categories
3275 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3276 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3279 // search both columns
3280 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3281 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3282 matched += shortcutsTW->findItems(searchLE->text(),
3283 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3285 // hide everyone (to avoid searching in matched QList repeatedly
3286 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3288 (*it++)->setHidden(true);
3289 // show matched items
3290 for (auto & item : matched)
3291 if (!isAlwaysHidden(*item)) {
3292 item->setHidden(false);
3294 item->parent()->setExpanded(true);
3299 docstring makeCmdString(FuncRequest const & f)
3301 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3302 if (!f.argument().empty())
3303 actionStr += " " + f.argument();
3308 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3310 FuncRequest res = user_bind_.getBinding(k);
3311 if (res != FuncRequest::unknown)
3313 res = system_bind_.getBinding(k);
3315 // Check if it is unbound. Note: user_unbind_ can only unbind one
3316 // FuncRequest per key sequence.
3317 if (user_unbind_.getBinding(k) == res)
3318 return FuncRequest::unknown;
3323 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3324 KeySequence const & k,
3325 QString const & lfun_to_modify)
3327 if (func.action() == LFUN_UNKNOWN_ACTION) {
3328 Alert::error(_("Failed to create shortcut"),
3329 _("Unknown or invalid LyX function"));
3330 activatePrefsWindow(form_);
3334 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3335 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3336 // and how it is used in GuiPrefs::shortcutOkPressed.
3337 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3338 Alert::error(_("Failed to create shortcut"),
3339 _("This LyX function is hidden and cannot be bound."));
3340 activatePrefsWindow(form_);
3344 if (k.length() == 0) {
3345 Alert::error(_("Failed to create shortcut"),
3346 _("Invalid or empty key sequence"));
3347 activatePrefsWindow(form_);
3351 FuncRequest oldBinding = currentBinding(k);
3352 if (oldBinding == func)
3353 // nothing to change
3356 // Check whether the key sequence is a prefix for other shortcuts.
3357 if (oldBinding == FuncRequest::prefix) {
3358 docstring const new_action_string = makeCmdString(func);
3359 docstring const text = bformat(_("Shortcut `%1$s' is already a prefix for other commands.\n"
3360 "Are you sure you want to unbind these commands and bind it to %2$s?"),
3361 k.print(KeySequence::ForGui), new_action_string);
3362 int ret = Alert::prompt(_("Redefine shortcut?"),
3363 text, 0, 1, _("&Redefine"), _("&Cancel"));
3364 activatePrefsWindow(form_);
3367 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3368 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3369 Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchRecursive), 1);
3370 deactivateShortcuts(items);
3374 // make sure this key isn't already bound---and, if so, prompt user
3375 // (exclude the lfun the user already wants to modify)
3376 docstring const action_string = makeCmdString(oldBinding);
3377 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3378 && lfun_to_modify != toqstr(action_string)) {
3379 docstring const new_action_string = makeCmdString(func);
3380 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3382 "Are you sure you want to unbind the "
3383 "current shortcut and bind it to %3$s?"),
3384 k.print(KeySequence::ForGui), action_string,
3386 int ret = Alert::prompt(_("Redefine shortcut?"),
3387 text, 0, 1, _("&Redefine"), _("&Cancel"));
3388 activatePrefsWindow(form_);
3391 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3392 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3393 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3394 deactivateShortcuts(items);
3400 void PrefShortcuts::shortcutOkPressed()
3402 QString const new_lfun = shortcut_->lfunLE->text();
3403 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3404 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3406 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3407 // "modify", or is empty if they clicked "new" (which I do not really like)
3408 if (!validateNewShortcut(func, k, save_lfun_))
3411 if (!save_lfun_.isEmpty()) {
3412 // real modification of the lfun's shortcut,
3413 // so remove the previous one
3414 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3415 deactivateShortcuts(to_modify);
3418 shortcut_->accept();
3420 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3422 user_bind_.bind(&k, func);
3423 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3425 item->parent()->setExpanded(true);
3426 shortcutsTW->setCurrentItem(item);
3427 shortcutsTW->scrollToItem(item);
3429 Alert::error(_("Failed to create shortcut"),
3430 _("Can not insert shortcut to the list"));
3431 activatePrefsWindow(form_);
3437 void PrefShortcuts::shortcutCancelPressed()
3439 shortcut_->shortcutWG->reset();
3443 void PrefShortcuts::shortcutClearPressed()
3445 shortcut_->shortcutWG->reset();
3449 void PrefShortcuts::shortcutRemovePressed()
3451 shortcut_->shortcutWG->removeFromSequence();
3455 /////////////////////////////////////////////////////////////////////
3459 /////////////////////////////////////////////////////////////////////
3461 PrefIdentity::PrefIdentity(GuiPreferences * form)
3462 : PrefModule(QString(), N_("Identity"), form)
3466 connect(nameED, SIGNAL(textChanged(QString)),
3467 this, SIGNAL(changed()));
3468 connect(emailED, SIGNAL(textChanged(QString)),
3469 this, SIGNAL(changed()));
3470 connect(initialsED, SIGNAL(textChanged(QString)),
3471 this, SIGNAL(changed()));
3473 nameED->setValidator(new NoNewLineValidator(nameED));
3474 emailED->setValidator(new NoNewLineValidator(emailED));
3475 initialsED->setValidator(new NoNewLineValidator(initialsED));
3479 void PrefIdentity::applyRC(LyXRC & rc) const
3481 rc.user_name = fromqstr(nameED->text());
3482 rc.user_email = fromqstr(emailED->text());
3483 rc.user_initials = fromqstr(initialsED->text());
3487 void PrefIdentity::updateRC(LyXRC const & rc)
3489 nameED->setText(toqstr(rc.user_name));
3490 emailED->setText(toqstr(rc.user_email));
3491 initialsED->setText(toqstr(rc.user_initials));
3496 /////////////////////////////////////////////////////////////////////
3500 /////////////////////////////////////////////////////////////////////
3502 GuiPreferences::GuiPreferences(GuiView & lv)
3503 : GuiDialog(lv, "prefs", qt_("Preferences"))
3507 QDialog::setModal(false);
3509 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3510 this, SLOT(slotButtonBox(QAbstractButton *)));
3512 addModule(new PrefUserInterface(this));
3513 addModule(new PrefDocHandling(this));
3514 addModule(new PrefEdit(this));
3515 addModule(new PrefShortcuts(this));
3516 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3517 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3518 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3519 addModule(screenfonts);
3520 addModule(new PrefColors(this));
3521 addModule(new PrefDisplay(this));
3522 addModule(new PrefInput(this));
3523 addModule(new PrefCompletion(this));
3525 addModule(new PrefPaths(this));
3527 addModule(new PrefIdentity(this));
3529 addModule(new PrefLanguage(this));
3530 addModule(new PrefSpellchecker(this));
3532 PrefOutput * output = new PrefOutput(this);
3534 addModule(new PrefLatex(this));
3536 PrefConverters * converters = new PrefConverters(this);
3537 PrefFileformats * formats = new PrefFileformats(this);
3538 connect(formats, SIGNAL(formatsChanged()),
3539 converters, SLOT(updateGui()));
3540 addModule(converters);
3543 prefsPS->setCurrentPanel("User Interface");
3545 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3546 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3547 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3548 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3549 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3551 guilyxfiles_ = new GuiLyXFiles(lv);
3552 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3553 this, SLOT(slotFileSelected(QString)));
3557 void GuiPreferences::addModule(PrefModule * module)
3559 LASSERT(module, return);
3560 if (module->category().isEmpty())
3561 prefsPS->addPanel(module, module->title());
3563 prefsPS->addPanel(module, module->title(), module->category());
3564 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3565 modules_.push_back(module);
3569 void GuiPreferences::change_adaptor()
3575 void GuiPreferences::applyRC(LyXRC & rc) const
3577 size_t end = modules_.size();
3578 for (size_t i = 0; i != end; ++i)
3579 modules_[i]->applyRC(rc);
3583 void GuiPreferences::updateRC(LyXRC const & rc)
3585 size_t const end = modules_.size();
3586 for (size_t i = 0; i != end; ++i)
3587 modules_[i]->updateRC(rc);
3591 void GuiPreferences::applyView()
3597 bool GuiPreferences::initialiseParams(string const &)
3600 formats_ = theFormats();
3601 converters_ = theConverters();
3602 converters_.update(formats_);
3603 movers_ = theMovers();
3607 // Make sure that the bc is in the INITIAL state
3608 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3615 void GuiPreferences::dispatchParams()
3618 rc_.write(ss, true);
3619 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3620 // issue prefsApplied signal. This will update the
3621 // localized screen font sizes.
3623 // FIXME: these need lfuns
3625 Author const & author =
3626 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3627 from_utf8(rc_.user_initials));
3628 theBufferList().recordCurrentAuthor(author);
3630 theFormats() = formats_;
3632 theConverters() = converters_;
3633 theConverters().update(formats_);
3634 theConverters().buildGraph();
3635 theBufferList().invalidateConverterCache();
3637 theMovers() = movers_;
3639 for (string const & color : colors_)
3640 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3644 if (!tempSaveCB->isChecked())
3645 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3649 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3651 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3655 void GuiPreferences::slotFileSelected(QString const file)
3661 QString GuiPreferences::browseLibFile(QString const & dir,
3662 QString const & name, QString const & ext)
3666 guilyxfiles_->passParams(fromqstr(dir));
3667 guilyxfiles_->selectItem(name);
3668 guilyxfiles_->exec();
3670 activatePrefsWindow(this);
3672 QString const result = uifile_;
3674 // remove the extension if it is the default one
3675 QString noextresult;
3676 if (getExtension(result) == ext)
3677 noextresult = removeExtension(result);
3679 noextresult = result;
3681 // remove the directory, if it is the default one
3682 QString const file = onlyFileName(noextresult);
3683 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3690 QString GuiPreferences::browsebind(QString const & file)
3692 return browseLibFile("bind", file, "bind");
3696 QString GuiPreferences::browseUI(QString const & file)
3698 return browseLibFile("ui", file, "ui");
3702 QString GuiPreferences::browsekbmap(QString const & file)
3704 return browseLibFile("kbd", file, "kmap");
3708 QString GuiPreferences::browse(QString const & file,
3709 QString const & title)
3711 return browseFile(file, title, QStringList(), true);
3715 } // namespace frontend
3718 #include "moc_GuiPrefs.cpp"