3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
16 #include "ColorCache.h"
17 #include "FileDialog.h"
18 #include "GuiApplication.h"
19 #include "GuiFontExample.h"
20 #include "GuiFontLoader.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiLyXFiles.h"
24 #include "qt_helpers.h"
25 #include "Validator.h"
28 #include "BufferList.h"
31 #include "ConverterCache.h"
32 #include "FontEnums.h"
33 #include "FuncRequest.h"
34 #include "KeySequence.h"
36 #include "LengthCombo.h"
37 #include "LyXAction.h"
39 #include "PanelStack.h"
41 #include "SpellChecker.h"
43 #include "support/debug.h"
44 #include "support/FileName.h"
45 #include "support/filetools.h"
46 #include "support/gettext.h"
47 #include "support/lassert.h"
48 #include "support/lstrings.h"
49 #include "support/Messages.h"
50 #include "support/os.h"
51 #include "support/Package.h"
53 #include "frontends/alert.h"
54 #include "frontends/Application.h"
55 #include "frontends/FontLoader.h"
57 #include <QAbstractItemModel>
59 #include <QColorDialog>
60 #include <QFontDatabase>
61 #include <QHeaderView>
63 #include <QMessageBox>
64 #include <QPushButton>
67 #include <QTreeWidget>
68 #include <QTreeWidgetItem>
79 using namespace lyx::support;
80 using namespace lyx::support::os;
85 /////////////////////////////////////////////////////////////////////
89 /////////////////////////////////////////////////////////////////////
91 /** Launch a file dialog and return the chosen file.
92 filename: a suggested filename.
93 title: the title of the dialog.
95 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
97 QString browseFile(QString const & filename,
98 QString const & title,
99 QStringList const & filters,
101 QString const & label1 = QString(),
102 QString const & dir1 = QString(),
103 QString const & label2 = QString(),
104 QString const & dir2 = QString(),
105 QString const & fallback_dir = QString())
107 QString lastPath = ".";
108 if (!filename.isEmpty())
109 lastPath = onlyPath(filename);
110 else if(!fallback_dir.isEmpty())
111 lastPath = fallback_dir;
113 FileDialog dlg(title);
114 dlg.setButton1(label1, dir1);
115 dlg.setButton2(label2, dir2);
117 FileDialog::Result result;
120 result = dlg.save(lastPath, filters, onlyFileName(filename));
122 result = dlg.open(lastPath, filters, onlyFileName(filename));
124 return result.second;
128 /** Launch a file dialog and return the chosen directory.
129 pathname: a suggested pathname.
130 title: the title of the dialog.
131 dir1 = (name, dir), dir2 = (name, dir): extra buttons on the dialog.
133 QString browseDir(QString const & pathname,
134 QString const & title,
135 QString const & label1 = QString(),
136 QString const & dir1 = QString(),
137 QString const & label2 = QString(),
138 QString const & dir2 = QString())
140 QString lastPath = ".";
141 if (!pathname.isEmpty())
142 lastPath = onlyPath(pathname);
144 FileDialog dlg(title);
145 dlg.setButton1(label1, dir1);
146 dlg.setButton2(label2, dir2);
148 FileDialog::Result const result =
149 dlg.opendir(lastPath, onlyFileName(pathname));
151 return result.second;
155 } // namespace frontend
158 QString browseRelToParent(QString const & filename, QString const & relpath,
159 QString const & title, QStringList const & filters, bool save,
160 QString const & label1, QString const & dir1,
161 QString const & label2, QString const & dir2)
163 QString const fname = makeAbsPath(filename, relpath);
165 QString const outname =
166 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
168 QString const reloutname =
169 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
171 if (reloutname.startsWith("../"))
178 QString browseRelToSub(QString const & filename, QString const & relpath,
179 QString const & title, QStringList const & filters, bool save,
180 QString const & label1, QString const & dir1,
181 QString const & label2, QString const & dir2)
183 QString const fname = makeAbsPath(filename, relpath);
185 QString const outname =
186 frontend::browseFile(fname, title, filters, save, label1, dir1, label2, dir2);
188 QString const reloutname =
189 toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath)));
191 QString testname = reloutname;
192 #if QT_VERSION < 0x060000
193 testname.remove(QRegExp("^(\\.\\./)+"));
195 testname.remove(QRegularExpression("^(\\.\\./)+"));
198 if (testname.contains("/"))
206 /////////////////////////////////////////////////////////////////////
210 /////////////////////////////////////////////////////////////////////
214 QString const catLookAndFeel = N_("Look & Feel");
215 QString const catEditing = N_("Editing");
216 QString const catLanguage = N_("Language Settings");
217 QString const catOutput = N_("Output");
218 QString const catFiles = N_("File Handling");
220 static void parseFontName(QString const & mangled0,
221 string & name, string & foundry)
223 string mangled = fromqstr(mangled0);
224 size_t const idx = mangled.find('[');
225 if (idx == string::npos || idx == 0) {
229 name = mangled.substr(0, idx - 1);
230 foundry = mangled.substr(idx + 1, mangled.size() - idx - 2);
235 static void setComboxFont(QComboBox * cb, string const & family,
236 string const & foundry)
238 QString fontname = toqstr(family);
239 if (!foundry.empty())
240 fontname += " [" + toqstr(foundry) + ']';
242 for (int i = 0; i != cb->count(); ++i) {
243 if (cb->itemText(i) == fontname) {
244 cb->setCurrentIndex(i);
249 // Try matching without foundry name
251 // We count in reverse in order to prefer the Xft foundry
252 for (int i = cb->count(); --i >= 0;) {
253 string name, fnt_foundry;
254 parseFontName(cb->itemText(i), name, fnt_foundry);
255 if (compare_ascii_no_case(name, family) == 0) {
256 cb->setCurrentIndex(i);
261 // family alone can contain e.g. "Helvetica [Adobe]"
262 string tmpname, tmpfoundry;
263 parseFontName(toqstr(family), tmpname, tmpfoundry);
265 // We count in reverse in order to prefer the Xft foundry
266 for (int i = cb->count(); --i >= 0; ) {
267 string name, fnt_foundry;
268 parseFontName(cb->itemText(i), name, fnt_foundry);
269 if (compare_ascii_no_case(name, fnt_foundry) == 0) {
270 cb->setCurrentIndex(i);
275 // Bleh, default fonts, and the names couldn't be found. Hack
280 QString const font_family = toqstr(family);
281 if (font_family == guiApp->romanFontName()) {
282 font.setStyleHint(QFont::Serif);
283 font.setFamily(font_family);
284 } else if (font_family == guiApp->sansFontName()) {
285 font.setStyleHint(QFont::SansSerif);
286 font.setFamily(font_family);
287 } else if (font_family == guiApp->typewriterFontName()) {
288 font.setStyleHint(QFont::TypeWriter);
289 font.setFamily(font_family);
291 LYXERR0("FAILED to find the default font: '"
292 << foundry << "', '" << family << '\'');
296 QFontInfo info(font);
297 string default_font_name, dummyfoundry;
298 parseFontName(info.family(), default_font_name, dummyfoundry);
299 LYXERR0("Apparent font is " << default_font_name);
301 for (int i = 0; i < cb->count(); ++i) {
302 LYXERR0("Looking at " << cb->itemText(i));
303 if (compare_ascii_no_case(fromqstr(cb->itemText(i)),
304 default_font_name) == 0) {
305 cb->setCurrentIndex(i);
310 LYXERR0("FAILED to find the font: '"
311 << foundry << "', '" << family << '\'');
315 /////////////////////////////////////////////////////////////////////
319 /////////////////////////////////////////////////////////////////////
321 PrefOutput::PrefOutput(GuiPreferences * form)
322 : PrefModule(catOutput, N_("General[[settings]]"), form)
326 dviCB->setValidator(new NoNewLineValidator(dviCB));
327 pdfCB->setValidator(new NoNewLineValidator(pdfCB));
329 connect(plaintextLinelengthSB, SIGNAL(valueChanged(int)),
330 this, SIGNAL(changed()));
331 connect(overwriteCO, SIGNAL(activated(int)),
332 this, SIGNAL(changed()));
333 connect(dviCB, SIGNAL(editTextChanged(QString)),
334 this, SIGNAL(changed()));
335 connect(pdfCB, SIGNAL(editTextChanged(QString)),
336 this, SIGNAL(changed()));
337 connect(printerPaperTypeED, SIGNAL(textChanged(QString)),
338 this, SIGNAL(changed()));
339 connect(printerLandscapeED, SIGNAL(textChanged(QString)),
340 this, SIGNAL(changed()));
341 connect(printerPaperSizeED, SIGNAL(textChanged(QString)),
342 this, SIGNAL(changed()));
344 printerPaperTypeED->setValidator(new NoNewLineValidator(printerPaperTypeED));
345 printerLandscapeED->setValidator(new NoNewLineValidator(printerLandscapeED));
346 printerPaperSizeED->setValidator(new NoNewLineValidator(printerPaperSizeED));
349 dviCB->addItem("xdvi -sourceposition '$$n:\\ $$t' $$o");
350 dviCB->addItem("yap -1 -s \"$$n $$t\" $$o");
351 dviCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
352 dviCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
354 pdfCB->addItem("CMCDDE SUMATRA control [ForwardSearch(\\\"$$o\\\",\\\"$$t\\\",$$n,0,0,1)]");
355 pdfCB->addItem("SumatraPDF -reuse-instance \"$$o\" -forward-search \"$$t\" $$n");
356 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"xpdf -raise -remote $$t.tmp $$o %{page+1}\"");
357 pdfCB->addItem("okular --unique \"$$o#src:$$n $$f\"");
358 pdfCB->addItem("qpdfview --unique \"$$o#src:$$f:$$n:0\"");
359 pdfCB->addItem("synctex view -i $$n:0:$$t -o $$o -x \"evince -i %{page+1} $$o\"");
360 pdfCB->addItem("/Applications/Skim.app/Contents/SharedSupport/displayline $$n $$o $$t");
364 void PrefOutput::applyRC(LyXRC & rc) const
366 rc.plaintext_linelen = plaintextLinelengthSB->value();
367 rc.forward_search_dvi = fromqstr(dviCB->currentText());
368 rc.forward_search_pdf = fromqstr(pdfCB->currentText());
370 switch (overwriteCO->currentIndex()) {
372 rc.export_overwrite = NO_FILES;
375 rc.export_overwrite = MAIN_FILE;
378 rc.export_overwrite = ALL_FILES;
382 rc.print_paper_flag = fromqstr(printerPaperTypeED->text());
383 rc.print_landscape_flag = fromqstr(printerLandscapeED->text());
384 rc.print_paper_dimension_flag = fromqstr(printerPaperSizeED->text());
388 void PrefOutput::updateRC(LyXRC const & rc)
390 plaintextLinelengthSB->setValue(rc.plaintext_linelen);
391 dviCB->setEditText(toqstr(rc.forward_search_dvi));
392 pdfCB->setEditText(toqstr(rc.forward_search_pdf));
394 switch (rc.export_overwrite) {
396 overwriteCO->setCurrentIndex(0);
399 overwriteCO->setCurrentIndex(1);
402 overwriteCO->setCurrentIndex(2);
406 printerPaperTypeED->setText(toqstr(rc.print_paper_flag));
407 printerLandscapeED->setText(toqstr(rc.print_landscape_flag));
408 printerPaperSizeED->setText(toqstr(rc.print_paper_dimension_flag));
412 /////////////////////////////////////////////////////////////////////
416 /////////////////////////////////////////////////////////////////////
418 PrefInput::PrefInput(GuiPreferences * form)
419 : PrefModule(catEditing, N_("Keyboard/Mouse"), form)
423 connect(keymapCB, SIGNAL(clicked()),
424 this, SIGNAL(changed()));
425 connect(firstKeymapED, SIGNAL(textChanged(QString)),
426 this, SIGNAL(changed()));
427 connect(secondKeymapED, SIGNAL(textChanged(QString)),
428 this, SIGNAL(changed()));
429 connect(mouseWheelSpeedSB, SIGNAL(valueChanged(double)),
430 this, SIGNAL(changed()));
431 connect(scrollzoomEnableCB, SIGNAL(clicked()),
432 this, SIGNAL(changed()));
433 connect(scrollzoomValueCO, SIGNAL(activated(int)),
434 this, SIGNAL(changed()));
435 connect(dontswapCB, SIGNAL(toggled(bool)),
436 this, SIGNAL(changed()));
437 connect(mmPasteCB, SIGNAL(toggled(bool)),
438 this, SIGNAL(changed()));
440 // reveal checkbox for switching Ctrl and Meta on Mac:
443 #if QT_VERSION > 0x040600
447 dontswapCB->setVisible(swapcb);
451 void PrefInput::applyRC(LyXRC & rc) const
453 // FIXME: can derive CB from the two EDs
454 rc.use_kbmap = keymapCB->isChecked();
455 rc.primary_kbmap = internal_path(fromqstr(firstKeymapED->text()));
456 rc.secondary_kbmap = internal_path(fromqstr(secondKeymapED->text()));
457 rc.mouse_wheel_speed = mouseWheelSpeedSB->value();
458 if (scrollzoomEnableCB->isChecked()) {
459 switch (scrollzoomValueCO->currentIndex()) {
461 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_CTRL;
464 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_SHIFT;
467 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_ALT;
471 rc.scroll_wheel_zoom = LyXRC::SCROLL_WHEEL_ZOOM_OFF;
473 rc.mac_dontswap_ctrl_meta = dontswapCB->isChecked();
474 rc.mouse_middlebutton_paste = mmPasteCB->isChecked();
478 void PrefInput::updateRC(LyXRC const & rc)
480 // FIXME: can derive CB from the two EDs
481 keymapCB->setChecked(rc.use_kbmap);
482 firstKeymapED->setText(toqstr(external_path(rc.primary_kbmap)));
483 secondKeymapED->setText(toqstr(external_path(rc.secondary_kbmap)));
484 mouseWheelSpeedSB->setValue(rc.mouse_wheel_speed);
485 switch (rc.scroll_wheel_zoom) {
486 case LyXRC::SCROLL_WHEEL_ZOOM_OFF:
487 scrollzoomEnableCB->setChecked(false);
489 case LyXRC::SCROLL_WHEEL_ZOOM_CTRL:
490 scrollzoomEnableCB->setChecked(true);
491 scrollzoomValueCO->setCurrentIndex(0);
493 case LyXRC::SCROLL_WHEEL_ZOOM_SHIFT:
494 scrollzoomEnableCB->setChecked(true);
495 scrollzoomValueCO->setCurrentIndex(1);
497 case LyXRC::SCROLL_WHEEL_ZOOM_ALT:
498 scrollzoomEnableCB->setChecked(true);
499 scrollzoomValueCO->setCurrentIndex(2);
502 dontswapCB->setChecked(rc.mac_dontswap_ctrl_meta);
503 mmPasteCB->setChecked(rc.mouse_middlebutton_paste);
507 QString PrefInput::testKeymap(QString const & keymap)
509 return form_->browsekbmap(internalPath(keymap));
513 void PrefInput::on_firstKeymapPB_clicked(bool)
515 QString const file = testKeymap(firstKeymapED->text());
517 firstKeymapED->setText(file);
521 void PrefInput::on_secondKeymapPB_clicked(bool)
523 QString const file = testKeymap(secondKeymapED->text());
525 secondKeymapED->setText(file);
529 void PrefInput::on_keymapCB_toggled(bool keymap)
531 firstKeymapLA->setEnabled(keymap);
532 secondKeymapLA->setEnabled(keymap);
533 firstKeymapED->setEnabled(keymap);
534 secondKeymapED->setEnabled(keymap);
535 firstKeymapPB->setEnabled(keymap);
536 secondKeymapPB->setEnabled(keymap);
540 void PrefInput::on_scrollzoomEnableCB_toggled(bool enabled)
542 scrollzoomValueCO->setEnabled(enabled);
546 /////////////////////////////////////////////////////////////////////
550 /////////////////////////////////////////////////////////////////////
552 PrefCompletion::PrefCompletion(GuiPreferences * form)
553 : PrefModule(catEditing, N_("Input Completion"), form)
557 connect(inlineDelaySB, SIGNAL(valueChanged(double)),
558 this, SIGNAL(changed()));
559 connect(inlineMathCB, SIGNAL(clicked()),
560 this, SIGNAL(changed()));
561 connect(inlineTextCB, SIGNAL(clicked()),
562 this, SIGNAL(changed()));
563 connect(inlineDotsCB, SIGNAL(clicked()),
564 this, SIGNAL(changed()));
565 connect(popupDelaySB, SIGNAL(valueChanged(double)),
566 this, SIGNAL(changed()));
567 connect(popupMathCB, SIGNAL(clicked()),
568 this, SIGNAL(changed()));
569 connect(autocorrectionCB, SIGNAL(clicked()),
570 this, SIGNAL(changed()));
571 connect(popupTextCB, SIGNAL(clicked()),
572 this, SIGNAL(changed()));
573 connect(popupAfterCompleteCB, SIGNAL(clicked()),
574 this, SIGNAL(changed()));
575 connect(cursorTextCB, SIGNAL(clicked()),
576 this, SIGNAL(changed()));
577 connect(minlengthSB, SIGNAL(valueChanged(int)),
578 this, SIGNAL(changed()));
582 void PrefCompletion::on_inlineTextCB_clicked()
588 void PrefCompletion::on_popupTextCB_clicked()
594 void PrefCompletion::enableCB()
596 cursorTextCB->setEnabled(
597 popupTextCB->isChecked() || inlineTextCB->isChecked());
601 void PrefCompletion::applyRC(LyXRC & rc) const
603 rc.completion_inline_delay = inlineDelaySB->value();
604 rc.completion_inline_math = inlineMathCB->isChecked();
605 rc.completion_inline_text = inlineTextCB->isChecked();
606 rc.completion_inline_dots = inlineDotsCB->isChecked() ? 13 : -1;
607 rc.completion_popup_delay = popupDelaySB->value();
608 rc.completion_popup_math = popupMathCB->isChecked();
609 rc.autocorrection_math = autocorrectionCB->isChecked();
610 rc.completion_popup_text = popupTextCB->isChecked();
611 rc.completion_cursor_text = cursorTextCB->isChecked();
612 rc.completion_popup_after_complete =
613 popupAfterCompleteCB->isChecked();
614 rc.completion_minlength = minlengthSB->value();
618 void PrefCompletion::updateRC(LyXRC const & rc)
620 inlineDelaySB->setValue(rc.completion_inline_delay);
621 inlineMathCB->setChecked(rc.completion_inline_math);
622 inlineTextCB->setChecked(rc.completion_inline_text);
623 inlineDotsCB->setChecked(rc.completion_inline_dots != -1);
624 popupDelaySB->setValue(rc.completion_popup_delay);
625 popupMathCB->setChecked(rc.completion_popup_math);
626 autocorrectionCB->setChecked(rc.autocorrection_math);
627 popupTextCB->setChecked(rc.completion_popup_text);
628 cursorTextCB->setChecked(rc.completion_cursor_text);
629 popupAfterCompleteCB->setChecked(rc.completion_popup_after_complete);
631 minlengthSB->setValue(rc.completion_minlength);
636 /////////////////////////////////////////////////////////////////////
640 /////////////////////////////////////////////////////////////////////
642 PrefLatex::PrefLatex(GuiPreferences * form)
643 : PrefModule(catOutput, N_("LaTeX"), form)
647 latexDviPaperED->setValidator(new NoNewLineValidator(latexDviPaperED));
648 latexBibtexED->setValidator(new NoNewLineValidator(latexBibtexED));
649 latexJBibtexED->setValidator(new NoNewLineValidator(latexJBibtexED));
650 latexIndexED->setValidator(new NoNewLineValidator(latexIndexED));
651 latexJIndexED->setValidator(new NoNewLineValidator(latexJIndexED));
652 latexNomenclED->setValidator(new NoNewLineValidator(latexNomenclED));
653 latexChecktexED->setValidator(new NoNewLineValidator(latexChecktexED));
655 connect(latexChecktexED, SIGNAL(textChanged(QString)),
656 this, SIGNAL(changed()));
657 connect(latexBibtexCO, SIGNAL(activated(int)),
658 this, SIGNAL(changed()));
659 connect(latexBibtexED, SIGNAL(textChanged(QString)),
660 this, SIGNAL(changed()));
661 connect(latexJBibtexCO, SIGNAL(activated(int)),
662 this, SIGNAL(changed()));
663 connect(latexJBibtexED, SIGNAL(textChanged(QString)),
664 this, SIGNAL(changed()));
665 connect(latexIndexCO, SIGNAL(activated(int)),
666 this, SIGNAL(changed()));
667 connect(latexIndexED, SIGNAL(textChanged(QString)),
668 this, SIGNAL(changed()));
669 connect(latexJIndexED, SIGNAL(textChanged(QString)),
670 this, SIGNAL(changed()));
671 connect(latexAutoresetCB, SIGNAL(clicked()),
672 this, SIGNAL(changed()));
673 connect(latexDviPaperED, SIGNAL(textChanged(QString)),
674 this, SIGNAL(changed()));
675 connect(latexNomenclED, SIGNAL(textChanged(QString)),
676 this, SIGNAL(changed()));
678 #if defined(__CYGWIN__) || defined(_WIN32)
679 pathCB->setVisible(true);
680 connect(pathCB, SIGNAL(clicked()),
681 this, SIGNAL(changed()));
683 pathCB->setVisible(false);
688 void PrefLatex::on_latexBibtexCO_activated(int n)
690 QString const bibtex = latexBibtexCO->itemData(n).toString();
691 if (bibtex.isEmpty()) {
692 latexBibtexED->clear();
693 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
696 for (LyXRC::CommandSet::const_iterator it = bibtex_alternatives.begin();
697 it != bibtex_alternatives.end(); ++it) {
698 QString const bib = toqstr(*it);
699 int ind = bib.indexOf(" ");
700 QString sel_command = bib.left(ind);
701 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
702 if (bibtex == sel_command) {
704 latexBibtexED->clear();
706 latexBibtexED->setText(sel_options.trimmed());
709 latexBibtexOptionsLA->setText(qt_("&Options:"));
713 void PrefLatex::on_latexJBibtexCO_activated(int n)
715 QString const jbibtex = latexJBibtexCO->itemData(n).toString();
716 if (jbibtex.isEmpty()) {
717 latexJBibtexED->clear();
718 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
721 for (LyXRC::CommandSet::const_iterator it = jbibtex_alternatives.begin();
722 it != jbibtex_alternatives.end(); ++it) {
723 QString const bib = toqstr(*it);
724 int ind = bib.indexOf(" ");
725 QString sel_command = bib.left(ind);
726 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
727 if (jbibtex == sel_command) {
729 latexJBibtexED->clear();
731 latexJBibtexED->setText(sel_options.trimmed());
734 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
738 void PrefLatex::on_latexIndexCO_activated(int n)
740 QString const index = latexIndexCO->itemData(n).toString();
741 if (index.isEmpty()) {
742 latexIndexED->clear();
743 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
746 for (LyXRC::CommandSet::const_iterator it = index_alternatives.begin();
747 it != index_alternatives.end(); ++it) {
748 QString const idx = toqstr(*it);
749 int ind = idx.indexOf(" ");
750 QString sel_command = idx.left(ind);
751 QString sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
752 if (index == sel_command) {
754 latexIndexED->clear();
756 latexIndexED->setText(sel_options.trimmed());
759 latexIndexOptionsLA->setText(qt_("Op&tions:"));
763 void PrefLatex::applyRC(LyXRC & rc) const
765 // If bibtex is not empty, bibopt contains the options, otherwise
766 // it is a customized bibtex command with options.
767 QString const bibtex = latexBibtexCO->itemData(
768 latexBibtexCO->currentIndex()).toString();
769 QString const bibopt = latexBibtexED->text();
770 if (bibtex.isEmpty())
771 rc.bibtex_command = fromqstr(bibopt);
772 else if (bibopt.isEmpty())
773 rc.bibtex_command = fromqstr(bibtex);
775 rc.bibtex_command = fromqstr(bibtex) + " " + fromqstr(bibopt);
777 // If jbibtex is not empty, jbibopt contains the options, otherwise
778 // it is a customized bibtex command with options.
779 QString const jbibtex = latexJBibtexCO->itemData(
780 latexJBibtexCO->currentIndex()).toString();
781 QString const jbibopt = latexJBibtexED->text();
782 if (jbibtex.isEmpty())
783 rc.jbibtex_command = fromqstr(jbibopt);
784 else if (jbibopt.isEmpty())
785 rc.jbibtex_command = fromqstr(jbibtex);
787 rc.jbibtex_command = fromqstr(jbibtex) + " " + fromqstr(jbibopt);
789 // If index is not empty, idxopt contains the options, otherwise
790 // it is a customized index command with options.
791 QString const index = latexIndexCO->itemData(
792 latexIndexCO->currentIndex()).toString();
793 QString const idxopt = latexIndexED->text();
795 rc.index_command = fromqstr(idxopt);
796 else if (idxopt.isEmpty())
797 rc.index_command = fromqstr(index);
799 rc.index_command = fromqstr(index) + " " + fromqstr(idxopt);
801 rc.chktex_command = fromqstr(latexChecktexED->text());
802 rc.jindex_command = fromqstr(latexJIndexED->text());
803 rc.nomencl_command = fromqstr(latexNomenclED->text());
804 rc.auto_reset_options = latexAutoresetCB->isChecked();
805 rc.view_dvi_paper_option = fromqstr(latexDviPaperED->text());
806 #if defined(__CYGWIN__) || defined(_WIN32)
807 rc.windows_style_tex_paths = pathCB->isChecked();
812 void PrefLatex::updateRC(LyXRC const & rc)
814 latexBibtexCO->clear();
816 latexBibtexCO->addItem(qt_("Automatic"), "automatic");
817 latexBibtexCO->addItem(qt_("Custom"), QString());
818 for (LyXRC::CommandSet::const_iterator it = rc.bibtex_alternatives.begin();
819 it != rc.bibtex_alternatives.end(); ++it) {
820 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
821 latexBibtexCO->addItem(command, command);
824 bibtex_alternatives = rc.bibtex_alternatives;
826 QString const bib = toqstr(rc.bibtex_command);
827 int ind = bib.indexOf(" ");
828 QString sel_command = bib.left(ind);
829 QString sel_options = ind < 0 ? QString() : bib.mid(ind + 1);
831 int pos = latexBibtexCO->findData(sel_command);
833 latexBibtexCO->setCurrentIndex(pos);
834 latexBibtexED->setText(sel_options.trimmed());
835 latexBibtexOptionsLA->setText(qt_("&Options:"));
837 latexBibtexED->setText(toqstr(rc.bibtex_command));
838 latexBibtexCO->setCurrentIndex(0);
839 latexBibtexOptionsLA->setText(qt_("C&ommand:"));
842 latexJBibtexCO->clear();
844 latexJBibtexCO->addItem(qt_("Automatic"), "automatic");
845 latexJBibtexCO->addItem(qt_("Custom"), QString());
846 for (LyXRC::CommandSet::const_iterator it = rc.jbibtex_alternatives.begin();
847 it != rc.jbibtex_alternatives.end(); ++it) {
848 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
849 latexJBibtexCO->addItem(command, command);
852 jbibtex_alternatives = rc.jbibtex_alternatives;
854 QString const jbib = toqstr(rc.jbibtex_command);
855 ind = jbib.indexOf(" ");
856 sel_command = jbib.left(ind);
857 sel_options = ind < 0 ? QString() : jbib.mid(ind + 1);
859 pos = latexJBibtexCO->findData(sel_command);
861 latexJBibtexCO->setCurrentIndex(pos);
862 latexJBibtexED->setText(sel_options.trimmed());
863 latexJBibtexOptionsLA->setText(qt_("Opt&ions:"));
865 latexJBibtexED->setText(toqstr(rc.bibtex_command));
866 latexJBibtexCO->setCurrentIndex(0);
867 latexJBibtexOptionsLA->setText(qt_("Co&mmand:"));
870 latexIndexCO->clear();
872 latexIndexCO->addItem(qt_("Custom"), QString());
873 for (LyXRC::CommandSet::const_iterator it = rc.index_alternatives.begin();
874 it != rc.index_alternatives.end(); ++it) {
875 QString const command = toqstr(*it).left(toqstr(*it).indexOf(" "));
876 latexIndexCO->addItem(command, command);
879 index_alternatives = rc.index_alternatives;
881 QString const idx = toqstr(rc.index_command);
882 ind = idx.indexOf(" ");
883 sel_command = idx.left(ind);
884 sel_options = ind < 0 ? QString() : idx.mid(ind + 1);
886 pos = latexIndexCO->findData(sel_command);
888 latexIndexCO->setCurrentIndex(pos);
889 latexIndexED->setText(sel_options.trimmed());
890 latexIndexOptionsLA->setText(qt_("Op&tions:"));
892 latexIndexED->setText(toqstr(rc.index_command));
893 latexIndexCO->setCurrentIndex(0);
894 latexIndexOptionsLA->setText(qt_("Co&mmand:"));
897 latexChecktexED->setText(toqstr(rc.chktex_command));
898 latexJIndexED->setText(toqstr(rc.jindex_command));
899 latexNomenclED->setText(toqstr(rc.nomencl_command));
900 latexAutoresetCB->setChecked(rc.auto_reset_options);
901 latexDviPaperED->setText(toqstr(rc.view_dvi_paper_option));
902 #if defined(__CYGWIN__) || defined(_WIN32)
903 pathCB->setChecked(rc.windows_style_tex_paths);
908 /////////////////////////////////////////////////////////////////////
912 /////////////////////////////////////////////////////////////////////
914 PrefScreenFonts::PrefScreenFonts(GuiPreferences * form)
915 : PrefModule(catLookAndFeel, N_("Screen Fonts"), form)
919 #if QT_VERSION < 0x050e00
920 connect(screenRomanCO, SIGNAL(activated(QString)),
921 this, SLOT(selectRoman(QString)));
922 connect(screenSansCO, SIGNAL(activated(QString)),
923 this, SLOT(selectSans(QString)));
924 connect(screenTypewriterCO, SIGNAL(activated(QString)),
925 this, SLOT(selectTypewriter(QString)));
927 connect(screenRomanCO, SIGNAL(textActivated(QString)),
928 this, SLOT(selectRoman(QString)));
929 connect(screenSansCO, SIGNAL(textActivated(QString)),
930 this, SLOT(selectSans(QString)));
931 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
932 this, SLOT(selectTypewriter(QString)));
935 #if QT_VERSION >= 0x060000
936 const QStringList families(QFontDatabase::families());
938 QFontDatabase fontdb;
939 const QStringList families(fontdb.families());
941 for (auto const & family : families) {
942 screenRomanCO->addItem(family);
943 screenSansCO->addItem(family);
944 screenTypewriterCO->addItem(family);
946 #if QT_VERSION < 0x050e00
947 connect(screenRomanCO, SIGNAL(activated(QString)),
948 this, SIGNAL(changed()));
949 connect(screenSansCO, SIGNAL(activated(QString)),
950 this, SIGNAL(changed()));
951 connect(screenTypewriterCO, SIGNAL(activated(QString)),
952 this, SIGNAL(changed()));
954 connect(screenRomanCO, SIGNAL(textActivated(QString)),
955 this, SIGNAL(changed()));
956 connect(screenSansCO, SIGNAL(textActivated(QString)),
957 this, SIGNAL(changed()));
958 connect(screenTypewriterCO, SIGNAL(textActivated(QString)),
959 this, SIGNAL(changed()));
961 connect(screenZoomSB, SIGNAL(valueChanged(int)),
962 this, SIGNAL(changed()));
963 connect(screenTinyED, SIGNAL(textChanged(QString)),
964 this, SIGNAL(changed()));
965 connect(screenSmallestED, SIGNAL(textChanged(QString)),
966 this, SIGNAL(changed()));
967 connect(screenSmallerED, SIGNAL(textChanged(QString)),
968 this, SIGNAL(changed()));
969 connect(screenSmallED, SIGNAL(textChanged(QString)),
970 this, SIGNAL(changed()));
971 connect(screenNormalED, SIGNAL(textChanged(QString)),
972 this, SIGNAL(changed()));
973 connect(screenLargeED, SIGNAL(textChanged(QString)),
974 this, SIGNAL(changed()));
975 connect(screenLargerED, SIGNAL(textChanged(QString)),
976 this, SIGNAL(changed()));
977 connect(screenLargestED, SIGNAL(textChanged(QString)),
978 this, SIGNAL(changed()));
979 connect(screenHugeED, SIGNAL(textChanged(QString)),
980 this, SIGNAL(changed()));
981 connect(screenHugerED, SIGNAL(textChanged(QString)),
982 this, SIGNAL(changed()));
984 screenTinyED->setValidator(new QDoubleValidator(screenTinyED));
985 screenSmallestED->setValidator(new QDoubleValidator(screenSmallestED));
986 screenSmallerED->setValidator(new QDoubleValidator(screenSmallerED));
987 screenSmallED->setValidator(new QDoubleValidator(screenSmallED));
988 screenNormalED->setValidator(new QDoubleValidator(screenNormalED));
989 screenLargeED->setValidator(new QDoubleValidator(screenLargeED));
990 screenLargerED->setValidator(new QDoubleValidator(screenLargerED));
991 screenLargestED->setValidator(new QDoubleValidator(screenLargestED));
992 screenHugeED->setValidator(new QDoubleValidator(screenHugeED));
993 screenHugerED->setValidator(new QDoubleValidator(screenHugerED));
997 void PrefScreenFonts::applyRC(LyXRC & rc) const
999 LyXRC const oldrc = rc;
1001 parseFontName(screenRomanCO->currentText(),
1002 rc.roman_font_name, rc.roman_font_foundry);
1003 parseFontName(screenSansCO->currentText(),
1004 rc.sans_font_name, rc.sans_font_foundry);
1005 parseFontName(screenTypewriterCO->currentText(),
1006 rc.typewriter_font_name, rc.typewriter_font_foundry);
1008 rc.defaultZoom = screenZoomSB->value();
1009 rc.font_sizes[TINY_SIZE] = widgetToDoubleStr(screenTinyED);
1010 rc.font_sizes[SCRIPT_SIZE] = widgetToDoubleStr(screenSmallestED);
1011 rc.font_sizes[FOOTNOTE_SIZE] = widgetToDoubleStr(screenSmallerED);
1012 rc.font_sizes[SMALL_SIZE] = widgetToDoubleStr(screenSmallED);
1013 rc.font_sizes[NORMAL_SIZE] = widgetToDoubleStr(screenNormalED);
1014 rc.font_sizes[LARGE_SIZE] = widgetToDoubleStr(screenLargeED);
1015 rc.font_sizes[LARGER_SIZE] = widgetToDoubleStr(screenLargerED);
1016 rc.font_sizes[LARGEST_SIZE] = widgetToDoubleStr(screenLargestED);
1017 rc.font_sizes[HUGE_SIZE] = widgetToDoubleStr(screenHugeED);
1018 rc.font_sizes[HUGER_SIZE] = widgetToDoubleStr(screenHugerED);
1022 void PrefScreenFonts::updateRC(LyXRC const & rc)
1024 setComboxFont(screenRomanCO, rc.roman_font_name,
1025 rc.roman_font_foundry);
1026 setComboxFont(screenSansCO, rc.sans_font_name,
1027 rc.sans_font_foundry);
1028 setComboxFont(screenTypewriterCO, rc.typewriter_font_name,
1029 rc.typewriter_font_foundry);
1031 selectRoman(screenRomanCO->currentText());
1032 selectSans(screenSansCO->currentText());
1033 selectTypewriter(screenTypewriterCO->currentText());
1035 screenZoomSB->setValue(rc.defaultZoom);
1036 updateScreenFontSizes(rc);
1040 void PrefScreenFonts::updateScreenFontSizes(LyXRC const & rc)
1042 doubleToWidget(screenTinyED, rc.font_sizes[TINY_SIZE]);
1043 doubleToWidget(screenSmallestED, rc.font_sizes[SCRIPT_SIZE]);
1044 doubleToWidget(screenSmallerED, rc.font_sizes[FOOTNOTE_SIZE]);
1045 doubleToWidget(screenSmallED, rc.font_sizes[SMALL_SIZE]);
1046 doubleToWidget(screenNormalED, rc.font_sizes[NORMAL_SIZE]);
1047 doubleToWidget(screenLargeED, rc.font_sizes[LARGE_SIZE]);
1048 doubleToWidget(screenLargerED, rc.font_sizes[LARGER_SIZE]);
1049 doubleToWidget(screenLargestED, rc.font_sizes[LARGEST_SIZE]);
1050 doubleToWidget(screenHugeED, rc.font_sizes[HUGE_SIZE]);
1051 doubleToWidget(screenHugerED, rc.font_sizes[HUGER_SIZE]);
1055 void PrefScreenFonts::selectRoman(const QString & name)
1057 screenRomanFE->set(QFont(name), name);
1061 void PrefScreenFonts::selectSans(const QString & name)
1063 screenSansFE->set(QFont(name), name);
1067 void PrefScreenFonts::selectTypewriter(const QString & name)
1069 screenTypewriterFE->set(QFont(name), name);
1073 /////////////////////////////////////////////////////////////////////
1077 /////////////////////////////////////////////////////////////////////
1080 PrefColors::PrefColors(GuiPreferences * form)
1081 : PrefModule(catLookAndFeel, N_("Colors"), form)
1085 // FIXME: all of this initialization should be put into the controller.
1086 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg113301.html
1087 // for some discussion of why that is not trivial.
1088 QPixmap icon(32, 32);
1089 for (int i = 0; i < Color_ignore; ++i) {
1090 ColorCode lc = static_cast<ColorCode>(i);
1091 if (lc == Color_none
1092 || lc == Color_black
1093 || lc == Color_white
1095 || lc == Color_brown
1097 || lc == Color_darkgray
1099 || lc == Color_green
1100 || lc == Color_lightgray
1102 || lc == Color_magenta
1103 || lc == Color_olive
1104 || lc == Color_orange
1106 || lc == Color_purple
1109 || lc == Color_violet
1110 || lc == Color_yellow
1111 || lc == Color_inherit
1112 || lc == Color_ignore)
1114 lcolors_.push_back(lc);
1116 sort(lcolors_.begin(), lcolors_.end(), ColorSorter);
1117 vector<ColorCode>::const_iterator cit = lcolors_.begin();
1118 vector<ColorCode>::const_iterator const end = lcolors_.end();
1119 for (; cit != end; ++cit) {
1120 (void) new QListWidgetItem(QIcon(icon),
1121 toqstr(lcolor.getGUIName(*cit)), lyxObjectsLW);
1123 curcolors_.resize(lcolors_.size());
1124 newcolors_.resize(lcolors_.size());
1125 // End initialization
1127 connect(colorChangePB, SIGNAL(clicked()),
1128 this, SLOT(changeColor()));
1129 connect(colorResetPB, SIGNAL(clicked()),
1130 this, SLOT(resetColor()));
1131 connect(colorResetAllPB, SIGNAL(clicked()),
1132 this, SLOT(resetAllColor()));
1133 connect(lyxObjectsLW, SIGNAL(itemSelectionChanged()),
1134 this, SLOT(changeLyxObjectsSelection()));
1135 connect(lyxObjectsLW, SIGNAL(itemActivated(QListWidgetItem*)),
1136 this, SLOT(changeColor()));
1137 connect(syscolorsCB, SIGNAL(toggled(bool)),
1138 this, SIGNAL(changed()));
1139 connect(syscolorsCB, SIGNAL(toggled(bool)),
1140 this, SLOT(changeSysColor()));
1144 void PrefColors::applyRC(LyXRC & rc) const
1148 for (unsigned int i = 0; i < lcolors_.size(); ++i)
1149 if (curcolors_[i] != newcolors_[i])
1150 form_->setColor(lcolors_[i], newcolors_[i]);
1151 rc.use_system_colors = syscolorsCB->isChecked();
1153 if (oldrc.use_system_colors != rc.use_system_colors)
1154 guiApp->colorCache().clear();
1158 void PrefColors::updateRC(LyXRC const & rc)
1160 for (size_type i = 0; i < lcolors_.size(); ++i) {
1161 QColor color = guiApp->colorCache().get(lcolors_[i], false);
1162 QPixmap coloritem(32, 32);
1163 coloritem.fill(color);
1164 lyxObjectsLW->item(int(i))->setIcon(QIcon(coloritem));
1165 newcolors_[i] = curcolors_[i] = color.name();
1167 syscolorsCB->setChecked(rc.use_system_colors);
1168 changeLyxObjectsSelection();
1170 setDisabledResets();
1174 void PrefColors::changeColor()
1176 int const row = lyxObjectsLW->currentRow();
1182 QString const color = newcolors_[size_t(row)];
1183 QColor const c = QColorDialog::getColor(QColor(color), qApp->focusWidget());
1185 if (setColor(row, c, color)) {
1186 setDisabledResets();
1193 void PrefColors::resetColor()
1195 int const row = lyxObjectsLW->currentRow();
1201 QString const color = newcolors_[size_t(row)];
1202 QColor const c = getDefaultColorByRow(row);
1204 if (setColor(row, c, color)) {
1205 setDisabledResets();
1212 void PrefColors::resetAllColor()
1214 bool isChanged = false;
1216 colorResetAllPB->setDisabled(true);
1218 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1219 QString const color = newcolors_[size_t(irow)];
1220 QColor const c = getDefaultColorByRow(irow);
1222 if (setColor(irow, c, color))
1227 setDisabledResets();
1234 bool PrefColors::setColor(int const row, QColor const & new_color,
1235 QString const & old_color)
1237 if (new_color.isValid() && new_color.name() != old_color) {
1238 newcolors_[size_t(row)] = new_color.name();
1239 QPixmap coloritem(32, 32);
1240 coloritem.fill(new_color);
1241 lyxObjectsLW->item(row)->setIcon(QIcon(coloritem));
1248 void PrefColors::setDisabledResets()
1250 int const row = lyxObjectsLW->currentRow();
1251 // set disable reset buttons ...
1253 colorResetPB->setDisabled(isDefaultColor(row, newcolors_[size_t(row)]));
1255 colorResetAllPB->setDisabled(true);
1257 // ... in between process qt events to give quicker visual feedback to the user ...
1258 guiApp->processEvents();
1260 // ... set disable Reset All button
1261 for (int irow = 0, count = lyxObjectsLW->count(); irow < count; ++irow) {
1262 if (!isDefaultColor(irow, newcolors_[size_t(irow)])) {
1263 colorResetAllPB->setDisabled(false);
1264 // the break condition might hide performance issues
1265 // if a non-default color is at the top of the list
1272 bool PrefColors::isDefaultColor(int const row, QString const & color)
1274 return color == getDefaultColorByRow(row).name();
1278 QColor PrefColors::getDefaultColorByRow(int const row)
1280 ColorSet const defaultcolor;
1281 return defaultcolor.getX11HexName(lcolors_[size_t(row)],
1282 guiApp->colorCache().isDarkMode()).c_str();
1286 void PrefColors::changeSysColor()
1288 for (int row = 0 ; row < lyxObjectsLW->count() ; ++row) {
1289 // skip colors that are taken from system palette
1290 bool const disable = syscolorsCB->isChecked()
1291 && guiApp->colorCache().isSystem(lcolors_[size_t(row)]);
1293 QListWidgetItem * const item = lyxObjectsLW->item(row);
1294 Qt::ItemFlags const flags = item->flags();
1297 item->setFlags(flags & ~Qt::ItemIsEnabled);
1299 item->setFlags(flags | Qt::ItemIsEnabled);
1304 void PrefColors::changeLyxObjectsSelection()
1306 int currentRow = lyxObjectsLW->currentRow();
1307 colorChangePB->setDisabled(currentRow < 0);
1310 colorResetPB->setDisabled(true);
1312 colorResetPB->setDisabled(
1313 isDefaultColor(currentRow, newcolors_[size_t(currentRow)]));
1317 /////////////////////////////////////////////////////////////////////
1321 /////////////////////////////////////////////////////////////////////
1323 PrefDisplay::PrefDisplay(GuiPreferences * form)
1324 : PrefModule(catLookAndFeel, N_("Display"), form)
1327 connect(displayGraphicsCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1328 connect(instantPreviewCO, SIGNAL(activated(int)), this, SIGNAL(changed()));
1329 connect(previewSizeSB, SIGNAL(valueChanged(double)), this, SIGNAL(changed()));
1330 connect(paragraphMarkerCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1331 connect(ctAdditionsUnderlinedCB, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
1335 void PrefDisplay::on_instantPreviewCO_currentIndexChanged(int index)
1337 previewSizeSB->setEnabled(index != 0);
1341 void PrefDisplay::applyRC(LyXRC & rc) const
1343 switch (instantPreviewCO->currentIndex()) {
1345 rc.preview = LyXRC::PREVIEW_OFF;
1348 rc.preview = LyXRC::PREVIEW_NO_MATH;
1351 rc.preview = LyXRC::PREVIEW_ON;
1355 rc.display_graphics = displayGraphicsCB->isChecked();
1356 rc.preview_scale_factor = previewSizeSB->value();
1357 rc.paragraph_markers = paragraphMarkerCB->isChecked();
1358 rc.ct_additions_underlined = ctAdditionsUnderlinedCB->isChecked();
1360 // FIXME!! The graphics cache no longer has a changeDisplay method.
1362 if (old_value != rc.display_graphics) {
1363 graphics::GCache & gc = graphics::GCache::get();
1370 void PrefDisplay::updateRC(LyXRC const & rc)
1372 switch (rc.preview) {
1373 case LyXRC::PREVIEW_OFF:
1374 instantPreviewCO->setCurrentIndex(0);
1376 case LyXRC::PREVIEW_NO_MATH :
1377 instantPreviewCO->setCurrentIndex(1);
1379 case LyXRC::PREVIEW_ON :
1380 instantPreviewCO->setCurrentIndex(2);
1384 displayGraphicsCB->setChecked(rc.display_graphics);
1385 previewSizeSB->setValue(rc.preview_scale_factor);
1386 paragraphMarkerCB->setChecked(rc.paragraph_markers);
1387 ctAdditionsUnderlinedCB->setChecked(rc.ct_additions_underlined);
1388 previewSizeSB->setEnabled(
1390 && rc.preview != LyXRC::PREVIEW_OFF);
1394 /////////////////////////////////////////////////////////////////////
1398 /////////////////////////////////////////////////////////////////////
1400 PrefPaths::PrefPaths(GuiPreferences * form)
1401 : PrefModule(QString(), N_("Paths"), form)
1405 connect(workingDirPB, SIGNAL(clicked()), this, SLOT(selectWorkingdir()));
1406 connect(workingDirED, SIGNAL(textChanged(QString)),
1407 this, SIGNAL(changed()));
1409 connect(templateDirPB, SIGNAL(clicked()), this, SLOT(selectTemplatedir()));
1410 connect(templateDirED, SIGNAL(textChanged(QString)),
1411 this, SIGNAL(changed()));
1413 connect(exampleDirPB, SIGNAL(clicked()), this, SLOT(selectExampledir()));
1414 connect(exampleDirED, SIGNAL(textChanged(QString)),
1415 this, SIGNAL(changed()));
1417 connect(backupDirPB, SIGNAL(clicked()), this, SLOT(selectBackupdir()));
1418 connect(backupDirED, SIGNAL(textChanged(QString)),
1419 this, SIGNAL(changed()));
1421 connect(lyxserverDirPB, SIGNAL(clicked()), this, SLOT(selectLyxPipe()));
1422 connect(lyxserverDirED, SIGNAL(textChanged(QString)),
1423 this, SIGNAL(changed()));
1425 connect(thesaurusDirPB, SIGNAL(clicked()), this, SLOT(selectThesaurusdir()));
1426 connect(thesaurusDirED, SIGNAL(textChanged(QString)),
1427 this, SIGNAL(changed()));
1429 connect(tempDirPB, SIGNAL(clicked()), this, SLOT(selectTempdir()));
1430 connect(tempDirED, SIGNAL(textChanged(QString)),
1431 this, SIGNAL(changed()));
1433 #if defined(USE_HUNSPELL)
1434 connect(hunspellDirPB, SIGNAL(clicked()), this, SLOT(selectHunspelldir()));
1435 connect(hunspellDirED, SIGNAL(textChanged(QString)),
1436 this, SIGNAL(changed()));
1438 hunspellDirPB->setEnabled(false);
1439 hunspellDirED->setEnabled(false);
1442 connect(pathPrefixED, SIGNAL(textChanged(QString)),
1443 this, SIGNAL(changed()));
1445 connect(texinputsPrefixED, SIGNAL(textChanged(QString)),
1446 this, SIGNAL(changed()));
1448 pathPrefixED->setValidator(new NoNewLineValidator(pathPrefixED));
1449 texinputsPrefixED->setValidator(new NoNewLineValidator(texinputsPrefixED));
1453 void PrefPaths::applyRC(LyXRC & rc) const
1455 rc.document_path = internal_path(fromqstr(workingDirED->text()));
1456 rc.example_path = internal_path(fromqstr(exampleDirED->text()));
1457 rc.template_path = internal_path(fromqstr(templateDirED->text()));
1458 rc.backupdir_path = internal_path(fromqstr(backupDirED->text()));
1459 rc.tempdir_path = internal_path(fromqstr(tempDirED->text()));
1460 rc.thesaurusdir_path = internal_path(fromqstr(thesaurusDirED->text()));
1461 rc.hunspelldir_path = internal_path(fromqstr(hunspellDirED->text()));
1462 rc.path_prefix = internal_path_list(fromqstr(pathPrefixED->text()));
1463 rc.texinputs_prefix = internal_path_list(fromqstr(texinputsPrefixED->text()));
1464 // FIXME: should be a checkbox only
1465 rc.lyxpipes = internal_path(fromqstr(lyxserverDirED->text()));
1469 void PrefPaths::updateRC(LyXRC const & rc)
1471 workingDirED->setText(toqstr(external_path(rc.document_path)));
1472 exampleDirED->setText(toqstr(external_path(rc.example_path)));
1473 templateDirED->setText(toqstr(external_path(rc.template_path)));
1474 backupDirED->setText(toqstr(external_path(rc.backupdir_path)));
1475 tempDirED->setText(toqstr(external_path(rc.tempdir_path)));
1476 thesaurusDirED->setText(toqstr(external_path(rc.thesaurusdir_path)));
1477 hunspellDirED->setText(toqstr(external_path(rc.hunspelldir_path)));
1478 pathPrefixED->setText(toqstr(external_path_list(rc.path_prefix)));
1479 texinputsPrefixED->setText(toqstr(external_path_list(rc.texinputs_prefix)));
1480 // FIXME: should be a checkbox only
1481 lyxserverDirED->setText(toqstr(external_path(rc.lyxpipes)));
1485 void PrefPaths::selectExampledir()
1487 QString file = browseDir(internalPath(exampleDirED->text()),
1488 qt_("Select directory for example files"));
1489 if (!file.isEmpty())
1490 exampleDirED->setText(file);
1494 void PrefPaths::selectTemplatedir()
1496 QString file = browseDir(internalPath(templateDirED->text()),
1497 qt_("Select a document templates directory"));
1498 if (!file.isEmpty())
1499 templateDirED->setText(file);
1503 void PrefPaths::selectTempdir()
1505 QString file = browseDir(internalPath(tempDirED->text()),
1506 qt_("Select a temporary directory"));
1507 if (!file.isEmpty())
1508 tempDirED->setText(file);
1512 void PrefPaths::selectBackupdir()
1514 QString file = browseDir(internalPath(backupDirED->text()),
1515 qt_("Select a backups directory"));
1516 if (!file.isEmpty())
1517 backupDirED->setText(file);
1521 void PrefPaths::selectWorkingdir()
1523 QString file = browseDir(internalPath(workingDirED->text()),
1524 qt_("Select a document directory"));
1525 if (!file.isEmpty())
1526 workingDirED->setText(file);
1530 void PrefPaths::selectThesaurusdir()
1532 QString file = browseDir(internalPath(thesaurusDirED->text()),
1533 qt_("Set the path to the thesaurus dictionaries"));
1534 if (!file.isEmpty())
1535 thesaurusDirED->setText(file);
1539 void PrefPaths::selectHunspelldir()
1541 QString file = browseDir(internalPath(hunspellDirED->text()),
1542 qt_("Set the path to the Hunspell dictionaries"));
1543 if (!file.isEmpty())
1544 hunspellDirED->setText(file);
1548 void PrefPaths::selectLyxPipe()
1550 QString file = form_->browse(internalPath(lyxserverDirED->text()),
1551 qt_("Give a filename for the LyX server pipe"));
1552 if (!file.isEmpty())
1553 lyxserverDirED->setText(file);
1557 /////////////////////////////////////////////////////////////////////
1561 /////////////////////////////////////////////////////////////////////
1563 PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
1564 : PrefModule(catLanguage, N_("Spellchecker"), form)
1568 // FIXME: this check should test the target platform (darwin)
1569 #if defined(USE_MACOSX_PACKAGING)
1570 spellcheckerCB->addItem(qt_("Native"), QString("native"));
1571 #define CONNECT_APPLESPELL
1573 #undef CONNECT_APPLESPELL
1575 #if defined(USE_ASPELL)
1576 spellcheckerCB->addItem(qt_("Aspell"), QString("aspell"));
1578 #if defined(USE_ENCHANT)
1579 spellcheckerCB->addItem(qt_("Enchant"), QString("enchant"));
1581 #if defined(USE_HUNSPELL)
1582 spellcheckerCB->addItem(qt_("Hunspell"), QString("hunspell"));
1585 #if defined(CONNECT_APPLESPELL) || defined(USE_ASPELL) || defined(USE_ENCHANT) || defined(USE_HUNSPELL)
1586 connect(spellcheckerCB, SIGNAL(currentIndexChanged(int)),
1587 this, SIGNAL(changed()));
1588 connect(altLanguageED, SIGNAL(textChanged(QString)),
1589 this, SIGNAL(changed()));
1590 connect(escapeCharactersED, SIGNAL(textChanged(QString)),
1591 this, SIGNAL(changed()));
1592 connect(compoundWordCB, SIGNAL(clicked()),
1593 this, SIGNAL(changed()));
1594 connect(spellcheckContinuouslyCB, SIGNAL(clicked()),
1595 this, SIGNAL(changed()));
1596 connect(spellcheckNotesCB, SIGNAL(clicked()),
1597 this, SIGNAL(changed()));
1599 altLanguageED->setValidator(new NoNewLineValidator(altLanguageED));
1600 escapeCharactersED->setValidator(new NoNewLineValidator(escapeCharactersED));
1602 spellcheckerCB->setEnabled(false);
1603 altLanguageED->setEnabled(false);
1604 escapeCharactersED->setEnabled(false);
1605 compoundWordCB->setEnabled(false);
1606 spellcheckContinuouslyCB->setEnabled(false);
1607 spellcheckNotesCB->setEnabled(false);
1612 void PrefSpellchecker::applyRC(LyXRC & rc) const
1614 string const speller = fromqstr(spellcheckerCB->
1615 itemData(spellcheckerCB->currentIndex()).toString());
1616 if (!speller.empty())
1617 rc.spellchecker = speller;
1618 rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
1619 rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
1620 rc.spellchecker_accept_compound = compoundWordCB->isChecked();
1621 rc.spellcheck_continuously = spellcheckContinuouslyCB->isChecked();
1622 rc.spellcheck_notes = spellcheckNotesCB->isChecked();
1626 void PrefSpellchecker::updateRC(LyXRC const & rc)
1628 spellcheckerCB->setCurrentIndex(
1629 spellcheckerCB->findData(toqstr(rc.spellchecker)));
1630 altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
1631 escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
1632 compoundWordCB->setChecked(rc.spellchecker_accept_compound);
1633 spellcheckContinuouslyCB->setChecked(rc.spellcheck_continuously);
1634 spellcheckNotesCB->setChecked(rc.spellcheck_notes);
1638 void PrefSpellchecker::on_spellcheckerCB_currentIndexChanged(int index)
1640 QString spellchecker = spellcheckerCB->itemData(index).toString();
1642 compoundWordCB->setEnabled(spellchecker == QString("aspell"));
1647 /////////////////////////////////////////////////////////////////////
1651 /////////////////////////////////////////////////////////////////////
1654 PrefConverters::PrefConverters(GuiPreferences * form)
1655 : PrefModule(catFiles, N_("Converters"), form)
1659 connect(converterNewPB, SIGNAL(clicked()),
1660 this, SLOT(updateConverter()));
1661 connect(converterRemovePB, SIGNAL(clicked()),
1662 this, SLOT(removeConverter()));
1663 connect(converterModifyPB, SIGNAL(clicked()),
1664 this, SLOT(updateConverter()));
1665 connect(convertersLW, SIGNAL(currentRowChanged(int)),
1666 this, SLOT(switchConverter()));
1667 #if QT_VERSION < 0x050e00
1668 connect(converterFromCO, SIGNAL(activated(QString)),
1669 this, SLOT(changeConverter()));
1670 connect(converterToCO, SIGNAL(activated(QString)),
1671 this, SLOT(changeConverter()));
1673 connect(converterFromCO, SIGNAL(textActivated(QString)),
1674 this, SLOT(changeConverter()));
1675 connect(converterToCO, SIGNAL(textActivated(QString)),
1676 this, SLOT(changeConverter()));
1678 connect(converterED, SIGNAL(textEdited(QString)),
1679 this, SLOT(changeConverter()));
1680 connect(converterFlagED, SIGNAL(textEdited(QString)),
1681 this, SLOT(changeConverter()));
1682 connect(converterNewPB, SIGNAL(clicked()),
1683 this, SIGNAL(changed()));
1684 connect(converterRemovePB, SIGNAL(clicked()),
1685 this, SIGNAL(changed()));
1686 connect(converterModifyPB, SIGNAL(clicked()),
1687 this, SIGNAL(changed()));
1688 connect(maxAgeLE, SIGNAL(textEdited(QString)),
1689 this, SIGNAL(changed()));
1690 connect(needauthForbiddenCB, SIGNAL(toggled(bool)),
1691 this, SIGNAL(changed()));
1693 converterED->setValidator(new NoNewLineValidator(converterED));
1694 converterFlagED->setValidator(new NoNewLineValidator(converterFlagED));
1695 maxAgeLE->setValidator(new QDoubleValidator(0, HUGE_VAL, 6, maxAgeLE));
1696 //converterDefGB->setFocusProxy(convertersLW);
1700 void PrefConverters::applyRC(LyXRC & rc) const
1702 rc.use_converter_cache = cacheCB->isChecked();
1703 rc.use_converter_needauth_forbidden = needauthForbiddenCB->isChecked();
1704 rc.use_converter_needauth = needauthCB->isChecked();
1705 rc.converter_cache_maxage = int(widgetToDouble(maxAgeLE) * 86400.0);
1709 static void setCheckboxBlockSignals(QCheckBox *cb, bool checked) {
1710 cb->blockSignals(true);
1711 cb->setChecked(checked);
1712 cb->blockSignals(false);
1716 void PrefConverters::updateRC(LyXRC const & rc)
1718 cacheCB->setChecked(rc.use_converter_cache);
1719 needauthForbiddenCB->setChecked(rc.use_converter_needauth_forbidden);
1720 setCheckboxBlockSignals(needauthCB, rc.use_converter_needauth);
1722 doubleToWidget(maxAgeLE, (double(rc.converter_cache_maxage) / 86400.0), 'g', 6);
1727 void PrefConverters::updateGui()
1729 QString const pattern("%1 -> %2");
1730 form_->formats().sort();
1731 form_->converters().update(form_->formats());
1732 // save current selection
1735 .arg(converterFromCO->currentText())
1736 .arg(converterToCO->currentText());
1738 converterFromCO->clear();
1739 converterToCO->clear();
1741 for (Format const & f : form_->formats()) {
1742 QString const name = toqstr(translateIfPossible(f.prettyname()));
1743 converterFromCO->addItem(name);
1744 converterToCO->addItem(name);
1747 // currentRowChanged(int) is also triggered when updating the listwidget
1748 // block signals to avoid unnecessary calls to switchConverter()
1749 convertersLW->blockSignals(true);
1750 convertersLW->clear();
1752 for (Converter const & c : form_->converters()) {
1753 QString const name =
1755 .arg(toqstr(translateIfPossible(c.From()->prettyname())))
1756 .arg(toqstr(translateIfPossible(c.To()->prettyname())));
1757 int type = form_->converters().getNumber(c.From()->name(),
1759 new QListWidgetItem(name, convertersLW, type);
1761 convertersLW->sortItems(Qt::AscendingOrder);
1762 convertersLW->blockSignals(false);
1764 // restore selection
1765 if (current != pattern.arg(QString()).arg(QString())) {
1766 QList<QListWidgetItem *> const item =
1767 convertersLW->findItems(current, Qt::MatchExactly);
1768 if (!item.isEmpty())
1769 convertersLW->setCurrentItem(item.at(0));
1772 // select first element if restoring failed
1773 if (convertersLW->currentRow() == -1)
1774 convertersLW->setCurrentRow(0);
1780 void PrefConverters::switchConverter()
1782 int const cnr = convertersLW->currentItem()->type();
1783 Converter const & c(form_->converters().get(cnr));
1784 converterFromCO->setCurrentIndex(form_->formats().getNumber(c.from()));
1785 converterToCO->setCurrentIndex(form_->formats().getNumber(c.to()));
1786 converterED->setText(toqstr(c.command()));
1787 converterFlagED->setText(toqstr(c.flags()));
1793 void PrefConverters::changeConverter()
1799 void PrefConverters::updateButtons()
1801 if (form_->formats().empty())
1803 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1804 Format const & to = form_->formats().get(converterToCO->currentIndex());
1805 int const sel = form_->converters().getNumber(from.name(), to.name());
1806 bool const known = sel >= 0;
1807 bool const valid = !(converterED->text().isEmpty()
1808 || from.name() == to.name());
1813 if (convertersLW->count() > 0) {
1814 int const cnr = convertersLW->currentItem()->type();
1815 Converter const & c = form_->converters().get(cnr);
1816 old_command = c.command();
1817 old_flag = c.flags();
1820 string const new_command = fromqstr(converterED->text());
1821 string const new_flag = fromqstr(converterFlagED->text());
1823 bool modified = (old_command != new_command || old_flag != new_flag);
1825 converterModifyPB->setEnabled(valid && known && modified);
1826 converterNewPB->setEnabled(valid && !known);
1827 converterRemovePB->setEnabled(known);
1829 maxAgeLE->setEnabled(cacheCB->isChecked());
1830 maxAgeLA->setEnabled(cacheCB->isChecked());
1835 // specify unique from/to or it doesn't appear. This is really bad UI
1836 // this is why we can use the same function for both new and modify
1837 void PrefConverters::updateConverter()
1839 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1840 Format const & to = form_->formats().get(converterToCO->currentIndex());
1841 string const flags = fromqstr(converterFlagED->text());
1842 string const command = fromqstr(converterED->text());
1844 Converter const * old =
1845 form_->converters().getConverter(from.name(), to.name());
1846 form_->converters().add(from.name(), to.name(), command, flags);
1849 form_->converters().updateLast(form_->formats());
1853 // Remove all files created by this converter from the cache, since
1854 // the modified converter might create different files.
1855 ConverterCache::get().remove_all(from.name(), to.name());
1859 void PrefConverters::removeConverter()
1861 Format const & from = form_->formats().get(converterFromCO->currentIndex());
1862 Format const & to = form_->formats().get(converterToCO->currentIndex());
1863 form_->converters().erase(from.name(), to.name());
1867 // Remove all files created by this converter from the cache, since
1868 // a possible new converter might create different files.
1869 ConverterCache::get().remove_all(from.name(), to.name());
1873 void PrefConverters::on_cacheCB_stateChanged(int state)
1875 maxAgeLE->setEnabled(state == Qt::Checked);
1876 maxAgeLA->setEnabled(state == Qt::Checked);
1881 void PrefConverters::on_needauthForbiddenCB_toggled(bool checked)
1883 needauthCB->setEnabled(!checked);
1887 void PrefConverters::on_needauthCB_toggled(bool checked)
1894 int ret = frontend::Alert::prompt(
1895 _("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!"),
1896 0, 0, _("&No"), _("&Yes"));
1900 setCheckboxBlockSignals(needauthCB, true);
1904 /////////////////////////////////////////////////////////////////////
1908 /////////////////////////////////////////////////////////////////////
1910 class FormatValidator : public QValidator
1913 FormatValidator(QWidget *, Formats const & f);
1914 void fixup(QString & input) const override;
1915 QValidator::State validate(QString & input, int & pos) const override;
1917 virtual QString toString(Format const & format) const = 0;
1919 Formats const & formats_;
1923 FormatValidator::FormatValidator(QWidget * parent, Formats const & f)
1924 : QValidator(parent), formats_(f)
1929 void FormatValidator::fixup(QString & input) const
1931 Formats::const_iterator cit = formats_.begin();
1932 Formats::const_iterator end = formats_.end();
1933 for (; cit != end; ++cit) {
1934 QString const name = toString(*cit);
1935 if (distance(formats_.begin(), cit) == nr()) {
1943 QValidator::State FormatValidator::validate(QString & input, int & /*pos*/) const
1945 Formats::const_iterator cit = formats_.begin();
1946 Formats::const_iterator end = formats_.end();
1947 bool unknown = true;
1948 for (; unknown && cit != end; ++cit) {
1949 QString const name = toString(*cit);
1950 if (distance(formats_.begin(), cit) != nr())
1951 unknown = name != input;
1954 if (unknown && !input.isEmpty())
1955 return QValidator::Acceptable;
1957 return QValidator::Intermediate;
1961 int FormatValidator::nr() const
1963 QComboBox * p = qobject_cast<QComboBox *>(parent());
1964 return p->itemData(p->currentIndex()).toInt();
1968 /////////////////////////////////////////////////////////////////////
1970 // FormatNameValidator
1972 /////////////////////////////////////////////////////////////////////
1974 class FormatNameValidator : public FormatValidator
1977 FormatNameValidator(QWidget * parent, Formats const & f)
1978 : FormatValidator(parent, f)
1981 QString toString(Format const & format) const override
1983 return toqstr(format.name());
1988 /////////////////////////////////////////////////////////////////////
1990 // FormatPrettynameValidator
1992 /////////////////////////////////////////////////////////////////////
1994 class FormatPrettynameValidator : public FormatValidator
1997 FormatPrettynameValidator(QWidget * parent, Formats const & f)
1998 : FormatValidator(parent, f)
2001 QString toString(Format const & format) const override
2003 return toqstr(translateIfPossible(format.prettyname()));
2008 /////////////////////////////////////////////////////////////////////
2012 /////////////////////////////////////////////////////////////////////
2014 PrefFileformats::PrefFileformats(GuiPreferences * form)
2015 : PrefModule(catFiles, N_("File Formats"), form)
2019 formatED->setValidator(new FormatNameValidator(formatsCB, form_->formats()));
2020 formatsCB->setValidator(new FormatPrettynameValidator(formatsCB, form_->formats()));
2021 extensionsED->setValidator(new NoNewLineValidator(extensionsED));
2022 shortcutED->setValidator(new NoNewLineValidator(shortcutED));
2023 editorED->setValidator(new NoNewLineValidator(editorED));
2024 viewerED->setValidator(new NoNewLineValidator(viewerED));
2025 copierED->setValidator(new NoNewLineValidator(copierED));
2027 connect(documentCB, SIGNAL(clicked()),
2028 this, SLOT(setFlags()));
2029 connect(vectorCB, SIGNAL(clicked()),
2030 this, SLOT(setFlags()));
2031 connect(exportMenuCB, SIGNAL(clicked()),
2032 this, SLOT(setFlags()));
2033 connect(formatsCB->lineEdit(), SIGNAL(editingFinished()),
2034 this, SLOT(updatePrettyname()));
2035 connect(formatsCB->lineEdit(), SIGNAL(textEdited(QString)),
2036 this, SIGNAL(changed()));
2037 #if QT_VERSION < 0x050e00
2038 connect(defaultFormatCB, SIGNAL(activated(QString)),
2039 this, SIGNAL(changed()));
2040 connect(defaultOTFFormatCB, SIGNAL(activated(QString)),
2041 this, SIGNAL(changed()));
2042 connect(defaultPlatexFormatCB, SIGNAL(activated(QString)),
2043 this, SIGNAL(changed()));
2045 connect(defaultFormatCB, SIGNAL(textActivated(QString)),
2046 this, SIGNAL(changed()));
2047 connect(defaultOTFFormatCB, SIGNAL(textActivated(QString)),
2048 this, SIGNAL(changed()));
2049 connect(defaultPlatexFormatCB, SIGNAL(textActivated(QString)),
2050 this, SIGNAL(changed()));
2052 connect(viewerCO, SIGNAL(activated(int)),
2053 this, SIGNAL(changed()));
2054 connect(editorCO, SIGNAL(activated(int)),
2055 this, SIGNAL(changed()));
2061 string const l10n_shortcut(docstring const & prettyname, string const & shortcut)
2063 if (shortcut.empty())
2066 string l10n_format =
2067 to_utf8(_(to_utf8(prettyname) + '|' + shortcut));
2068 return split(l10n_format, '|');
2074 void PrefFileformats::applyRC(LyXRC & rc) const
2076 QString const default_format = defaultFormatCB->itemData(
2077 defaultFormatCB->currentIndex()).toString();
2078 rc.default_view_format = fromqstr(default_format);
2079 QString const default_otf_format = defaultOTFFormatCB->itemData(
2080 defaultOTFFormatCB->currentIndex()).toString();
2081 rc.default_otf_view_format = fromqstr(default_otf_format);
2082 QString const default_platex_format = defaultPlatexFormatCB->itemData(
2083 defaultPlatexFormatCB->currentIndex()).toString();
2084 rc.default_platex_view_format = fromqstr(default_platex_format);
2088 void PrefFileformats::updateRC(LyXRC const & rc)
2090 viewer_alternatives = rc.viewer_alternatives;
2091 editor_alternatives = rc.editor_alternatives;
2092 bool const init = defaultFormatCB->currentText().isEmpty();
2096 defaultFormatCB->findData(toqstr(rc.default_view_format));
2097 defaultFormatCB->setCurrentIndex(pos);
2098 pos = defaultOTFFormatCB->findData(toqstr(rc.default_otf_view_format));
2099 defaultOTFFormatCB->setCurrentIndex(pos);
2100 defaultOTFFormatCB->setCurrentIndex(pos);
2101 pos = defaultPlatexFormatCB->findData(toqstr(rc.default_platex_view_format));
2102 defaultPlatexFormatCB->setCurrentIndex(pos);
2103 defaultPlatexFormatCB->setCurrentIndex(pos);
2108 void PrefFileformats::updateView()
2110 QString const current = formatsCB->currentText();
2111 QString const current_def = defaultFormatCB->currentText();
2112 QString const current_def_otf = defaultOTFFormatCB->currentText();
2113 QString const current_def_platex = defaultPlatexFormatCB->currentText();
2115 // update comboboxes with formats
2116 formatsCB->blockSignals(true);
2117 defaultFormatCB->blockSignals(true);
2118 defaultOTFFormatCB->blockSignals(true);
2119 defaultPlatexFormatCB->blockSignals(true);
2121 defaultFormatCB->clear();
2122 defaultOTFFormatCB->clear();
2123 defaultPlatexFormatCB->clear();
2124 form_->formats().sort();
2125 for (Format const & f : form_->formats()) {
2126 QString const prettyname = toqstr(translateIfPossible(f.prettyname()));
2127 formatsCB->addItem(prettyname,
2128 QVariant(form_->formats().getNumber(f.name())));
2129 if (f.viewer().empty())
2131 if (form_->converters().isReachable("xhtml", f.name())
2132 || form_->converters().isReachable("dviluatex", f.name())
2133 || form_->converters().isReachable("luatex", f.name())
2134 || form_->converters().isReachable("xetex", f.name())) {
2135 defaultFormatCB->addItem(prettyname,
2136 QVariant(toqstr(f.name())));
2137 defaultOTFFormatCB->addItem(prettyname,
2138 QVariant(toqstr(f.name())));
2140 if (form_->converters().isReachable("latex", f.name())
2141 || form_->converters().isReachable("pdflatex", f.name()))
2142 defaultFormatCB->addItem(prettyname,
2143 QVariant(toqstr(f.name())));
2144 if (form_->converters().isReachable("platex", f.name()))
2145 defaultPlatexFormatCB->addItem(prettyname,
2146 QVariant(toqstr(f.name())));
2150 // restore selections
2151 int item = formatsCB->findText(current, Qt::MatchExactly);
2152 formatsCB->setCurrentIndex(item < 0 ? 0 : item);
2153 on_formatsCB_currentIndexChanged(item < 0 ? 0 : item);
2154 item = defaultFormatCB->findText(current_def, Qt::MatchExactly);
2155 defaultFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2156 item = defaultOTFFormatCB->findText(current_def_otf, Qt::MatchExactly);
2157 defaultOTFFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2158 item = defaultPlatexFormatCB->findText(current_def_platex, Qt::MatchExactly);
2159 defaultPlatexFormatCB->setCurrentIndex(item < 0 ? 0 : item);
2160 formatsCB->blockSignals(false);
2161 defaultFormatCB->blockSignals(false);
2162 defaultOTFFormatCB->blockSignals(false);
2163 defaultPlatexFormatCB->blockSignals(false);
2167 void PrefFileformats::on_formatsCB_currentIndexChanged(int i)
2169 if (form_->formats().empty())
2171 int const nr = formatsCB->itemData(i).toInt();
2172 Format const f = form_->formats().get(nr);
2174 formatED->setText(toqstr(f.name()));
2175 copierED->setText(toqstr(form_->movers().command(f.name())));
2176 extensionsED->setText(toqstr(f.extensions()));
2177 mimeED->setText(toqstr(f.mime()));
2178 shortcutED->setText(
2179 toqstr(l10n_shortcut(f.prettyname(), f.shortcut())));
2180 documentCB->setChecked((f.documentFormat()));
2181 vectorCB->setChecked((f.vectorFormat()));
2182 exportMenuCB->setChecked((f.inExportMenu()));
2183 exportMenuCB->setEnabled((f.documentFormat()));
2189 void PrefFileformats::setFlags()
2191 int flags = Format::none;
2192 if (documentCB->isChecked())
2193 flags |= Format::document;
2194 if (vectorCB->isChecked())
2195 flags |= Format::vector;
2196 if (exportMenuCB->isChecked())
2197 flags |= Format::export_menu;
2198 currentFormat().setFlags(flags);
2199 exportMenuCB->setEnabled(documentCB->isChecked());
2204 void PrefFileformats::on_copierED_textEdited(const QString & s)
2206 string const fmt = fromqstr(formatED->text());
2207 form_->movers().set(fmt, fromqstr(s));
2212 void PrefFileformats::on_extensionsED_textEdited(const QString & s)
2214 currentFormat().setExtensions(fromqstr(s));
2219 void PrefFileformats::on_viewerED_textEdited(const QString & s)
2221 currentFormat().setViewer(fromqstr(s));
2226 void PrefFileformats::on_editorED_textEdited(const QString & s)
2228 currentFormat().setEditor(fromqstr(s));
2233 void PrefFileformats::on_mimeED_textEdited(const QString & s)
2235 currentFormat().setMime(fromqstr(s));
2240 void PrefFileformats::on_shortcutED_textEdited(const QString & s)
2242 string const new_shortcut = fromqstr(s);
2243 if (new_shortcut == l10n_shortcut(currentFormat().prettyname(),
2244 currentFormat().shortcut()))
2246 currentFormat().setShortcut(new_shortcut);
2251 void PrefFileformats::on_formatED_editingFinished()
2253 string const newname = fromqstr(formatED->displayText());
2254 string const oldname = currentFormat().name();
2255 if (newname == oldname)
2257 if (form_->converters().formatIsUsed(oldname)) {
2258 Alert::error(_("Format in use"),
2259 _("You cannot change a format's short name "
2260 "if the format is used by a converter. "
2261 "Please remove the converter first."));
2266 currentFormat().setName(newname);
2271 void PrefFileformats::on_formatED_textChanged(const QString &)
2273 QString t = formatED->text();
2275 bool valid = formatED->validator()->validate(t, p) == QValidator::Acceptable;
2276 setValid(formatLA, valid);
2280 void PrefFileformats::on_formatsCB_editTextChanged(const QString &)
2282 QString t = formatsCB->currentText();
2284 bool valid = formatsCB->validator()->validate(t, p) == QValidator::Acceptable;
2285 setValid(formatsLA, valid);
2289 void PrefFileformats::updatePrettyname()
2291 QString const newname = formatsCB->currentText();
2292 if (newname == toqstr(translateIfPossible(currentFormat().prettyname())))
2295 currentFormat().setPrettyname(qstring_to_ucs4(newname));
2303 void updateComboBox(LyXRC::Alternatives const & alts,
2304 string const & fmt, QComboBox * combo)
2306 LyXRC::Alternatives::const_iterator it =
2308 if (it != alts.end()) {
2309 LyXRC::CommandSet const & cmds = it->second;
2310 LyXRC::CommandSet::const_iterator sit =
2312 LyXRC::CommandSet::const_iterator const sen =
2314 for (; sit != sen; ++sit) {
2315 QString const qcmd = toqstr(*sit);
2316 combo->addItem(qcmd, qcmd);
2323 void PrefFileformats::updateViewers()
2325 Format const f = currentFormat();
2326 viewerCO->blockSignals(true);
2328 viewerCO->addItem(qt_("None"), QString());
2329 if (os::canAutoOpenFile(f.extension(), os::VIEW))
2330 viewerCO->addItem(qt_("System Default"), QString("auto"));
2331 updateComboBox(viewer_alternatives, f.name(), viewerCO);
2332 viewerCO->addItem(qt_("Custom"), QString("custom viewer"));
2333 viewerCO->blockSignals(false);
2335 int pos = viewerCO->findData(toqstr(f.viewer()));
2338 viewerED->setEnabled(false);
2339 viewerCO->setCurrentIndex(pos);
2341 viewerED->setEnabled(true);
2342 viewerED->setText(toqstr(f.viewer()));
2343 viewerCO->setCurrentIndex(viewerCO->findData(toqstr("custom viewer")));
2348 void PrefFileformats::updateEditors()
2350 Format const f = currentFormat();
2351 editorCO->blockSignals(true);
2353 editorCO->addItem(qt_("None"), QString());
2354 if (os::canAutoOpenFile(f.extension(), os::EDIT))
2355 editorCO->addItem(qt_("System Default"), QString("auto"));
2356 updateComboBox(editor_alternatives, f.name(), editorCO);
2357 editorCO->addItem(qt_("Custom"), QString("custom editor"));
2358 editorCO->blockSignals(false);
2360 int pos = editorCO->findData(toqstr(f.editor()));
2363 editorED->setEnabled(false);
2364 editorCO->setCurrentIndex(pos);
2366 editorED->setEnabled(true);
2367 editorED->setText(toqstr(f.editor()));
2368 editorCO->setCurrentIndex(editorCO->findData(toqstr("custom editor")));
2373 void PrefFileformats::on_viewerCO_currentIndexChanged(int i)
2375 bool const custom = viewerCO->itemData(i).toString() == "custom viewer";
2376 viewerED->setEnabled(custom);
2378 currentFormat().setViewer(fromqstr(viewerCO->itemData(i).toString()));
2382 void PrefFileformats::on_editorCO_currentIndexChanged(int i)
2384 bool const custom = editorCO->itemData(i).toString() == "custom editor";
2385 editorED->setEnabled(custom);
2387 currentFormat().setEditor(fromqstr(editorCO->itemData(i).toString()));
2391 Format & PrefFileformats::currentFormat()
2393 int const i = formatsCB->currentIndex();
2394 int const nr = formatsCB->itemData(i).toInt();
2395 return form_->formats().get(nr);
2399 void PrefFileformats::on_formatNewPB_clicked()
2401 form_->formats().add("", "", docstring(), "", "", "", "", Format::none);
2403 formatsCB->setCurrentIndex(0);
2404 formatsCB->setFocus(Qt::OtherFocusReason);
2408 void PrefFileformats::on_formatRemovePB_clicked()
2410 int const i = formatsCB->currentIndex();
2411 int const nr = formatsCB->itemData(i).toInt();
2412 string const current_text = form_->formats().get(nr).name();
2413 if (form_->converters().formatIsUsed(current_text)) {
2414 Alert::error(_("Format in use"),
2415 _("Cannot remove a Format used by a Converter. "
2416 "Remove the converter first."));
2420 form_->formats().erase(current_text);
2423 on_formatsCB_editTextChanged(formatsCB->currentText());
2428 /////////////////////////////////////////////////////////////////////
2432 /////////////////////////////////////////////////////////////////////
2434 PrefLanguage::PrefLanguage(GuiPreferences * form)
2435 : PrefModule(catLanguage, N_("Language"), form)
2439 connect(visualCursorRB, SIGNAL(clicked()),
2440 this, SIGNAL(changed()));
2441 connect(logicalCursorRB, SIGNAL(clicked()),
2442 this, SIGNAL(changed()));
2443 connect(markForeignCB, SIGNAL(clicked()),
2444 this, SIGNAL(changed()));
2445 connect(respectOSkbdCB, SIGNAL(clicked()),
2446 this, SIGNAL(changed()));
2447 connect(explicitDocLangBeginCB, SIGNAL(clicked()),
2448 this, SIGNAL(changed()));
2449 connect(explicitDocLangEndCB, SIGNAL(clicked()),
2450 this, SIGNAL(changed()));
2451 connect(languagePackageCO, SIGNAL(activated(int)),
2452 this, SIGNAL(changed()));
2453 connect(languagePackageED, SIGNAL(textChanged(QString)),
2454 this, SIGNAL(changed()));
2455 connect(globalCB, SIGNAL(clicked()),
2456 this, SIGNAL(changed()));
2457 connect(startCommandED, SIGNAL(textChanged(QString)),
2458 this, SIGNAL(changed()));
2459 connect(endCommandED, SIGNAL(textChanged(QString)),
2460 this, SIGNAL(changed()));
2461 connect(uiLanguageCO, SIGNAL(activated(int)),
2462 this, SIGNAL(changed()));
2463 connect(defaultDecimalSepED, SIGNAL(textChanged(QString)),
2464 this, SIGNAL(changed()));
2465 connect(defaultDecimalSepCO, SIGNAL(activated(int)),
2466 this, SIGNAL(changed()));
2467 connect(defaultLengthUnitCO, SIGNAL(activated(int)),
2468 this, SIGNAL(changed()));
2470 languagePackageED->setValidator(new NoNewLineValidator(languagePackageED));
2471 startCommandED->setValidator(new NoNewLineValidator(startCommandED));
2472 endCommandED->setValidator(new NoNewLineValidator(endCommandED));
2474 #if QT_VERSION < 0x060000
2475 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this));
2477 defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this));
2479 defaultDecimalSepED->setMaxLength(1);
2481 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
2482 defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
2484 QAbstractItemModel * language_model = guiApp->languageModel();
2485 language_model->sort(0);
2486 uiLanguageCO->blockSignals(true);
2487 uiLanguageCO->clear();
2488 uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
2489 for (int i = 0; i != language_model->rowCount(); ++i) {
2490 QModelIndex index = language_model->index(i, 0);
2491 // Filter the list based on the available translation and add
2492 // each language code only once
2493 string const name = fromqstr(index.data(Qt::UserRole).toString());
2494 Language const * lang = languages.getLanguage(name);
2497 // never remove the currently selected language
2498 if (name != form->rc().gui_language
2499 && name != lyxrc.gui_language
2500 && (!Messages::available(lang->code())
2501 || !lang->hasGuiSupport()))
2503 uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
2504 index.data(Qt::UserRole).toString());
2506 uiLanguageCO->blockSignals(false);
2508 // FIXME: restore this when it works (see discussion in #6450).
2509 respectOSkbdCB->hide();
2513 void PrefLanguage::on_uiLanguageCO_currentIndexChanged(int)
2515 QMessageBox::information(this, qt_("LyX needs to be restarted!"),
2516 qt_("The change of user interface language will be fully "
2517 "effective only after a restart."));
2521 void PrefLanguage::on_languagePackageCO_currentIndexChanged(int i)
2524 languagePackageED->setText(save_langpack_);
2525 else if (!languagePackageED->text().isEmpty()) {
2526 save_langpack_ = languagePackageED->text();
2527 languagePackageED->clear();
2529 languagePackageED->setEnabled(i == 2);
2533 void PrefLanguage::on_defaultDecimalSepCO_currentIndexChanged(int i)
2535 defaultDecimalSepED->setEnabled(i == 1);
2539 void PrefLanguage::applyRC(LyXRC & rc) const
2541 rc.visual_cursor = visualCursorRB->isChecked();
2542 rc.mark_foreign_language = markForeignCB->isChecked();
2543 rc.respect_os_kbd_language = respectOSkbdCB->isChecked();
2544 rc.language_auto_begin = !explicitDocLangBeginCB->isChecked();
2545 rc.language_auto_end = !explicitDocLangEndCB->isChecked();
2546 int const p = languagePackageCO->currentIndex();
2548 rc.language_package_selection = LyXRC::LP_AUTO;
2550 rc.language_package_selection = LyXRC::LP_BABEL;
2552 rc.language_package_selection = LyXRC::LP_CUSTOM;
2554 rc.language_package_selection = LyXRC::LP_NONE;
2555 rc.language_custom_package = fromqstr(languagePackageED->text());
2556 rc.language_global_options = globalCB->isChecked();
2557 rc.language_command_begin = fromqstr(startCommandED->text());
2558 rc.language_command_end = fromqstr(endCommandED->text());
2559 rc.gui_language = fromqstr(
2560 uiLanguageCO->itemData(uiLanguageCO->currentIndex()).toString());
2561 if (defaultDecimalSepCO->currentIndex() == 0)
2562 rc.default_decimal_sep = "locale";
2564 rc.default_decimal_sep = fromqstr(defaultDecimalSepED->text());
2565 rc.default_length_unit = (Length::UNIT) defaultLengthUnitCO->itemData(defaultLengthUnitCO->currentIndex()).toInt();
2569 void PrefLanguage::updateRC(LyXRC const & rc)
2571 if (rc.visual_cursor)
2572 visualCursorRB->setChecked(true);
2574 logicalCursorRB->setChecked(true);
2575 markForeignCB->setChecked(rc.mark_foreign_language);
2576 respectOSkbdCB->setChecked(rc.respect_os_kbd_language);
2577 explicitDocLangBeginCB->setChecked(!rc.language_auto_begin);
2578 explicitDocLangEndCB->setChecked(!rc.language_auto_end);
2579 languagePackageCO->setCurrentIndex(rc.language_package_selection);
2580 if (languagePackageCO->currentIndex() == 2) {
2581 languagePackageED->setText(toqstr(rc.language_custom_package));
2582 languagePackageED->setEnabled(true);
2584 languagePackageED->clear();
2585 save_langpack_ = toqstr(rc.language_custom_package);
2586 languagePackageED->setEnabled(false);
2588 defaultDecimalSepED->setEnabled(defaultDecimalSepCO->currentIndex() == 1);
2589 globalCB->setChecked(rc.language_global_options);
2590 startCommandED->setText(toqstr(rc.language_command_begin));
2591 endCommandED->setText(toqstr(rc.language_command_end));
2592 if (rc.default_decimal_sep == "locale") {
2593 defaultDecimalSepCO->setCurrentIndex(0);
2594 defaultDecimalSepED->clear();
2596 defaultDecimalSepCO->setCurrentIndex(1);
2597 defaultDecimalSepED->setText(toqstr(rc.default_decimal_sep));
2599 int pos = defaultLengthUnitCO->findData(int(rc.default_length_unit));
2600 defaultLengthUnitCO->setCurrentIndex(pos);
2602 pos = uiLanguageCO->findData(toqstr(rc.gui_language));
2603 uiLanguageCO->blockSignals(true);
2604 uiLanguageCO->setCurrentIndex(pos);
2605 uiLanguageCO->blockSignals(false);
2609 /////////////////////////////////////////////////////////////////////
2611 // PrefUserInterface
2613 /////////////////////////////////////////////////////////////////////
2615 PrefUserInterface::PrefUserInterface(GuiPreferences * form)
2616 : PrefModule(catLookAndFeel, N_("User Interface"), form)
2620 connect(uiFilePB, SIGNAL(clicked()),
2621 this, SLOT(selectUi()));
2622 connect(uiFileED, SIGNAL(textChanged(QString)),
2623 this, SIGNAL(changed()));
2624 connect(iconSetCO, SIGNAL(activated(int)),
2625 this, SIGNAL(changed()));
2626 connect(useSystemThemeIconsCB, SIGNAL(clicked()),
2627 this, SIGNAL(changed()));
2628 connect(lastfilesSB, SIGNAL(valueChanged(int)),
2629 this, SIGNAL(changed()));
2630 connect(tooltipCB, SIGNAL(toggled(bool)),
2631 this, SIGNAL(changed()));
2632 lastfilesSB->setMaximum(maxlastfiles);
2634 iconSetCO->addItem(qt_("Default"), QString());
2635 iconSetCO->addItem(qt_("Classic"), "classic");
2636 iconSetCO->addItem(qt_("Oxygen"), "oxygen");
2638 #if QT_VERSION >= 0x040600
2639 if (guiApp->platformName() != "qt4x11"
2640 && guiApp->platformName() != "xcb"
2641 && !guiApp->platformName().contains("wayland"))
2643 useSystemThemeIconsCB->hide();
2647 void PrefUserInterface::applyRC(LyXRC & rc) const
2649 rc.icon_set = fromqstr(iconSetCO->itemData(
2650 iconSetCO->currentIndex()).toString());
2652 rc.ui_file = internal_path(fromqstr(uiFileED->text()));
2653 rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
2654 rc.num_lastfiles = lastfilesSB->value();
2655 rc.use_tooltip = tooltipCB->isChecked();
2659 void PrefUserInterface::updateRC(LyXRC const & rc)
2661 int iconset = iconSetCO->findData(toqstr(rc.icon_set));
2664 iconSetCO->setCurrentIndex(iconset);
2665 useSystemThemeIconsCB->setChecked(rc.use_system_theme_icons);
2666 uiFileED->setText(toqstr(external_path(rc.ui_file)));
2667 lastfilesSB->setValue(rc.num_lastfiles);
2668 tooltipCB->setChecked(rc.use_tooltip);
2672 void PrefUserInterface::selectUi()
2674 QString file = form_->browseUI(internalPath(uiFileED->text()));
2675 if (!file.isEmpty())
2676 uiFileED->setText(file);
2680 /////////////////////////////////////////////////////////////////////
2682 // PrefDocumentHandling
2684 /////////////////////////////////////////////////////////////////////
2686 PrefDocHandling::PrefDocHandling(GuiPreferences * form)
2687 : PrefModule(catLookAndFeel, N_("Document Handling"), form)
2691 connect(autoSaveCB, SIGNAL(toggled(bool)),
2692 autoSaveSB, SLOT(setEnabled(bool)));
2693 connect(autoSaveCB, SIGNAL(toggled(bool)),
2694 TextLabel1, SLOT(setEnabled(bool)));
2695 connect(openDocumentsInTabsCB, SIGNAL(clicked()),
2696 this, SIGNAL(changed()));
2697 connect(singleInstanceCB, SIGNAL(clicked()),
2698 this, SIGNAL(changed()));
2699 connect(singleCloseTabButtonCB, SIGNAL(clicked()),
2700 this, SIGNAL(changed()));
2701 connect(closeLastViewCO, SIGNAL(activated(int)),
2702 this, SIGNAL(changed()));
2703 connect(restoreCursorCB, SIGNAL(clicked()),
2704 this, SIGNAL(changed()));
2705 connect(loadSessionCB, SIGNAL(clicked()),
2706 this, SIGNAL(changed()));
2707 connect(allowGeometrySessionCB, SIGNAL(clicked()),
2708 this, SIGNAL(changed()));
2709 connect(autoSaveSB, SIGNAL(valueChanged(int)),
2710 this, SIGNAL(changed()));
2711 connect(autoSaveCB, SIGNAL(clicked()),
2712 this, SIGNAL(changed()));
2713 connect(backupCB, SIGNAL(clicked()),
2714 this, SIGNAL(changed()));
2715 connect(saveCompressedCB, SIGNAL(clicked()),
2716 this, SIGNAL(changed()));
2717 connect(saveOriginCB, SIGNAL(clicked()),
2718 this, SIGNAL(changed()));
2722 void PrefDocHandling::applyRC(LyXRC & rc) const
2724 rc.use_lastfilepos = restoreCursorCB->isChecked();
2725 rc.load_session = loadSessionCB->isChecked();
2726 rc.allow_geometry_session = allowGeometrySessionCB->isChecked();
2727 rc.autosave = autoSaveCB->isChecked() ? autoSaveSB->value() * 60 : 0;
2728 rc.make_backup = backupCB->isChecked();
2729 rc.save_compressed = saveCompressedCB->isChecked();
2730 rc.save_origin = saveOriginCB->isChecked();
2731 rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
2732 rc.single_instance = singleInstanceCB->isChecked();
2733 rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
2735 switch (closeLastViewCO->currentIndex()) {
2737 rc.close_buffer_with_last_view = "yes";
2740 rc.close_buffer_with_last_view = "no";
2743 rc.close_buffer_with_last_view = "ask";
2751 void PrefDocHandling::updateRC(LyXRC const & rc)
2753 restoreCursorCB->setChecked(rc.use_lastfilepos);
2754 loadSessionCB->setChecked(rc.load_session);
2755 allowGeometrySessionCB->setChecked(rc.allow_geometry_session);
2756 // convert to minutes
2757 bool autosave = rc.autosave > 0;
2758 int mins = rc.autosave / 60;
2761 autoSaveSB->setValue(mins);
2762 autoSaveCB->setChecked(autosave);
2763 autoSaveSB->setEnabled(autosave);
2764 backupCB->setChecked(rc.make_backup);
2765 saveCompressedCB->setChecked(rc.save_compressed);
2766 saveOriginCB->setChecked(rc.save_origin);
2767 openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
2768 singleInstanceCB->setChecked(rc.single_instance && !rc.lyxpipes.empty());
2769 singleInstanceCB->setEnabled(!rc.lyxpipes.empty());
2770 singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
2771 if (rc.close_buffer_with_last_view == "yes")
2772 closeLastViewCO->setCurrentIndex(0);
2773 else if (rc.close_buffer_with_last_view == "no")
2774 closeLastViewCO->setCurrentIndex(1);
2775 else if (rc.close_buffer_with_last_view == "ask")
2776 closeLastViewCO->setCurrentIndex(2);
2780 void PrefDocHandling::on_clearSessionPB_clicked()
2782 guiApp->clearSession();
2787 /////////////////////////////////////////////////////////////////////
2791 /////////////////////////////////////////////////////////////////////
2793 PrefEdit::PrefEdit(GuiPreferences * form)
2794 : PrefModule(catEditing, N_("Control"), form)
2798 connect(cursorFollowsCB, SIGNAL(clicked()),
2799 this, SIGNAL(changed()));
2800 connect(scrollBelowCB, SIGNAL(clicked()),
2801 this, SIGNAL(changed()));
2802 connect(macLikeCursorMovementCB, SIGNAL(clicked()),
2803 this, SIGNAL(changed()));
2804 connect(copyCTMarkupCB, SIGNAL(clicked()),
2805 this, SIGNAL(changed()));
2806 connect(sortEnvironmentsCB, SIGNAL(clicked()),
2807 this, SIGNAL(changed()));
2808 connect(groupEnvironmentsCB, SIGNAL(clicked()),
2809 this, SIGNAL(changed()));
2810 connect(macroEditStyleCO, SIGNAL(activated(int)),
2811 this, SIGNAL(changed()));
2812 connect(cursorWidthSB, SIGNAL(valueChanged(int)),
2813 this, SIGNAL(changed()));
2814 connect(citationSearchLE, SIGNAL(textChanged(QString)),
2815 this, SIGNAL(changed()));
2816 connect(screenWidthLE, SIGNAL(textChanged(QString)),
2817 this, SIGNAL(changed()));
2818 connect(screenWidthUnitCO, SIGNAL(selectionChanged(lyx::Length::UNIT)),
2819 this, SIGNAL(changed()));
2820 connect(toggleTabbarCB, SIGNAL(toggled(bool)),
2821 this, SIGNAL(changed()));
2822 connect(toggleMenubarCB, SIGNAL(toggled(bool)),
2823 this, SIGNAL(changed()));
2824 connect(toggleScrollbarCB, SIGNAL(toggled(bool)),
2825 this, SIGNAL(changed()));
2826 connect(toggleStatusbarCB, SIGNAL(toggled(bool)),
2827 this, SIGNAL(changed()));
2828 connect(toggleToolbarsCB, SIGNAL(toggled(bool)),
2829 this, SIGNAL(changed()));
2833 void PrefEdit::on_screenLimitCB_toggled(bool const state)
2835 screenWidthLE->setEnabled(state);
2836 screenWidthUnitCO->setEnabled(state);
2841 void PrefEdit::on_citationSearchCB_toggled(bool const state)
2843 citationSearchLE->setEnabled(state);
2844 citationSearchLA->setEnabled(state);
2849 void PrefEdit::applyRC(LyXRC & rc) const
2851 rc.cursor_follows_scrollbar = cursorFollowsCB->isChecked();
2852 rc.scroll_below_document = scrollBelowCB->isChecked();
2853 rc.mac_like_cursor_movement = macLikeCursorMovementCB->isChecked();
2854 rc.ct_markup_copied = copyCTMarkupCB->isChecked();
2855 rc.sort_layouts = sortEnvironmentsCB->isChecked();
2856 rc.group_layouts = groupEnvironmentsCB->isChecked();
2857 switch (macroEditStyleCO->currentIndex()) {
2858 case 0: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE_BOX; break;
2859 case 1: rc.macro_edit_style = LyXRC::MACRO_EDIT_INLINE; break;
2860 case 2: rc.macro_edit_style = LyXRC::MACRO_EDIT_LIST; break;
2862 rc.cursor_width = cursorWidthSB->value();
2863 rc.citation_search = citationSearchCB->isChecked();
2864 rc.citation_search_pattern = fromqstr(citationSearchLE->text());
2865 rc.full_screen_toolbars = toggleToolbarsCB->isChecked();
2866 rc.full_screen_scrollbar = toggleScrollbarCB->isChecked();
2867 rc.full_screen_statusbar = toggleStatusbarCB->isChecked();
2868 rc.full_screen_tabbar = toggleTabbarCB->isChecked();
2869 rc.full_screen_menubar = toggleMenubarCB->isChecked();
2870 rc.screen_width = Length(widgetsToLength(screenWidthLE, screenWidthUnitCO));
2871 rc.screen_limit = screenLimitCB->isChecked();
2875 void PrefEdit::updateRC(LyXRC const & rc)
2877 cursorFollowsCB->setChecked(rc.cursor_follows_scrollbar);
2878 scrollBelowCB->setChecked(rc.scroll_below_document);
2879 macLikeCursorMovementCB->setChecked(rc.mac_like_cursor_movement);
2880 copyCTMarkupCB->setChecked(rc.ct_markup_copied);
2881 sortEnvironmentsCB->setChecked(rc.sort_layouts);
2882 groupEnvironmentsCB->setChecked(rc.group_layouts);
2883 macroEditStyleCO->setCurrentIndex(rc.macro_edit_style);
2884 cursorWidthSB->setValue(rc.cursor_width);
2885 citationSearchCB->setChecked(rc.citation_search);
2886 citationSearchLE->setText(toqstr(rc.citation_search_pattern));
2887 citationSearchLE->setEnabled(rc.citation_search);
2888 citationSearchLA->setEnabled(rc.citation_search);
2889 toggleScrollbarCB->setChecked(rc.full_screen_scrollbar);
2890 toggleStatusbarCB->setChecked(rc.full_screen_statusbar);
2891 toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
2892 toggleTabbarCB->setChecked(rc.full_screen_tabbar);
2893 toggleMenubarCB->setChecked(rc.full_screen_menubar);
2894 lengthToWidgets(screenWidthLE, screenWidthUnitCO, rc.screen_width, Length::defaultUnit());
2895 screenWidthUnitCO->setEnabled(rc.screen_limit);
2896 screenLimitCB->setChecked(rc.screen_limit);
2897 screenWidthLE->setEnabled(rc.screen_limit);
2901 /////////////////////////////////////////////////////////////////////
2905 /////////////////////////////////////////////////////////////////////
2908 GuiShortcutDialog::GuiShortcutDialog(QWidget * parent) : QDialog(parent)
2910 Ui::shortcutUi::setupUi(this);
2911 QDialog::setModal(true);
2912 lfunLE->setValidator(new NoNewLineValidator(lfunLE));
2916 PrefShortcuts::PrefShortcuts(GuiPreferences * form)
2917 : PrefModule(catEditing, N_("Shortcuts"), form),
2918 editItem_(nullptr), mathItem_(nullptr), bufferItem_(nullptr), layoutItem_(nullptr),
2919 systemItem_(nullptr)
2923 shortcutsTW->setColumnCount(2);
2924 shortcutsTW->headerItem()->setText(0, qt_("Function"));
2925 shortcutsTW->headerItem()->setText(1, qt_("Shortcut"));
2926 shortcutsTW->setSortingEnabled(true);
2927 // Multi-selection can be annoying.
2928 // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection);
2930 connect(bindFilePB, SIGNAL(clicked()),
2931 this, SLOT(selectBind()));
2932 connect(bindFileED, SIGNAL(textChanged(QString)),
2933 this, SIGNAL(changed()));
2935 shortcut_ = new GuiShortcutDialog(this);
2936 shortcut_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
2937 shortcut_bc_.setOK(shortcut_->buttonBox->button(QDialogButtonBox::Ok));
2938 shortcut_bc_.setCancel(shortcut_->buttonBox->button(QDialogButtonBox::Cancel));
2940 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2941 this, SIGNAL(changed()));
2942 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2943 shortcut_, SLOT(reject()));
2944 connect(shortcut_->clearPB, SIGNAL(clicked()),
2945 this, SLOT(shortcutClearPressed()));
2946 connect(shortcut_->removePB, SIGNAL(clicked()),
2947 this, SLOT(shortcutRemovePressed()));
2948 connect(shortcut_->buttonBox, SIGNAL(accepted()),
2949 this, SLOT(shortcutOkPressed()));
2950 connect(shortcut_->buttonBox, SIGNAL(rejected()),
2951 this, SLOT(shortcutCancelPressed()));
2955 void PrefShortcuts::applyRC(LyXRC & rc) const
2957 rc.bind_file = internal_path(fromqstr(bindFileED->text()));
2958 // write user_bind and user_unbind to .lyx/bind/user.bind
2959 FileName bind_dir(addPath(package().user_support().absFileName(), "bind"));
2960 if (!bind_dir.exists() && !bind_dir.createDirectory(0777)) {
2961 lyxerr << "LyX could not create the user bind directory '"
2962 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2965 if (!bind_dir.isDirWritable()) {
2966 lyxerr << "LyX could not write to the user bind directory '"
2967 << bind_dir << "'. All user-defined key bindings will be lost." << endl;
2970 FileName user_bind_file(bind_dir.absFileName() + "/user.bind");
2971 user_unbind_.write(user_bind_file.toFilesystemEncoding(), false, true);
2972 user_bind_.write(user_bind_file.toFilesystemEncoding(), true, false);
2973 // immediately apply the keybindings. Why this is not done before?
2974 // The good thing is that the menus are updated automatically.
2975 theTopLevelKeymap().clear();
2976 theTopLevelKeymap().read("site");
2977 theTopLevelKeymap().read(rc.bind_file, nullptr, KeyMap::Fallback);
2978 theTopLevelKeymap().read("user", nullptr, KeyMap::MissingOK);
2982 void PrefShortcuts::updateRC(LyXRC const & rc)
2984 bindFileED->setText(toqstr(external_path(rc.bind_file)));
2986 system_bind_.clear();
2988 user_unbind_.clear();
2989 system_bind_.read("site");
2990 system_bind_.read(rc.bind_file);
2991 // \unbind in user.bind is added to user_unbind_
2992 user_bind_.read("user", &user_unbind_, KeyMap::MissingOK);
2993 updateShortcutsTW();
2997 void PrefShortcuts::updateShortcutsTW()
2999 shortcutsTW->clear();
3001 editItem_ = new QTreeWidgetItem(shortcutsTW);
3002 editItem_->setText(0, qt_("Cursor, Mouse and Editing Functions"));
3003 editItem_->setFlags(editItem_->flags() & ~Qt::ItemIsSelectable);
3005 mathItem_ = new QTreeWidgetItem(shortcutsTW);
3006 mathItem_->setText(0, qt_("Mathematical Symbols"));
3007 mathItem_->setFlags(mathItem_->flags() & ~Qt::ItemIsSelectable);
3009 bufferItem_ = new QTreeWidgetItem(shortcutsTW);
3010 bufferItem_->setText(0, qt_("Document and Window"));
3011 bufferItem_->setFlags(bufferItem_->flags() & ~Qt::ItemIsSelectable);
3013 layoutItem_ = new QTreeWidgetItem(shortcutsTW);
3014 layoutItem_->setText(0, qt_("Font, Layouts and Textclasses"));
3015 layoutItem_->setFlags(layoutItem_->flags() & ~Qt::ItemIsSelectable);
3017 systemItem_ = new QTreeWidgetItem(shortcutsTW);
3018 systemItem_->setText(0, qt_("System and Miscellaneous"));
3019 systemItem_->setFlags(systemItem_->flags() & ~Qt::ItemIsSelectable);
3021 // listBindings(unbound=true) lists all bound and unbound lfuns
3022 // Items in this list is tagged by its source.
3023 KeyMap::BindingList bindinglist = system_bind_.listBindings(true,
3025 KeyMap::BindingList user_bindinglist = user_bind_.listBindings(false,
3027 KeyMap::BindingList user_unbindinglist = user_unbind_.listBindings(false,
3028 KeyMap::UserUnbind);
3029 bindinglist.insert(bindinglist.end(), user_bindinglist.begin(),
3030 user_bindinglist.end());
3031 bindinglist.insert(bindinglist.end(), user_unbindinglist.begin(),
3032 user_unbindinglist.end());
3034 KeyMap::BindingList::const_iterator it = bindinglist.begin();
3035 KeyMap::BindingList::const_iterator it_end = bindinglist.end();
3036 for (; it != it_end; ++it)
3037 insertShortcutItem(it->request, it->sequence, it->tag);
3039 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3040 on_shortcutsTW_itemSelectionChanged();
3041 on_searchLE_textEdited();
3042 shortcutsTW->resizeColumnToContents(0);
3047 KeyMap::ItemType PrefShortcuts::itemType(QTreeWidgetItem & item)
3049 return static_cast<KeyMap::ItemType>(item.data(0, Qt::UserRole).toInt());
3054 bool PrefShortcuts::isAlwaysHidden(QTreeWidgetItem & item)
3056 // Hide rebound system settings that are empty
3057 return itemType(item) == KeyMap::UserUnbind && item.text(1).isEmpty();
3061 void PrefShortcuts::setItemType(QTreeWidgetItem * item, KeyMap::ItemType tag)
3063 item->setData(0, Qt::UserRole, QVariant(tag));
3067 case KeyMap::System:
3069 case KeyMap::UserBind:
3072 case KeyMap::UserUnbind:
3073 font.setStrikeOut(true);
3075 // this item is not displayed now.
3076 case KeyMap::UserExtraUnbind:
3077 font.setStrikeOut(true);
3080 item->setHidden(isAlwaysHidden(*item));
3081 item->setFont(1, font);
3085 QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun,
3086 KeySequence const & seq, KeyMap::ItemType tag)
3088 FuncCode const action = lfun.action();
3089 string const action_name = lyxaction.getActionName(action);
3090 QString const lfun_name = toqstr(from_utf8(action_name)
3091 + ' ' + lfun.argument());
3092 QString const shortcut = toqstr(seq.print(KeySequence::ForGui));
3094 QTreeWidgetItem * newItem = nullptr;
3095 // for unbind items, try to find an existing item in the system bind list
3096 if (tag == KeyMap::UserUnbind) {
3097 QList<QTreeWidgetItem*> const items = shortcutsTW->findItems(shortcut,
3098 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3099 for (auto const & item : items) {
3100 if (item->text(0) == lfun_name || lfun == FuncRequest::unknown) {
3105 // if not found, this unbind item is KeyMap::UserExtraUnbind
3106 // Such an item is not displayed to avoid confusion (what is
3107 // unmatched removed?).
3113 switch(lyxaction.getActionType(action)) {
3114 case LyXAction::Hidden:
3116 case LyXAction::Edit:
3117 newItem = new QTreeWidgetItem(editItem_);
3119 case LyXAction::Math:
3120 newItem = new QTreeWidgetItem(mathItem_);
3122 case LyXAction::Buffer:
3123 newItem = new QTreeWidgetItem(bufferItem_);
3125 case LyXAction::Layout:
3126 newItem = new QTreeWidgetItem(layoutItem_);
3128 case LyXAction::System:
3129 newItem = new QTreeWidgetItem(systemItem_);
3132 // this should not happen
3133 newItem = new QTreeWidgetItem(shortcutsTW);
3135 newItem->setText(0, lfun_name);
3136 newItem->setText(1, shortcut);
3139 // record BindFile representation to recover KeySequence when needed.
3140 newItem->setData(1, Qt::UserRole, toqstr(seq.print(KeySequence::BindFile)));
3141 setItemType(newItem, tag);
3146 void PrefShortcuts::on_shortcutsTW_itemSelectionChanged()
3148 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
3149 removePB->setEnabled(!items.isEmpty() && !items[0]->text(1).isEmpty());
3150 modifyPB->setEnabled(!items.isEmpty());
3151 if (items.isEmpty())
3154 if (itemType(*items[0]) == KeyMap::UserUnbind)
3155 removePB->setText(qt_("Res&tore"));
3157 removePB->setText(qt_("Remo&ve"));
3161 void PrefShortcuts::on_shortcutsTW_itemDoubleClicked()
3167 void PrefShortcuts::modifyShortcut()
3169 QTreeWidgetItem * item = shortcutsTW->currentItem();
3170 if (item->flags() & Qt::ItemIsSelectable) {
3171 shortcut_->lfunLE->setText(item->text(0));
3172 save_lfun_ = item->text(0).trimmed();
3173 shortcut_->shortcutWG->setText(item->text(1));
3175 seq.parse(fromqstr(item->data(1, Qt::UserRole).toString()));
3176 shortcut_->shortcutWG->setKeySequence(seq);
3177 shortcut_->shortcutWG->setFocus();
3183 void PrefShortcuts::unhideEmpty(QString const & lfun, bool select)
3185 // list of items that match lfun
3186 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(lfun,
3187 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 0);
3188 for (auto const & item : items) {
3189 if (isAlwaysHidden(*item)) {
3190 setItemType(item, KeyMap::System);
3192 shortcutsTW->setCurrentItem(item);
3199 void PrefShortcuts::removeShortcut()
3201 // it seems that only one item can be selected, but I am
3202 // removing all selected items anyway.
3203 QList<QTreeWidgetItem*> items = shortcutsTW->selectedItems();
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);
3215 removePB->setText(qt_("Res&tore"));
3218 case KeyMap::UserBind: {
3219 // for user_bind, we remove this bind
3220 QTreeWidgetItem * parent = item->parent();
3221 int itemIdx = parent->indexOfChild(item);
3222 parent->takeChild(itemIdx);
3224 shortcutsTW->scrollToItem(parent->child(itemIdx - 1));
3226 shortcutsTW->scrollToItem(parent);
3227 user_bind_.unbind(shortcut, func);
3228 // If this user binding hid an empty system binding, unhide the
3229 // latter and select it.
3230 unhideEmpty(item->text(0), true);
3233 case KeyMap::UserUnbind: {
3234 // for user_unbind, we remove the unbind, and the item
3235 // become KeyMap::System again.
3237 seq.parse(shortcut);
3238 // Ask the user to replace current binding
3239 if (!validateNewShortcut(func, seq, QString()))
3241 user_unbind_.unbind(shortcut, func);
3242 setItemType(item, KeyMap::System);
3243 removePB->setText(qt_("Remo&ve"));
3246 case KeyMap::UserExtraUnbind: {
3247 // for user unbind that is not in system bind file,
3248 // remove this unbind file
3249 QTreeWidgetItem * parent = item->parent();
3250 parent->takeChild(parent->indexOfChild(item));
3251 user_unbind_.unbind(shortcut, func);
3258 void PrefShortcuts::deactivateShortcuts(QList<QTreeWidgetItem*> const & items)
3260 for (auto item : items) {
3261 string shortcut = fromqstr(item->data(1, Qt::UserRole).toString());
3262 string lfun = fromqstr(item->text(0));
3263 FuncRequest const func = lyxaction.lookupFunc(lfun);
3265 switch (itemType(*item)) {
3266 case KeyMap::System:
3267 // for system bind, we do not touch the item
3268 // but add an user unbind item
3269 user_unbind_.bind(shortcut, func);
3270 setItemType(item, KeyMap::UserUnbind);
3273 case KeyMap::UserBind: {
3274 // for user_bind, we remove this bind
3275 QTreeWidgetItem * parent = item->parent();
3276 int itemIdx = parent->indexOfChild(item);
3277 parent->takeChild(itemIdx);
3278 user_bind_.unbind(shortcut, func);
3279 unhideEmpty(item->text(0), false);
3289 void PrefShortcuts::selectBind()
3291 QString file = form_->browsebind(internalPath(bindFileED->text()));
3292 if (!file.isEmpty()) {
3293 bindFileED->setText(file);
3294 system_bind_ = KeyMap();
3295 system_bind_.read(fromqstr(file));
3296 updateShortcutsTW();
3301 void PrefShortcuts::on_modifyPB_pressed()
3307 void PrefShortcuts::on_newPB_pressed()
3309 shortcut_->lfunLE->clear();
3310 shortcut_->shortcutWG->reset();
3311 save_lfun_ = QString();
3316 void PrefShortcuts::on_removePB_pressed()
3323 void PrefShortcuts::on_searchLE_textEdited()
3325 if (searchLE->text().isEmpty()) {
3326 // show all hidden items
3327 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Hidden);
3329 (*it)->setHidden(isAlwaysHidden(**it));
3330 // close all categories
3331 for (int i = 0; i < shortcutsTW->topLevelItemCount(); ++i)
3332 shortcutsTW->collapseItem(shortcutsTW->topLevelItem(i));
3335 // search both columns
3336 QList<QTreeWidgetItem *> matched = shortcutsTW->findItems(searchLE->text(),
3337 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 0);
3338 matched += shortcutsTW->findItems(searchLE->text(),
3339 Qt::MatchFlags(Qt::MatchContains | Qt::MatchRecursive), 1);
3341 // hide everyone (to avoid searching in matched QList repeatedly
3342 QTreeWidgetItemIterator it(shortcutsTW, QTreeWidgetItemIterator::Selectable);
3344 (*it++)->setHidden(true);
3345 // show matched items
3346 for (auto & item : matched)
3347 if (!isAlwaysHidden(*item)) {
3348 item->setHidden(false);
3350 item->parent()->setExpanded(true);
3355 docstring makeCmdString(FuncRequest const & f)
3357 docstring actionStr = from_ascii(lyxaction.getActionName(f.action()));
3358 if (!f.argument().empty())
3359 actionStr += " " + f.argument();
3364 FuncRequest PrefShortcuts::currentBinding(KeySequence const & k)
3366 FuncRequest res = user_bind_.getBinding(k);
3367 if (res.action() != LFUN_UNKNOWN_ACTION)
3369 res = system_bind_.getBinding(k);
3370 // Check if it is unbound. Note: user_unbind_ can only unbind one
3371 // FuncRequest per key sequence.
3372 if (user_unbind_.getBinding(k) == res)
3373 return FuncRequest::unknown;
3378 bool PrefShortcuts::validateNewShortcut(FuncRequest const & func,
3379 KeySequence const & k,
3380 QString const & lfun_to_modify)
3382 if (func.action() == LFUN_UNKNOWN_ACTION) {
3383 Alert::error(_("Failed to create shortcut"),
3384 _("Unknown or invalid LyX function"));
3388 // It is not currently possible to bind Hidden lfuns such as self-insert. In
3389 // the future, to remove this limitation, see GuiPrefs::insertShortcutItem
3390 // and how it is used in GuiPrefs::shortcutOkPressed.
3391 if (lyxaction.getActionType(func.action()) == LyXAction::Hidden) {
3392 Alert::error(_("Failed to create shortcut"),
3393 _("This LyX function is hidden and cannot be bound."));
3397 if (k.length() == 0) {
3398 Alert::error(_("Failed to create shortcut"),
3399 _("Invalid or empty key sequence"));
3403 FuncRequest oldBinding = currentBinding(k);
3404 if (oldBinding == func)
3405 // nothing to change
3408 // make sure this key isn't already bound---and, if so, prompt user
3409 // (exclude the lfun the user already wants to modify)
3410 docstring const action_string = makeCmdString(oldBinding);
3411 if (oldBinding.action() != LFUN_UNKNOWN_ACTION
3412 && lfun_to_modify != toqstr(action_string)) {
3413 docstring const new_action_string = makeCmdString(func);
3414 docstring const text = bformat(_("Shortcut `%1$s' is already bound to "
3416 "Are you sure you want to unbind the "
3417 "current shortcut and bind it to %3$s?"),
3418 k.print(KeySequence::ForGui), action_string,
3420 int ret = Alert::prompt(_("Redefine shortcut?"),
3421 text, 0, 1, _("&Redefine"), _("&Cancel"));
3424 QString const sequence_text = toqstr(k.print(KeySequence::ForGui));
3425 QList<QTreeWidgetItem*> items = shortcutsTW->findItems(sequence_text,
3426 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive), 1);
3427 deactivateShortcuts(items);
3433 void PrefShortcuts::shortcutOkPressed()
3435 QString const new_lfun = shortcut_->lfunLE->text();
3436 FuncRequest const func = lyxaction.lookupFunc(fromqstr(new_lfun));
3437 KeySequence k = shortcut_->shortcutWG->getKeySequence();
3439 // save_lfun_ contains the text of the lfun to modify, if the user clicked
3440 // "modify", or is empty if they clicked "new" (which I do not really like)
3441 if (!validateNewShortcut(func, k, save_lfun_))
3444 if (!save_lfun_.isEmpty()) {
3445 // real modification of the lfun's shortcut,
3446 // so remove the previous one
3447 QList<QTreeWidgetItem*> to_modify = shortcutsTW->selectedItems();
3448 deactivateShortcuts(to_modify);
3451 shortcut_->accept();
3453 QTreeWidgetItem * item = insertShortcutItem(func, k, KeyMap::UserBind);
3455 user_bind_.bind(&k, func);
3456 shortcutsTW->sortItems(0, Qt::AscendingOrder);
3458 item->parent()->setExpanded(true);
3459 shortcutsTW->setCurrentItem(item);
3460 shortcutsTW->scrollToItem(item);
3462 Alert::error(_("Failed to create shortcut"),
3463 _("Can not insert shortcut to the list"));
3469 void PrefShortcuts::shortcutCancelPressed()
3471 shortcut_->shortcutWG->reset();
3475 void PrefShortcuts::shortcutClearPressed()
3477 shortcut_->shortcutWG->reset();
3481 void PrefShortcuts::shortcutRemovePressed()
3483 shortcut_->shortcutWG->removeFromSequence();
3487 /////////////////////////////////////////////////////////////////////
3491 /////////////////////////////////////////////////////////////////////
3493 PrefIdentity::PrefIdentity(GuiPreferences * form)
3494 : PrefModule(QString(), N_("Identity"), form)
3498 connect(nameED, SIGNAL(textChanged(QString)),
3499 this, SIGNAL(changed()));
3500 connect(emailED, SIGNAL(textChanged(QString)),
3501 this, SIGNAL(changed()));
3502 connect(initialsED, SIGNAL(textChanged(QString)),
3503 this, SIGNAL(changed()));
3505 nameED->setValidator(new NoNewLineValidator(nameED));
3506 emailED->setValidator(new NoNewLineValidator(emailED));
3507 initialsED->setValidator(new NoNewLineValidator(initialsED));
3511 void PrefIdentity::applyRC(LyXRC & rc) const
3513 rc.user_name = fromqstr(nameED->text());
3514 rc.user_email = fromqstr(emailED->text());
3515 rc.user_initials = fromqstr(initialsED->text());
3519 void PrefIdentity::updateRC(LyXRC const & rc)
3521 nameED->setText(toqstr(rc.user_name));
3522 emailED->setText(toqstr(rc.user_email));
3523 initialsED->setText(toqstr(rc.user_initials));
3528 /////////////////////////////////////////////////////////////////////
3532 /////////////////////////////////////////////////////////////////////
3534 GuiPreferences::GuiPreferences(GuiView & lv)
3535 : GuiDialog(lv, "prefs", qt_("Preferences"))
3539 QDialog::setModal(false);
3541 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
3542 this, SLOT(slotButtonBox(QAbstractButton *)));
3544 addModule(new PrefUserInterface(this));
3545 addModule(new PrefDocHandling(this));
3546 addModule(new PrefEdit(this));
3547 addModule(new PrefShortcuts(this));
3548 PrefScreenFonts * screenfonts = new PrefScreenFonts(this);
3549 connect(this, SIGNAL(prefsApplied(LyXRC const &)),
3550 screenfonts, SLOT(updateScreenFontSizes(LyXRC const &)));
3551 addModule(screenfonts);
3552 addModule(new PrefColors(this));
3553 addModule(new PrefDisplay(this));
3554 addModule(new PrefInput(this));
3555 addModule(new PrefCompletion(this));
3557 addModule(new PrefPaths(this));
3559 addModule(new PrefIdentity(this));
3561 addModule(new PrefLanguage(this));
3562 addModule(new PrefSpellchecker(this));
3564 PrefOutput * output = new PrefOutput(this);
3566 addModule(new PrefLatex(this));
3568 PrefConverters * converters = new PrefConverters(this);
3569 PrefFileformats * formats = new PrefFileformats(this);
3570 connect(formats, SIGNAL(formatsChanged()),
3571 converters, SLOT(updateGui()));
3572 addModule(converters);
3575 prefsPS->setCurrentPanel("User Interface");
3576 // FIXME: hack to work around resizing bug in Qt >= 4.2
3577 // bug verified with Qt 4.2.{0-3} (JSpitzm)
3578 #if QT_VERSION >= 0x040200
3579 prefsPS->updateGeometry();
3582 bc().setPolicy(ButtonPolicy::PreferencesPolicy);
3583 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
3584 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
3585 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
3586 bc().setRestore(buttonBox->button(QDialogButtonBox::Reset));
3588 guilyxfiles_ = new GuiLyXFiles(lv);
3589 connect(guilyxfiles_, SIGNAL(fileSelected(QString)),
3590 this, SLOT(slotFileSelected(QString)));
3594 void GuiPreferences::addModule(PrefModule * module)
3596 LASSERT(module, return);
3597 if (module->category().isEmpty())
3598 prefsPS->addPanel(module, module->title());
3600 prefsPS->addPanel(module, module->title(), module->category());
3601 connect(module, SIGNAL(changed()), this, SLOT(change_adaptor()));
3602 modules_.push_back(module);
3606 void GuiPreferences::change_adaptor()
3612 void GuiPreferences::applyRC(LyXRC & rc) const
3614 size_t end = modules_.size();
3615 for (size_t i = 0; i != end; ++i)
3616 modules_[i]->applyRC(rc);
3620 void GuiPreferences::updateRC(LyXRC const & rc)
3622 size_t const end = modules_.size();
3623 for (size_t i = 0; i != end; ++i)
3624 modules_[i]->updateRC(rc);
3628 void GuiPreferences::applyView()
3634 bool GuiPreferences::initialiseParams(string const &)
3637 formats_ = theFormats();
3638 converters_ = theConverters();
3639 converters_.update(formats_);
3640 movers_ = theMovers();
3644 // Make sure that the bc is in the INITIAL state
3645 if (bc().policy().buttonStatus(ButtonPolicy::RESTORE))
3652 void GuiPreferences::dispatchParams()
3655 rc_.write(ss, true);
3656 dispatch(FuncRequest(LFUN_LYXRC_APPLY, ss.str()));
3657 // issue prefsApplied signal. This will update the
3658 // localized screen font sizes.
3660 // FIXME: these need lfuns
3662 Author const & author =
3663 Author(from_utf8(rc_.user_name), from_utf8(rc_.user_email),
3664 from_utf8(rc_.user_initials));
3665 theBufferList().recordCurrentAuthor(author);
3667 theFormats() = formats_;
3669 theConverters() = converters_;
3670 theConverters().update(formats_);
3671 theConverters().buildGraph();
3672 theBufferList().invalidateConverterCache();
3674 theMovers() = movers_;
3676 for (string const & color : colors_)
3677 dispatch(FuncRequest(LFUN_SET_COLOR, color));
3681 if (!tempSaveCB->isChecked())
3682 dispatch(FuncRequest(LFUN_PREFERENCES_SAVE));
3686 void GuiPreferences::setColor(ColorCode col, QString const & hex)
3688 colors_.push_back(lcolor.getLyXName(col) + ' ' + fromqstr(hex));
3692 void GuiPreferences::slotFileSelected(QString const file)
3698 QString GuiPreferences::browseLibFile(QString const & dir,
3699 QString const & name, QString const & ext)
3703 guilyxfiles_->passParams(fromqstr(dir));
3704 guilyxfiles_->selectItem(name);
3705 guilyxfiles_->exec();
3707 QString const result = uifile_;
3709 // remove the extension if it is the default one
3710 QString noextresult;
3711 if (getExtension(result) == ext)
3712 noextresult = removeExtension(result);
3714 noextresult = result;
3716 // remove the directory, if it is the default one
3717 QString const file = onlyFileName(noextresult);
3718 if (toqstr(libFileSearch(dir, file, ext).absFileName()) == result)
3725 QString GuiPreferences::browsebind(QString const & file)
3727 return browseLibFile("bind", file, "bind");
3731 QString GuiPreferences::browseUI(QString const & file)
3733 return browseLibFile("ui", file, "ui");
3737 QString GuiPreferences::browsekbmap(QString const & file)
3739 return browseLibFile("kbd", file, "kmap");
3743 QString GuiPreferences::browse(QString const & file,
3744 QString const & title) const
3746 return browseFile(file, title, QStringList(), true);
3750 } // namespace frontend
3753 #include "moc_GuiPrefs.cpp"