3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetinclude.h"
68 #include "insets/insetnote.h"
69 #include "insets/insettabular.h"
70 #include "insets/insetvspace.h"
71 #include "insets/insetwrap.h"
73 #include "frontends/Alert.h"
74 #include "frontends/Dialogs.h"
75 #include "frontends/FileDialog.h"
76 #include "frontends/lyx_gui.h"
77 #include "frontends/LyXKeySym.h"
78 #include "frontends/LyXView.h"
79 #include "frontends/Menubar.h"
80 #include "frontends/Toolbars.h"
82 #include "support/environment.h"
83 #include "support/filefilterlist.h"
84 #include "support/filetools.h"
85 #include "support/forkedcontr.h"
86 #include "support/fs_extras.h"
87 #include "support/lstrings.h"
88 #include "support/path.h"
89 #include "support/package.h"
90 #include "support/systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
94 #include <boost/current_function.hpp>
95 #include <boost/filesystem/operations.hpp>
99 using bv_funcs::freefont2string;
101 using lyx::support::AbsolutePath;
102 using lyx::support::AddName;
103 using lyx::support::AddPath;
104 using lyx::support::bformat;
105 using lyx::support::ChangeExtension;
106 using lyx::support::contains;
107 using lyx::support::FileFilterList;
108 using lyx::support::FileSearch;
109 using lyx::support::ForkedcallsController;
110 using lyx::support::i18nLibFileSearch;
111 using lyx::support::IsDirWriteable;
112 using lyx::support::IsFileReadable;
113 using lyx::support::isStrInt;
114 using lyx::support::MakeAbsPath;
115 using lyx::support::MakeDisplayPath;
116 using lyx::support::package;
117 using lyx::support::Path;
118 using lyx::support::QuoteName;
119 using lyx::support::rtrim;
120 using lyx::support::split;
121 using lyx::support::subst;
122 using lyx::support::Systemcall;
123 using lyx::support::token;
124 using lyx::support::trim;
125 using lyx::support::prefixIs;
128 using std::make_pair;
131 using std::istringstream;
133 namespace biblio = lyx::biblio;
134 namespace fs = boost::filesystem;
137 extern BufferList bufferlist;
138 extern LyXServer * lyxserver;
140 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
143 extern tex_accent_struct get_accent(kb_action action);
148 bool getStatus(LCursor cursor,
149 FuncRequest const & cmd, FuncStatus & status)
151 // Try to fix cursor in case it is broken.
152 cursor.fixIfBroken();
154 // This is, of course, a mess. Better create a new doc iterator and use
155 // this in Inset::getStatus. This might require an additional
156 // BufferView * arg, though (which should be avoided)
157 //LCursor safe = *this;
159 for ( ; cursor.depth(); cursor.pop()) {
160 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
161 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
162 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
163 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
165 // The inset's getStatus() will return 'true' if it made
166 // a definitive decision on whether it want to handle the
167 // request or not. The result of this decision is put into
168 // the 'status' parameter.
169 if (cursor.inset().getStatus(cursor, cmd, status)) {
179 LyXFunc::LyXFunc(LyXView * lv)
182 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
183 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
184 meta_fake_bit(key_modifier::none)
189 void LyXFunc::handleKeyFunc(kb_action action)
191 char c = encoded_last_key;
193 if (keyseq.length()) {
197 owner->getIntl().getTransManager()
198 .deadkey(c, get_accent(action).accent, view()->getLyXText());
199 // Need to clear, in case the minibuffer calls these
202 // copied verbatim from do_accent_char
203 view()->cursor().resetAnchor();
208 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
210 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
212 // Do nothing if we have nothing (JMarc)
213 if (!keysym->isOK()) {
214 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
219 if (keysym->isModifier()) {
220 lyxerr[Debug::KEY] << "isModifier true" << endl;
224 Encoding const * encoding = view()->cursor().getEncoding();
226 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
228 // Do a one-deep top-level lookup for
229 // cancel and meta-fake keys. RVDK_PATCH_5
230 cancel_meta_seq.reset();
232 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
233 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
234 << " action first set to [" << func.action << ']'
237 // When not cancel or meta-fake, do the normal lookup.
238 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
239 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
240 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
241 // remove Caps Lock and Mod2 as a modifiers
242 func = keyseq.addkey(keysym, (state | meta_fake_bit));
243 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
244 << "action now set to ["
245 << func.action << ']' << endl;
248 // Dont remove this unless you know what you are doing.
249 meta_fake_bit = key_modifier::none;
251 // Can this happen now ?
252 if (func.action == LFUN_NOACTION) {
253 func = FuncRequest(LFUN_PREFIX);
256 if (lyxerr.debugging(Debug::KEY)) {
257 lyxerr << BOOST_CURRENT_FUNCTION
259 << func.action << "]["
260 << keyseq.print() << ']'
264 // already here we know if it any point in going further
265 // why not return already here if action == -1 and
266 // num_bytes == 0? (Lgb)
268 if (keyseq.length() > 1) {
269 owner->message(keyseq.print());
273 // Maybe user can only reach the key via holding down shift.
274 // Let's see. But only if shift is the only modifier
275 if (func.action == LFUN_UNKNOWN_ACTION &&
276 state == key_modifier::shift) {
277 lyxerr[Debug::KEY] << "Trying without shift" << endl;
278 func = keyseq.addkey(keysym, key_modifier::none);
279 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
282 if (func.action == LFUN_UNKNOWN_ACTION) {
283 // Hmm, we didn't match any of the keysequences. See
284 // if it's normal insertable text not already covered
286 if (keysym->isText() && keyseq.length() == 1) {
287 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
288 func = FuncRequest(LFUN_SELFINSERT);
290 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
291 owner->message(_("Unknown function."));
296 if (func.action == LFUN_SELFINSERT) {
297 if (encoded_last_key != 0) {
298 string const arg(1, encoded_last_key);
299 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
301 << "SelfInsert arg[`" << arg << "']" << endl;
309 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
311 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
313 LCursor & cur = view()->cursor();
315 /* In LyX/Mac, when a dialog is open, the menus of the
316 application can still be accessed without giving focus to
317 the main window. In this case, we want to disable the menu
318 entries that are buffer-related.
321 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
324 buf = owner->buffer();
326 if (cmd.action == LFUN_NOACTION) {
327 flag.message(N_("Nothing to do"));
332 switch (cmd.action) {
333 case LFUN_UNKNOWN_ACTION:
334 #ifndef HAVE_LIBAIKSAURUS
335 case LFUN_THESAURUS_ENTRY:
341 flag |= lyx_gui::getStatus(cmd);
344 if (flag.unknown()) {
345 flag.message(N_("Unknown action"));
349 if (!flag.enabled()) {
350 if (flag.message().empty())
351 flag.message(N_("Command disabled"));
355 // Check whether we need a buffer
356 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
358 flag.message(N_("Command not allowed with"
359 "out any document open"));
364 // I would really like to avoid having this switch and rather try to
365 // encode this in the function itself.
366 // -- And I'd rather let an inset decide which LFUNs it is willing
367 // to handle (Andre')
369 switch (cmd.action) {
370 case LFUN_TOOLTIPS_TOGGLE:
371 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
374 case LFUN_READ_ONLY_TOGGLE:
375 flag.setOnOff(buf->isReadonly());
378 case LFUN_SWITCHBUFFER:
379 // toggle on the current buffer, but do not toggle off
380 // the other ones (is that a good idea?)
381 if (cmd.argument == buf->fileName())
386 enable = cmd.argument == "custom"
387 || Exporter::IsExportable(*buf, cmd.argument);
391 enable = cur.selection();
395 enable = buf->isLatex() && lyxrc.chktex_command != "none";
399 enable = Exporter::IsExportable(*buf, "program");
402 case LFUN_LAYOUT_TABULAR:
403 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
407 case LFUN_LAYOUT_PARAGRAPH:
408 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
411 case LFUN_VC_REGISTER:
412 enable = !buf->lyxvc().inUse();
414 case LFUN_VC_CHECKIN:
415 enable = buf->lyxvc().inUse() && !buf->isReadonly();
417 case LFUN_VC_CHECKOUT:
418 enable = buf->lyxvc().inUse() && buf->isReadonly();
422 enable = buf->lyxvc().inUse();
424 case LFUN_MENURELOAD:
425 enable = !buf->isUnnamed() && !buf->isClean();
428 case LFUN_INSET_SETTINGS: {
432 InsetBase::Code code = cur.inset().lyxCode();
434 case InsetBase::TABULAR_CODE:
435 enable = cmd.argument == "tabular";
437 case InsetBase::ERT_CODE:
438 enable = cmd.argument == "ert";
440 case InsetBase::FLOAT_CODE:
441 enable = cmd.argument == "float";
443 case InsetBase::WRAP_CODE:
444 enable = cmd.argument == "wrap";
446 case InsetBase::NOTE_CODE:
447 enable = cmd.argument == "note";
449 case InsetBase::BRANCH_CODE:
450 enable = cmd.argument == "branch";
452 case InsetBase::BOX_CODE:
453 enable = cmd.argument == "box";
461 case LFUN_INSET_APPLY: {
462 string const name = cmd.getArg(0);
463 InsetBase * inset = owner->getDialogs().getOpenInset(name);
465 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
467 bool const success = inset->getStatus(cur, fr, fs);
468 // Every inset is supposed to handle this
469 BOOST_ASSERT(success);
472 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
473 flag |= getStatus(fr);
475 enable = flag.enabled();
479 case LFUN_DIALOG_SHOW: {
480 string const name = cmd.getArg(0);
482 enable = name == "aboutlyx"
486 || name == "texinfo";
487 else if (name == "print")
488 enable = Exporter::IsExportable(*buf, "dvi")
489 && lyxrc.print_command != "none";
490 else if (name == "character" || name == "mathpanel")
491 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
492 else if (name == "latexlog")
493 enable = IsFileReadable(buf->getLogName().second);
494 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
495 else if (name == "spellchecker")
498 else if (name == "vclog")
499 enable = buf->lyxvc().inUse();
503 case LFUN_DIALOG_SHOW_NEW_INSET:
504 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
507 case LFUN_DIALOG_UPDATE: {
508 string const name = cmd.getArg(0);
510 enable = name == "prefs";
514 // this one is difficult to get right. As a half-baked
515 // solution, we consider only the first action of the sequence
516 case LFUN_SEQUENCE: {
517 // argument contains ';'-terminated commands
518 string const firstcmd = token(cmd.argument, ';', 0);
519 FuncRequest func(lyxaction.lookupFunc(firstcmd));
520 func.origin = cmd.origin;
521 flag = getStatus(func);
525 case LFUN_MENUNEWTMPLT:
526 case LFUN_WORDFINDFORWARD:
527 case LFUN_WORDFINDBACKWARD:
529 case LFUN_EXEC_COMMAND:
532 case LFUN_CLOSEBUFFER:
541 case LFUN_RECONFIGURE:
545 case LFUN_DROP_LAYOUTS_CHOICE:
546 case LFUN_MENU_OPEN_BY_NAME:
549 case LFUN_GOTOFILEROW:
550 case LFUN_DIALOG_SHOW_NEXT_INSET:
551 case LFUN_DIALOG_HIDE:
552 case LFUN_DIALOG_DISCONNECT_INSET:
554 case LFUN_TOGGLECURSORFOLLOW:
558 case LFUN_KMAP_TOGGLE:
560 case LFUN_EXPORT_CUSTOM:
562 case LFUN_SAVEPREFERENCES:
563 case LFUN_SCREEN_FONT_UPDATE:
566 case LFUN_EXTERNAL_EDIT:
567 case LFUN_GRAPHICS_EDIT:
568 case LFUN_ALL_INSETS_TOGGLE:
569 case LFUN_LANGUAGE_BUFFER:
570 case LFUN_TEXTCLASS_APPLY:
571 case LFUN_TEXTCLASS_LOAD:
572 case LFUN_SAVE_AS_DEFAULT:
573 case LFUN_BUFFERPARAMS_APPLY:
574 case LFUN_LYXRC_APPLY:
575 case LFUN_NEXTBUFFER:
576 case LFUN_PREVIOUSBUFFER:
577 // these are handled in our dispatch()
582 if (!::getStatus(cur, cmd, flag))
583 flag = view()->getStatus(cmd);
589 // Can we use a readonly buffer?
590 if (buf && buf->isReadonly()
591 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
592 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
593 flag.message(N_("Document is read-only"));
597 // the default error message if we disable the command
598 if (!flag.enabled() && flag.message().empty())
599 flag.message(N_("Command disabled"));
607 bool ensureBufferClean(BufferView * bv)
609 Buffer & buf = *bv->buffer();
613 string const file = MakeDisplayPath(buf.fileName(), 30);
614 string text = bformat(_("The document %1$s has unsaved "
615 "changes.\n\nDo you want to save "
616 "the document?"), file);
617 int const ret = Alert::prompt(_("Save changed document?"),
618 text, 0, 1, _("&Save"),
622 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
624 return buf.isClean();
628 void showPrintError(string const & name)
630 string str = bformat(_("Could not print the document %1$s.\n"
631 "Check that your printer is set up correctly."),
632 MakeDisplayPath(name, 50));
633 Alert::error(_("Print document failed"), str);
637 void loadTextclass(string const & name)
639 std::pair<bool, lyx::textclass_type> const tc_pair =
640 textclasslist.NumberOfClass(name);
642 if (!tc_pair.first) {
643 lyxerr << "Document class \"" << name
644 << "\" does not exist."
649 lyx::textclass_type const tc = tc_pair.second;
651 if (!textclasslist[tc].load()) {
652 string s = bformat(_("The document could not be converted\n"
653 "into the document class %1$s."),
654 textclasslist[tc].name());
655 Alert::error(_("Could not change class"), s);
660 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
665 void LyXFunc::dispatch(FuncRequest const & cmd)
667 BOOST_ASSERT(view());
668 string const argument = cmd.argument;
669 kb_action const action = cmd.action;
671 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
672 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
674 // we have not done anything wrong yet.
676 dispatch_buffer.erase();
680 FuncStatus const flag = getStatus(cmd);
681 if (!flag.enabled()) {
682 // We cannot use this function here
683 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
684 << lyxaction.getActionName(action)
685 << " [" << action << "] is disabled at this location"
687 setErrorMessage(flag.message());
690 if (view()->available())
691 view()->hideCursor();
695 case LFUN_WORDFINDFORWARD:
696 case LFUN_WORDFINDBACKWARD: {
697 static string last_search;
698 string searched_string;
700 if (!argument.empty()) {
701 last_search = argument;
702 searched_string = argument;
704 searched_string = last_search;
707 if (searched_string.empty())
710 bool const fw = action == LFUN_WORDFINDFORWARD;
712 lyx::find::find2string(searched_string, true, false, fw);
713 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
718 owner->message(keyseq.printOptions());
721 case LFUN_EXEC_COMMAND:
722 owner->getToolbars().display("minibuffer", true);
723 owner->focus_command_buffer();
728 meta_fake_bit = key_modifier::none;
729 if (view()->available())
730 // cancel any selection
731 dispatch(FuncRequest(LFUN_MARK_OFF));
732 setMessage(N_("Cancel"));
736 meta_fake_bit = key_modifier::alt;
737 setMessage(keyseq.print());
740 case LFUN_READ_ONLY_TOGGLE:
741 if (owner->buffer()->lyxvc().inUse())
742 owner->buffer()->lyxvc().toggleReadOnly();
744 owner->buffer()->setReadonly(
745 !owner->buffer()->isReadonly());
748 // --- Menus -----------------------------------------------
750 menuNew(argument, false);
753 case LFUN_MENUNEWTMPLT:
754 menuNew(argument, true);
757 case LFUN_CLOSEBUFFER:
762 if (!owner->buffer()->isUnnamed()) {
763 string const str = bformat(_("Saving document %1$s..."),
764 MakeDisplayPath(owner->buffer()->fileName()));
766 MenuWrite(owner->buffer());
767 owner->message(str + _(" done."));
769 WriteAs(owner->buffer());
773 WriteAs(owner->buffer(), argument);
776 case LFUN_MENURELOAD: {
777 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
778 string text = bformat(_("Any changes will be lost. Are you sure "
779 "you want to revert to the saved version of the document %1$s?"), file);
780 int const ret = Alert::prompt(_("Revert to saved document?"),
781 text, 0, 1, _("&Revert"), _("&Cancel"));
789 Exporter::Export(owner->buffer(), argument, true);
790 view()->showErrorList(BufferFormat(*owner->buffer()));
794 Exporter::Preview(owner->buffer(), argument);
795 view()->showErrorList(BufferFormat(*owner->buffer()));
799 Exporter::Export(owner->buffer(), "program", true);
800 view()->showErrorList(_("Build"));
804 owner->buffer()->runChktex();
805 view()->showErrorList(_("ChkTeX"));
809 if (argument == "custom")
810 owner->getDialogs().show("sendto");
812 Exporter::Export(owner->buffer(), argument, false);
813 view()->showErrorList(BufferFormat(*owner->buffer()));
817 case LFUN_EXPORT_CUSTOM: {
819 string command = split(argument, format_name, ' ');
820 Format const * format = formats.getFormat(format_name);
822 lyxerr << "Format \"" << format_name
823 << "\" not recognized!"
828 Buffer * buffer = owner->buffer();
830 // The name of the file created by the conversion process
833 // Output to filename
834 if (format->name() == "lyx") {
835 string const latexname =
836 buffer->getLatexName(false);
837 filename = ChangeExtension(latexname,
838 format->extension());
839 filename = AddName(buffer->temppath(), filename);
841 if (!buffer->writeFile(filename))
845 Exporter::Export(buffer, format_name, true,
849 // Substitute $$FName for filename
850 if (!contains(command, "$$FName"))
851 command = "( " + command + " ) < $$FName";
852 command = subst(command, "$$FName", filename);
854 // Execute the command in the background
856 call.startscript(Systemcall::DontWait, command);
863 string command = split(split(argument, target, ' '),
867 || target_name.empty()
868 || command.empty()) {
869 lyxerr << "Unable to parse \""
870 << argument << '"' << std::endl;
873 if (target != "printer" && target != "file") {
874 lyxerr << "Unrecognized target \""
875 << target << '"' << std::endl;
879 Buffer * buffer = owner->buffer();
881 if (!Exporter::Export(buffer, "dvi", true)) {
882 showPrintError(buffer->fileName());
886 // Push directory path.
887 string const path = buffer->temppath();
890 // there are three cases here:
891 // 1. we print to a file
892 // 2. we print directly to a printer
893 // 3. we print using a spool command (print to file first)
896 string const dviname =
897 ChangeExtension(buffer->getLatexName(true),
900 if (target == "printer") {
901 if (!lyxrc.print_spool_command.empty()) {
902 // case 3: print using a spool
903 string const psname =
904 ChangeExtension(dviname,".ps");
905 command += lyxrc.print_to_file
908 + QuoteName(dviname);
911 lyxrc.print_spool_command +' ';
912 if (target_name != "default") {
913 command2 += lyxrc.print_spool_printerprefix
917 command2 += QuoteName(psname);
919 // If successful, then spool command
920 res = one.startscript(
925 res = one.startscript(
926 Systemcall::DontWait,
929 // case 2: print directly to a printer
930 res = one.startscript(
931 Systemcall::DontWait,
932 command + QuoteName(dviname));
936 // case 1: print to a file
937 command += lyxrc.print_to_file
938 + QuoteName(MakeAbsPath(target_name,
941 + QuoteName(dviname);
942 res = one.startscript(Systemcall::DontWait,
947 showPrintError(buffer->fileName());
956 QuitLyX(argument == "force");
960 InsetCommandParams p("tableofcontents");
961 string const data = InsetCommandMailer::params2string("toc", p);
962 owner->getDialogs().show("toc", data, 0);
970 case LFUN_RECONFIGURE:
974 case LFUN_HELP_OPEN: {
975 string const arg = argument;
977 setErrorMessage(N_("Missing argument"));
980 string const fname = i18nLibFileSearch("doc", arg, "lyx");
982 lyxerr << "LyX: unable to find documentation file `"
983 << arg << "'. Bad installation?" << endl;
986 owner->message(bformat(_("Opening help file %1$s..."),
987 MakeDisplayPath(fname)));
988 view()->loadLyXFile(fname, false);
992 // --- version control -------------------------------
993 case LFUN_VC_REGISTER:
994 if (!ensureBufferClean(view()))
996 if (!owner->buffer()->lyxvc().inUse()) {
997 owner->buffer()->lyxvc().registrer();
1002 case LFUN_VC_CHECKIN:
1003 if (!ensureBufferClean(view()))
1005 if (owner->buffer()->lyxvc().inUse()
1006 && !owner->buffer()->isReadonly()) {
1007 owner->buffer()->lyxvc().checkIn();
1012 case LFUN_VC_CHECKOUT:
1013 if (!ensureBufferClean(view()))
1015 if (owner->buffer()->lyxvc().inUse()
1016 && owner->buffer()->isReadonly()) {
1017 owner->buffer()->lyxvc().checkOut();
1022 case LFUN_VC_REVERT:
1023 owner->buffer()->lyxvc().revert();
1028 owner->buffer()->lyxvc().undoLast();
1032 // --- buffers ----------------------------------------
1033 case LFUN_SWITCHBUFFER:
1034 view()->setBuffer(bufferlist.getBuffer(argument));
1037 case LFUN_NEXTBUFFER:
1038 view()->setBuffer(bufferlist.next(view()->buffer()));
1041 case LFUN_PREVIOUSBUFFER:
1042 view()->setBuffer(bufferlist.previous(view()->buffer()));
1046 NewFile(view(), argument);
1049 case LFUN_FILE_OPEN:
1053 case LFUN_DROP_LAYOUTS_CHOICE:
1054 owner->getToolbars().openLayoutList();
1057 case LFUN_MENU_OPEN_BY_NAME:
1058 owner->getMenubar().openByName(argument);
1061 // --- lyxserver commands ----------------------------
1063 setMessage(owner->buffer()->fileName());
1064 lyxerr[Debug::INFO] << "FNAME["
1065 << owner->buffer()->fileName()
1070 dispatch_buffer = keyseq.print();
1071 lyxserver->notifyClient(dispatch_buffer);
1074 case LFUN_GOTOFILEROW: {
1077 istringstream is(argument);
1078 is >> file_name >> row;
1079 if (prefixIs(file_name, package().temp_dir())) {
1080 // Needed by inverse dvi search. If it is a file
1081 // in tmpdir, call the apropriated function
1082 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1084 // Must replace extension of the file to be .lyx
1085 // and get full path
1086 string const s = ChangeExtension(file_name, ".lyx");
1087 // Either change buffer or load the file
1088 if (bufferlist.exists(s)) {
1089 view()->setBuffer(bufferlist.getBuffer(s));
1091 view()->loadLyXFile(s);
1095 view()->setCursorFromRow(row);
1098 // see BufferView_pimpl::center()
1099 view()->updateScrollbar();
1103 case LFUN_DIALOG_SHOW: {
1104 string const name = cmd.getArg(0);
1105 string data = trim(cmd.argument.substr(name.size()));
1107 if (name == "character") {
1108 data = freefont2string();
1110 owner->getDialogs().show("character", data);
1113 else if (name == "latexlog") {
1114 pair<Buffer::LogType, string> const logfile =
1115 owner->buffer()->getLogName();
1116 switch (logfile.first) {
1117 case Buffer::latexlog:
1120 case Buffer::buildlog:
1124 data += logfile.second;
1125 owner->getDialogs().show("log", data);
1127 else if (name == "vclog") {
1128 string const data = "vc " +
1129 owner->buffer()->lyxvc().getLogFile();
1130 owner->getDialogs().show("log", data);
1133 owner->getDialogs().show(name, data);
1137 case LFUN_DIALOG_SHOW_NEW_INSET: {
1138 string const name = cmd.getArg(0);
1139 string data = trim(cmd.argument.substr(name.size()));
1140 if (name == "bibitem" ||
1147 InsetCommandParams p(name);
1148 data = InsetCommandMailer::params2string(name, p);
1149 } else if (name == "include") {
1150 InsetCommandParams p(data);
1151 data = InsetIncludeMailer::params2string(p);
1152 } else if (name == "box") {
1153 // \c data == "Boxed" || "Frameless" etc
1154 InsetBoxParams p(data);
1155 data = InsetBoxMailer::params2string(p);
1156 } else if (name == "branch") {
1157 InsetBranchParams p;
1158 data = InsetBranchMailer::params2string(p);
1159 } else if (name == "citation") {
1160 InsetCommandParams p("cite");
1161 data = InsetCommandMailer::params2string(name, p);
1162 } else if (name == "ert") {
1163 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1164 } else if (name == "external") {
1165 InsetExternalParams p;
1166 Buffer const & buffer = *owner->buffer();
1167 data = InsetExternalMailer::params2string(p, buffer);
1168 } else if (name == "float") {
1170 data = InsetFloatMailer::params2string(p);
1171 } else if (name == "graphics") {
1172 InsetGraphicsParams p;
1173 Buffer const & buffer = *owner->buffer();
1174 data = InsetGraphicsMailer::params2string(p, buffer);
1175 } else if (name == "note") {
1177 data = InsetNoteMailer::params2string(p);
1178 } else if (name == "vspace") {
1180 data = InsetVSpaceMailer::params2string(space);
1181 } else if (name == "wrap") {
1183 data = InsetWrapMailer::params2string(p);
1185 owner->getDialogs().show(name, data, 0);
1189 case LFUN_DIALOG_SHOW_NEXT_INSET:
1192 case LFUN_DIALOG_UPDATE: {
1193 string const & name = argument;
1194 // Can only update a dialog connected to an existing inset
1195 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1197 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1198 inset->dispatch(view()->cursor(), fr);
1199 } else if (name == "paragraph") {
1200 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1201 } else if (name == "prefs") {
1202 owner->getDialogs().update(name, string());
1207 case LFUN_DIALOG_HIDE:
1208 Dialogs::hide(argument, 0);
1211 case LFUN_DIALOG_DISCONNECT_INSET:
1212 owner->getDialogs().disconnect(argument);
1215 case LFUN_CHILDOPEN: {
1216 string const filename =
1217 MakeAbsPath(argument, owner->buffer()->filePath());
1218 setMessage(N_("Opening child document ") +
1219 MakeDisplayPath(filename) + "...");
1220 view()->savePosition(0);
1221 string const parentfilename = owner->buffer()->fileName();
1222 if (bufferlist.exists(filename))
1223 view()->setBuffer(bufferlist.getBuffer(filename));
1225 view()->loadLyXFile(filename);
1226 // Set the parent name of the child document.
1227 // This makes insertion of citations and references in the child work,
1228 // when the target is in the parent or another child document.
1229 owner->buffer()->setParentName(parentfilename);
1233 case LFUN_TOGGLECURSORFOLLOW:
1234 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1238 owner->getIntl().KeyMapOn(false);
1241 case LFUN_KMAP_PRIM:
1242 owner->getIntl().KeyMapPrim();
1246 owner->getIntl().KeyMapSec();
1249 case LFUN_KMAP_TOGGLE:
1250 owner->getIntl().ToggleKeyMap();
1256 string rest = split(argument, countstr, ' ');
1257 istringstream is(countstr);
1260 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1261 for (int i = 0; i < count; ++i)
1262 dispatch(lyxaction.lookupFunc(rest));
1266 case LFUN_SEQUENCE: {
1267 // argument contains ';'-terminated commands
1268 string arg = argument;
1269 while (!arg.empty()) {
1271 arg = split(arg, first, ';');
1272 FuncRequest func(lyxaction.lookupFunc(first));
1273 func.origin = cmd.origin;
1279 case LFUN_SAVEPREFERENCES: {
1280 Path p(package().user_support());
1281 lyxrc.write("preferences", false);
1285 case LFUN_SCREEN_FONT_UPDATE:
1286 // handle the screen font changes.
1287 lyxrc.set_font_norm_type();
1288 lyx_gui::update_fonts();
1289 // All visible buffers will need resize
1293 case LFUN_SET_COLOR: {
1295 string const x11_name = split(argument, lyx_name, ' ');
1296 if (lyx_name.empty() || x11_name.empty()) {
1297 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1302 bool const graphicsbg_changed =
1303 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1304 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1306 if (!lcolor.setColor(lyx_name, x11_name)) {
1308 bformat(_("Set-color \"%1$s\" failed "
1309 "- color is undefined or "
1310 "may not be redefined"), lyx_name));
1314 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1316 if (graphicsbg_changed) {
1317 #ifdef WITH_WARNINGS
1318 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1321 lyx::graphics::GCache::get().changeDisplay(true);
1328 owner->message(argument);
1331 case LFUN_TOOLTIPS_TOGGLE:
1332 owner->getDialogs().toggleTooltips();
1335 case LFUN_EXTERNAL_EDIT: {
1336 FuncRequest fr(action, argument);
1337 InsetExternal().dispatch(view()->cursor(), fr);
1341 case LFUN_GRAPHICS_EDIT: {
1342 FuncRequest fr(action, argument);
1343 InsetGraphics().dispatch(view()->cursor(), fr);
1347 case LFUN_INSET_APPLY: {
1348 string const name = cmd.getArg(0);
1349 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1351 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1352 inset->dispatch(view()->cursor(), fr);
1354 FuncRequest fr(LFUN_INSET_INSERT, argument);
1357 // ideally, the update flag should be set by the insets,
1358 // but this is not possible currently
1363 case LFUN_ALL_INSETS_TOGGLE: {
1365 string const name = split(argument, action, ' ');
1366 InsetBase::Code const inset_code =
1367 InsetBase::translate(name);
1369 LCursor & cur = view()->cursor();
1370 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1372 InsetBase & inset = owner->buffer()->inset();
1373 InsetIterator it = inset_iterator_begin(inset);
1374 InsetIterator const end = inset_iterator_end(inset);
1375 for (; it != end; ++it) {
1376 if (inset_code == InsetBase::NO_CODE
1377 || inset_code == it->lyxCode())
1378 it->dispatch(cur, fr);
1383 case LFUN_LANGUAGE_BUFFER: {
1384 Buffer & buffer = *owner->buffer();
1385 Language const * oldL = buffer.params().language;
1386 Language const * newL = languages.getLanguage(argument);
1387 if (!newL || oldL == newL)
1390 if (oldL->RightToLeft() == newL->RightToLeft()
1391 && !buffer.isMultiLingual())
1392 buffer.changeLanguage(oldL, newL);
1394 buffer.updateDocLang(newL);
1398 case LFUN_SAVE_AS_DEFAULT: {
1399 string const fname =
1400 AddName(AddPath(package().user_support(), "templates/"),
1402 Buffer defaults(fname);
1404 istringstream ss(argument);
1407 int const unknown_tokens = defaults.readHeader(lex);
1409 if (unknown_tokens != 0) {
1410 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1411 << unknown_tokens << " unknown token"
1412 << (unknown_tokens == 1 ? "" : "s")
1416 if (defaults.writeFile(defaults.fileName()))
1417 setMessage(_("Document defaults saved in ")
1418 + MakeDisplayPath(fname));
1420 setErrorMessage(_("Unable to save document defaults"));
1424 case LFUN_BUFFERPARAMS_APPLY: {
1425 biblio::CiteEngine const engine =
1426 owner->buffer()->params().cite_engine;
1428 istringstream ss(argument);
1431 int const unknown_tokens =
1432 owner->buffer()->readHeader(lex);
1434 if (unknown_tokens != 0) {
1435 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1436 << unknown_tokens << " unknown token"
1437 << (unknown_tokens == 1 ? "" : "s")
1440 if (engine == owner->buffer()->params().cite_engine)
1443 LCursor & cur = view()->cursor();
1444 FuncRequest fr(LFUN_INSET_REFRESH);
1446 InsetBase & inset = owner->buffer()->inset();
1447 InsetIterator it = inset_iterator_begin(inset);
1448 InsetIterator const end = inset_iterator_end(inset);
1449 for (; it != end; ++it)
1450 if (it->lyxCode() == InsetBase::CITE_CODE)
1451 it->dispatch(cur, fr);
1455 case LFUN_TEXTCLASS_APPLY: {
1456 recordUndoFullDocument(view());
1457 Buffer * buffer = owner->buffer();
1459 lyx::textclass_type const old_class =
1460 buffer->params().textclass;
1462 loadTextclass(argument);
1464 std::pair<bool, lyx::textclass_type> const tc_pair =
1465 textclasslist.NumberOfClass(argument);
1470 lyx::textclass_type const new_class = tc_pair.second;
1471 if (old_class == new_class)
1475 owner->message(_("Converting document to new document class..."));
1476 StableDocIterator backcur(view()->cursor());
1478 lyx::cap::SwitchBetweenClasses(
1479 old_class, new_class,
1480 buffer->paragraphs(), el);
1482 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1483 bufferErrors(*buffer, el);
1484 view()->showErrorList(_("Class switch"));
1485 updateCounters(*buffer);
1490 case LFUN_TEXTCLASS_LOAD:
1491 loadTextclass(argument);
1494 case LFUN_LYXRC_APPLY: {
1495 LyXRC const lyxrc_orig = lyxrc;
1497 istringstream ss(argument);
1498 bool const success = lyxrc.read(ss) == 0;
1501 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1502 << "Unable to read lyxrc data"
1507 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1512 view()->cursor().dispatch(cmd);
1513 update |= view()->cursor().result().update();
1514 if (!view()->cursor().result().dispatched())
1515 update |= view()->dispatch(cmd);
1520 if (view()->available()) {
1521 // Redraw screen unless explicitly told otherwise.
1522 // This also initializes the position cache for all insets
1523 // in (at least partially) visible top-level paragraphs.
1525 view()->update(Update::FitCursor | Update::Force);
1527 view()->update(Update::FitCursor);
1529 // if we executed a mutating lfun, mark the buffer as dirty
1530 // FIXME: Why not use flag.enabled() but call getStatus again?
1531 if (getStatus(cmd).enabled()
1532 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1533 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1534 view()->buffer()->markDirty();
1537 if (view()->cursor().inTexted()) {
1538 view()->owner()->updateLayoutChoice();
1541 sendDispatchMessage(_(getMessage()), cmd);
1545 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1547 owner->updateMenubar();
1548 owner->updateToolbars();
1550 const bool verbose = (cmd.origin == FuncRequest::UI
1551 || cmd.origin == FuncRequest::COMMANDBUFFER);
1553 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1554 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1556 owner->message(msg);
1560 string dispatch_msg = msg;
1561 if (!dispatch_msg.empty())
1562 dispatch_msg += ' ';
1564 string comname = lyxaction.getActionName(cmd.action);
1566 bool argsadded = false;
1568 if (!cmd.argument.empty()) {
1569 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1570 comname += ' ' + cmd.argument;
1575 string const shortcuts = toplevel_keymap->printbindings(cmd);
1577 if (!shortcuts.empty())
1578 comname += ": " + shortcuts;
1579 else if (!argsadded && !cmd.argument.empty())
1580 comname += ' ' + cmd.argument;
1582 if (!comname.empty()) {
1583 comname = rtrim(comname);
1584 dispatch_msg += '(' + rtrim(comname) + ')';
1587 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1588 if (!dispatch_msg.empty())
1589 owner->message(dispatch_msg);
1593 void LyXFunc::setupLocalKeymap()
1595 keyseq.stdmap = toplevel_keymap.get();
1596 keyseq.curmap = toplevel_keymap.get();
1597 cancel_meta_seq.stdmap = toplevel_keymap.get();
1598 cancel_meta_seq.curmap = toplevel_keymap.get();
1602 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1604 string initpath = lyxrc.document_path;
1605 string filename(name);
1607 if (view()->available()) {
1608 string const trypath = owner->buffer()->filePath();
1609 // If directory is writeable, use this as default.
1610 if (IsDirWriteable(trypath))
1614 static int newfile_number;
1616 if (filename.empty()) {
1617 filename = AddName(lyxrc.document_path,
1618 "newfile" + convert<string>(++newfile_number) + ".lyx");
1619 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1621 filename = AddName(lyxrc.document_path,
1622 "newfile" + convert<string>(newfile_number) +
1627 // The template stuff
1630 FileDialog fileDlg(_("Select template file"),
1631 LFUN_SELECT_FILE_SYNC,
1632 make_pair(string(_("Documents|#o#O")),
1633 string(lyxrc.document_path)),
1634 make_pair(string(_("Templates|#T#t")),
1635 string(lyxrc.template_path)));
1637 FileDialog::Result result =
1638 fileDlg.open(lyxrc.template_path,
1639 FileFilterList(_("LyX Documents (*.lyx)")),
1642 if (result.first == FileDialog::Later)
1644 if (result.second.empty())
1646 templname = result.second;
1649 view()->newFile(filename, templname, !name.empty());
1653 void LyXFunc::open(string const & fname)
1655 string initpath = lyxrc.document_path;
1657 if (view()->available()) {
1658 string const trypath = owner->buffer()->filePath();
1659 // If directory is writeable, use this as default.
1660 if (IsDirWriteable(trypath))
1666 if (fname.empty()) {
1667 FileDialog fileDlg(_("Select document to open"),
1669 make_pair(string(_("Documents|#o#O")),
1670 string(lyxrc.document_path)),
1671 make_pair(string(_("Examples|#E#e")),
1672 string(AddPath(package().system_support(), "examples"))));
1674 FileDialog::Result result =
1675 fileDlg.open(initpath,
1676 FileFilterList(_("LyX Documents (*.lyx)")),
1679 if (result.first == FileDialog::Later)
1682 filename = result.second;
1684 // check selected filename
1685 if (filename.empty()) {
1686 owner->message(_("Canceled."));
1692 // get absolute path of file and add ".lyx" to the filename if
1694 string const fullpath = FileSearch(string(), filename, "lyx");
1695 if (!fullpath.empty()) {
1696 filename = fullpath;
1699 string const disp_fn(MakeDisplayPath(filename));
1701 // if the file doesn't exist, let the user create one
1702 if (!fs::exists(filename)) {
1703 // the user specifically chose this name. Believe them.
1704 view()->newFile(filename, "", true);
1708 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1711 if (view()->loadLyXFile(filename)) {
1712 str2 = bformat(_("Document %1$s opened."), disp_fn);
1714 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1716 owner->message(str2);
1720 void LyXFunc::doImport(string const & argument)
1723 string filename = split(argument, format, ' ');
1725 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1726 << " file: " << filename << endl;
1728 // need user interaction
1729 if (filename.empty()) {
1730 string initpath = lyxrc.document_path;
1732 if (view()->available()) {
1733 string const trypath = owner->buffer()->filePath();
1734 // If directory is writeable, use this as default.
1735 if (IsDirWriteable(trypath))
1739 string const text = bformat(_("Select %1$s file to import"),
1740 formats.prettyName(format));
1742 FileDialog fileDlg(text,
1744 make_pair(string(_("Documents|#o#O")),
1745 string(lyxrc.document_path)),
1746 make_pair(string(_("Examples|#E#e")),
1747 string(AddPath(package().system_support(), "examples"))));
1749 string const filter = formats.prettyName(format)
1750 + " (*." + formats.extension(format) + ')';
1752 FileDialog::Result result =
1753 fileDlg.open(initpath,
1754 FileFilterList(filter),
1757 if (result.first == FileDialog::Later)
1760 filename = result.second;
1762 // check selected filename
1763 if (filename.empty())
1764 owner->message(_("Canceled."));
1767 if (filename.empty())
1770 // get absolute path of file
1771 filename = MakeAbsPath(filename);
1773 string const lyxfile = ChangeExtension(filename, ".lyx");
1775 // Check if the document already is open
1776 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1777 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1778 owner->message(_("Canceled."));
1783 // if the file exists already, and we didn't do
1784 // -i lyx thefile.lyx, warn
1785 if (fs::exists(lyxfile) && filename != lyxfile) {
1786 string const file = MakeDisplayPath(lyxfile, 30);
1788 string text = bformat(_("The document %1$s already exists.\n\n"
1789 "Do you want to over-write that document?"), file);
1790 int const ret = Alert::prompt(_("Over-write document?"),
1791 text, 0, 1, _("&Over-write"), _("&Cancel"));
1794 owner->message(_("Canceled."));
1799 Importer::Import(owner, filename, format);
1803 void LyXFunc::closeBuffer()
1805 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1806 if (bufferlist.empty()) {
1807 // need this otherwise SEGV may occur while
1808 // trying to set variables that don't exist
1809 // since there's no current buffer
1810 owner->getDialogs().hideBufferDependent();
1812 view()->setBuffer(bufferlist.first());
1818 // Each "owner" should have it's own message method. lyxview and
1819 // the minibuffer would use the minibuffer, but lyxserver would
1820 // send an ERROR signal to its client. Alejandro 970603
1821 // This function is bit problematic when it comes to NLS, to make the
1822 // lyx servers client be language indepenent we must not translate
1823 // strings sent to this func.
1824 void LyXFunc::setErrorMessage(string const & m) const
1826 dispatch_buffer = m;
1831 void LyXFunc::setMessage(string const & m) const
1833 dispatch_buffer = m;
1837 string const LyXFunc::viewStatusMessage()
1839 // When meta-fake key is pressed, show the key sequence so far + "M-".
1841 return keyseq.print() + "M-";
1843 // Else, when a non-complete key sequence is pressed,
1844 // show the available options.
1845 if (keyseq.length() > 0 && !keyseq.deleted())
1846 return keyseq.printOptions();
1848 if (!view()->available())
1849 return _("Welcome to LyX!");
1851 return view()->cursor().currentState();
1855 BufferView * LyXFunc::view() const
1857 BOOST_ASSERT(owner);
1858 return owner->view().get();
1862 bool LyXFunc::wasMetaKey() const
1864 return (meta_fake_bit != key_modifier::none);
1870 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1872 // Why the switch you might ask. It is a trick to ensure that all
1873 // the elements in the LyXRCTags enum is handled. As you can see
1874 // there are no breaks at all. So it is just a huge fall-through.
1875 // The nice thing is that we will get a warning from the compiler
1876 // if we forget an element.
1877 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1879 case LyXRC::RC_ACCEPT_COMPOUND:
1880 case LyXRC::RC_ALT_LANG:
1881 case LyXRC::RC_ASCIIROFF_COMMAND:
1882 case LyXRC::RC_ASCII_LINELEN:
1883 case LyXRC::RC_AUTOREGIONDELETE:
1884 case LyXRC::RC_AUTORESET_OPTIONS:
1885 case LyXRC::RC_AUTOSAVE:
1886 case LyXRC::RC_AUTO_NUMBER:
1887 case LyXRC::RC_BACKUPDIR_PATH:
1888 case LyXRC::RC_BIBTEX_COMMAND:
1889 case LyXRC::RC_BINDFILE:
1890 case LyXRC::RC_CHECKLASTFILES:
1891 case LyXRC::RC_CHKTEX_COMMAND:
1892 case LyXRC::RC_CONVERTER:
1893 case LyXRC::RC_COPIER:
1894 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1895 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1896 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1897 case LyXRC::RC_CYGWIN_PATH_FIX:
1898 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1899 namespace os = lyx::support::os;
1900 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1902 case LyXRC::RC_DATE_INSERT_FORMAT:
1903 case LyXRC::RC_DEFAULT_LANGUAGE:
1904 case LyXRC::RC_DEFAULT_PAPERSIZE:
1905 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1906 case LyXRC::RC_DISPLAY_GRAPHICS:
1907 case LyXRC::RC_DOCUMENTPATH:
1908 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1909 if (fs::exists(lyxrc_new.document_path) &&
1910 fs::is_directory(lyxrc_new.document_path)) {
1911 using lyx::support::package;
1912 package().document_dir() = lyxrc.document_path;
1915 case LyXRC::RC_ESC_CHARS:
1916 case LyXRC::RC_FONT_ENCODING:
1917 case LyXRC::RC_FORMAT:
1918 case LyXRC::RC_INDEX_COMMAND:
1919 case LyXRC::RC_INPUT:
1920 case LyXRC::RC_KBMAP:
1921 case LyXRC::RC_KBMAP_PRIMARY:
1922 case LyXRC::RC_KBMAP_SECONDARY:
1923 case LyXRC::RC_LABEL_INIT_LENGTH:
1924 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1925 case LyXRC::RC_LANGUAGE_AUTO_END:
1926 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1927 case LyXRC::RC_LANGUAGE_COMMAND_END:
1928 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1929 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1930 case LyXRC::RC_LANGUAGE_PACKAGE:
1931 case LyXRC::RC_LANGUAGE_USE_BABEL:
1932 case LyXRC::RC_LASTFILES:
1933 case LyXRC::RC_MAKE_BACKUP:
1934 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1935 case LyXRC::RC_NUMLASTFILES:
1936 case LyXRC::RC_PATH_PREFIX:
1937 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1938 using lyx::support::prependEnvPath;
1939 prependEnvPath("PATH", lyxrc.path_prefix);
1941 case LyXRC::RC_PERS_DICT:
1942 case LyXRC::RC_POPUP_BOLD_FONT:
1943 case LyXRC::RC_POPUP_FONT_ENCODING:
1944 case LyXRC::RC_POPUP_NORMAL_FONT:
1945 case LyXRC::RC_PREVIEW:
1946 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1947 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1948 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1949 case LyXRC::RC_PRINTCOPIESFLAG:
1950 case LyXRC::RC_PRINTER:
1951 case LyXRC::RC_PRINTEVENPAGEFLAG:
1952 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1953 case LyXRC::RC_PRINTFILEEXTENSION:
1954 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1955 case LyXRC::RC_PRINTODDPAGEFLAG:
1956 case LyXRC::RC_PRINTPAGERANGEFLAG:
1957 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1958 case LyXRC::RC_PRINTPAPERFLAG:
1959 case LyXRC::RC_PRINTREVERSEFLAG:
1960 case LyXRC::RC_PRINTSPOOL_COMMAND:
1961 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1962 case LyXRC::RC_PRINTTOFILE:
1963 case LyXRC::RC_PRINTTOPRINTER:
1964 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1965 case LyXRC::RC_PRINT_COMMAND:
1966 case LyXRC::RC_RTL_SUPPORT:
1967 case LyXRC::RC_SCREEN_DPI:
1968 case LyXRC::RC_SCREEN_FONT_ENCODING:
1969 case LyXRC::RC_SCREEN_FONT_ROMAN:
1970 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1971 case LyXRC::RC_SCREEN_FONT_SANS:
1972 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1973 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1974 case LyXRC::RC_SCREEN_FONT_SIZES:
1975 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1976 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1977 case LyXRC::RC_SCREEN_ZOOM:
1978 case LyXRC::RC_SERVERPIPE:
1979 case LyXRC::RC_SET_COLOR:
1980 case LyXRC::RC_SHOW_BANNER:
1981 case LyXRC::RC_SPELL_COMMAND:
1982 case LyXRC::RC_TEMPDIRPATH:
1983 case LyXRC::RC_TEMPLATEPATH:
1984 case LyXRC::RC_TEX_ALLOWS_SPACES:
1985 case LyXRC::RC_UIFILE:
1986 case LyXRC::RC_USER_EMAIL:
1987 case LyXRC::RC_USER_NAME:
1988 case LyXRC::RC_USETEMPDIR:
1989 case LyXRC::RC_USE_ALT_LANG:
1990 case LyXRC::RC_USE_ESC_CHARS:
1991 case LyXRC::RC_USE_INP_ENC:
1992 case LyXRC::RC_USE_PERS_DICT:
1993 case LyXRC::RC_USE_SPELL_LIB:
1994 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1995 case LyXRC::RC_VIEWER:
1996 case LyXRC::RC_WHEEL_JUMP:
1997 case LyXRC::RC_LAST: