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/insetnote.h"
68 #include "insets/insettabular.h"
69 #include "insets/insetvspace.h"
70 #include "insets/insetwrap.h"
72 #include "frontends/Alert.h"
73 #include "frontends/Dialogs.h"
74 #include "frontends/FileDialog.h"
75 #include "frontends/lyx_gui.h"
76 #include "frontends/LyXKeySym.h"
77 #include "frontends/LyXView.h"
78 #include "frontends/Menubar.h"
79 #include "frontends/Toolbars.h"
81 #include "support/environment.h"
82 #include "support/filefilterlist.h"
83 #include "support/filetools.h"
84 #include "support/forkedcontr.h"
85 #include "support/fs_extras.h"
86 #include "support/lstrings.h"
87 #include "support/path.h"
88 #include "support/package.h"
89 #include "support/systemcall.h"
90 #include "support/convert.h"
91 #include "support/os.h"
93 #include <boost/current_function.hpp>
94 #include <boost/filesystem/operations.hpp>
98 using bv_funcs::freefont2string;
100 using lyx::support::AbsolutePath;
101 using lyx::support::AddName;
102 using lyx::support::AddPath;
103 using lyx::support::bformat;
104 using lyx::support::ChangeExtension;
105 using lyx::support::contains;
106 using lyx::support::FileFilterList;
107 using lyx::support::FileSearch;
108 using lyx::support::ForkedcallsController;
109 using lyx::support::i18nLibFileSearch;
110 using lyx::support::IsDirWriteable;
111 using lyx::support::IsFileReadable;
112 using lyx::support::isStrInt;
113 using lyx::support::MakeAbsPath;
114 using lyx::support::MakeDisplayPath;
115 using lyx::support::package;
116 using lyx::support::Path;
117 using lyx::support::QuoteName;
118 using lyx::support::rtrim;
119 using lyx::support::split;
120 using lyx::support::subst;
121 using lyx::support::Systemcall;
122 using lyx::support::token;
123 using lyx::support::trim;
124 using lyx::support::prefixIs;
127 using std::make_pair;
130 using std::istringstream;
132 namespace biblio = lyx::biblio;
133 namespace fs = boost::filesystem;
136 extern BufferList bufferlist;
137 extern LyXServer * lyxserver;
139 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
142 extern tex_accent_struct get_accent(kb_action action);
147 bool getStatus(LCursor cursor,
148 FuncRequest const & cmd, FuncStatus & status)
150 // Try to fix cursor in case it is broken.
151 cursor.fixIfBroken();
153 // This is, of course, a mess. Better create a new doc iterator and use
154 // this in Inset::getStatus. This might require an additional
155 // BufferView * arg, though (which should be avoided)
156 //LCursor safe = *this;
158 for ( ; cursor.depth(); cursor.pop()) {
159 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
160 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
161 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
162 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
164 // The inset's getStatus() will return 'true' if it made
165 // a definitive decision on whether it want to handle the
166 // request or not. The result of this decision is put into
167 // the 'status' parameter.
168 if (cursor.inset().getStatus(cursor, cmd, status)) {
178 LyXFunc::LyXFunc(LyXView * lv)
181 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
182 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
183 meta_fake_bit(key_modifier::none)
188 void LyXFunc::handleKeyFunc(kb_action action)
190 char c = encoded_last_key;
192 if (keyseq.length()) {
196 owner->getIntl().getTransManager()
197 .deadkey(c, get_accent(action).accent, view()->getLyXText());
198 // Need to clear, in case the minibuffer calls these
201 // copied verbatim from do_accent_char
202 view()->cursor().resetAnchor();
207 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
209 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
211 // Do nothing if we have nothing (JMarc)
212 if (!keysym->isOK()) {
213 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
218 if (keysym->isModifier()) {
219 lyxerr[Debug::KEY] << "isModifier true" << endl;
223 Encoding const * encoding = view()->cursor().getEncoding();
225 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
227 // Do a one-deep top-level lookup for
228 // cancel and meta-fake keys. RVDK_PATCH_5
229 cancel_meta_seq.reset();
231 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
232 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
233 << " action first set to [" << func.action << ']'
236 // When not cancel or meta-fake, do the normal lookup.
237 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
238 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
239 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
240 // remove Caps Lock and Mod2 as a modifiers
241 func = keyseq.addkey(keysym, (state | meta_fake_bit));
242 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
243 << "action now set to ["
244 << func.action << ']' << endl;
247 // Dont remove this unless you know what you are doing.
248 meta_fake_bit = key_modifier::none;
250 // Can this happen now ?
251 if (func.action == LFUN_NOACTION) {
252 func = FuncRequest(LFUN_PREFIX);
255 if (lyxerr.debugging(Debug::KEY)) {
256 lyxerr << BOOST_CURRENT_FUNCTION
258 << func.action << "]["
259 << keyseq.print() << ']'
263 // already here we know if it any point in going further
264 // why not return already here if action == -1 and
265 // num_bytes == 0? (Lgb)
267 if (keyseq.length() > 1) {
268 owner->message(keyseq.print());
272 // Maybe user can only reach the key via holding down shift.
273 // Let's see. But only if shift is the only modifier
274 if (func.action == LFUN_UNKNOWN_ACTION &&
275 state == key_modifier::shift) {
276 lyxerr[Debug::KEY] << "Trying without shift" << endl;
277 func = keyseq.addkey(keysym, key_modifier::none);
278 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
281 if (func.action == LFUN_UNKNOWN_ACTION) {
282 // Hmm, we didn't match any of the keysequences. See
283 // if it's normal insertable text not already covered
285 if (keysym->isText() && keyseq.length() == 1) {
286 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
287 func = FuncRequest(LFUN_SELFINSERT);
289 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
290 owner->message(_("Unknown function."));
295 if (func.action == LFUN_SELFINSERT) {
296 if (encoded_last_key != 0) {
297 string const arg(1, encoded_last_key);
298 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
300 << "SelfInsert arg[`" << arg << "']" << endl;
308 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
310 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
312 LCursor & cur = view()->cursor();
314 /* In LyX/Mac, when a dialog is open, the menus of the
315 application can still be accessed without giving focus to
316 the main window. In this case, we want to disable the menu
317 entries that are buffer-related.
320 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
323 buf = owner->buffer();
325 if (cmd.action == LFUN_NOACTION) {
326 flag.message(N_("Nothing to do"));
331 switch (cmd.action) {
332 case LFUN_UNKNOWN_ACTION:
333 #ifndef HAVE_LIBAIKSAURUS
334 case LFUN_THESAURUS_ENTRY:
340 flag |= lyx_gui::getStatus(cmd);
343 if (flag.unknown()) {
344 flag.message(N_("Unknown action"));
348 if (!flag.enabled()) {
349 if (flag.message().empty())
350 flag.message(N_("Command disabled"));
354 // Check whether we need a buffer
355 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
357 flag.message(N_("Command not allowed with"
358 "out any document open"));
363 // I would really like to avoid having this switch and rather try to
364 // encode this in the function itself.
365 // -- And I'd rather let an inset decide which LFUNs it is willing
366 // to handle (Andre')
368 switch (cmd.action) {
369 case LFUN_TOOLTIPS_TOGGLE:
370 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
373 case LFUN_READ_ONLY_TOGGLE:
374 flag.setOnOff(buf->isReadonly());
377 case LFUN_SWITCHBUFFER:
378 // toggle on the current buffer, but do not toggle off
379 // the other ones (is that a good idea?)
380 if (cmd.argument == buf->fileName())
385 enable = cmd.argument == "custom"
386 || Exporter::IsExportable(*buf, cmd.argument);
390 enable = cur.selection();
394 enable = buf->isLatex() && lyxrc.chktex_command != "none";
398 enable = Exporter::IsExportable(*buf, "program");
401 case LFUN_LAYOUT_TABULAR:
402 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
406 case LFUN_LAYOUT_PARAGRAPH:
407 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
410 case LFUN_VC_REGISTER:
411 enable = !buf->lyxvc().inUse();
413 case LFUN_VC_CHECKIN:
414 enable = buf->lyxvc().inUse() && !buf->isReadonly();
416 case LFUN_VC_CHECKOUT:
417 enable = buf->lyxvc().inUse() && buf->isReadonly();
421 enable = buf->lyxvc().inUse();
423 case LFUN_MENURELOAD:
424 enable = !buf->isUnnamed() && !buf->isClean();
427 case LFUN_INSET_SETTINGS: {
431 UpdatableInset * inset = cur.inset().asUpdatableInset();
432 lyxerr << "inset: " << inset << endl;
436 InsetBase::Code code = inset->lyxCode();
438 case InsetBase::TABULAR_CODE:
439 enable = cmd.argument == "tabular";
441 case InsetBase::ERT_CODE:
442 enable = cmd.argument == "ert";
444 case InsetBase::FLOAT_CODE:
445 enable = cmd.argument == "float";
447 case InsetBase::WRAP_CODE:
448 enable = cmd.argument == "wrap";
450 case InsetBase::NOTE_CODE:
451 enable = cmd.argument == "note";
453 case InsetBase::BRANCH_CODE:
454 enable = cmd.argument == "branch";
456 case InsetBase::BOX_CODE:
457 enable = cmd.argument == "box";
465 case LFUN_INSET_APPLY: {
466 string const name = cmd.getArg(0);
467 InsetBase * inset = owner->getDialogs().getOpenInset(name);
469 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
471 bool const success = inset->getStatus(cur, fr, fs);
472 // Every inset is supposed to handle this
473 BOOST_ASSERT(success);
476 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
477 flag |= getStatus(fr);
479 enable = flag.enabled();
483 case LFUN_DIALOG_SHOW: {
484 string const name = cmd.getArg(0);
486 enable = name == "aboutlyx"
490 || name == "texinfo";
491 else if (name == "print")
492 enable = Exporter::IsExportable(*buf, "dvi")
493 && lyxrc.print_command != "none";
494 else if (name == "character" || name == "mathpanel")
495 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
496 else if (name == "vclog")
497 enable = buf->lyxvc().inUse();
498 else if (name == "latexlog")
499 enable = IsFileReadable(buf->getLogName().second);
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());
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" ||
1142 name == "include" ||
1148 InsetCommandParams p(name);
1149 data = InsetCommandMailer::params2string(name, p);
1150 } else if (name == "box") {
1151 // \c data == "Boxed" || "Frameless" etc
1152 InsetBoxParams p(data);
1153 data = InsetBoxMailer::params2string(p);
1154 } else if (name == "branch") {
1155 InsetBranchParams p;
1156 data = InsetBranchMailer::params2string(p);
1157 } else if (name == "citation") {
1158 InsetCommandParams p("cite");
1159 data = InsetCommandMailer::params2string(name, p);
1160 } else if (name == "ert") {
1161 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1162 } else if (name == "external") {
1163 InsetExternalParams p;
1164 Buffer const & buffer = *owner->buffer();
1165 data = InsetExternalMailer::params2string(p, buffer);
1166 } else if (name == "float") {
1168 data = InsetFloatMailer::params2string(p);
1169 } else if (name == "graphics") {
1170 InsetGraphicsParams p;
1171 Buffer const & buffer = *owner->buffer();
1172 data = InsetGraphicsMailer::params2string(p, buffer);
1173 } else if (name == "note") {
1175 data = InsetNoteMailer::params2string(p);
1176 } else if (name == "vspace") {
1178 data = InsetVSpaceMailer::params2string(space);
1179 } else if (name == "wrap") {
1181 data = InsetWrapMailer::params2string(p);
1183 owner->getDialogs().show(name, data, 0);
1187 case LFUN_DIALOG_SHOW_NEXT_INSET:
1190 case LFUN_DIALOG_UPDATE: {
1191 string const & name = argument;
1192 // Can only update a dialog connected to an existing inset
1193 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1195 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1196 inset->dispatch(view()->cursor(), fr);
1197 } else if (name == "paragraph") {
1198 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1199 } else if (name == "prefs") {
1200 owner->getDialogs().update(name, string());
1205 case LFUN_DIALOG_HIDE:
1206 Dialogs::hide(argument, 0);
1209 case LFUN_DIALOG_DISCONNECT_INSET:
1210 owner->getDialogs().disconnect(argument);
1213 case LFUN_CHILDOPEN: {
1214 string const filename =
1215 MakeAbsPath(argument, owner->buffer()->filePath());
1216 setMessage(N_("Opening child document ") +
1217 MakeDisplayPath(filename) + "...");
1218 view()->savePosition(0);
1219 string const parentfilename = owner->buffer()->fileName();
1220 if (bufferlist.exists(filename))
1221 view()->setBuffer(bufferlist.getBuffer(filename));
1223 view()->loadLyXFile(filename);
1224 // Set the parent name of the child document.
1225 // This makes insertion of citations and references in the child work,
1226 // when the target is in the parent or another child document.
1227 owner->buffer()->setParentName(parentfilename);
1231 case LFUN_TOGGLECURSORFOLLOW:
1232 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1236 owner->getIntl().KeyMapOn(false);
1239 case LFUN_KMAP_PRIM:
1240 owner->getIntl().KeyMapPrim();
1244 owner->getIntl().KeyMapSec();
1247 case LFUN_KMAP_TOGGLE:
1248 owner->getIntl().ToggleKeyMap();
1254 string rest = split(argument, countstr, ' ');
1255 istringstream is(countstr);
1258 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1259 for (int i = 0; i < count; ++i)
1260 dispatch(lyxaction.lookupFunc(rest));
1264 case LFUN_SEQUENCE: {
1265 // argument contains ';'-terminated commands
1266 string arg = argument;
1267 while (!arg.empty()) {
1269 arg = split(arg, first, ';');
1270 FuncRequest func(lyxaction.lookupFunc(first));
1271 func.origin = cmd.origin;
1277 case LFUN_SAVEPREFERENCES: {
1278 Path p(package().user_support());
1279 lyxrc.write("preferences", false);
1283 case LFUN_SCREEN_FONT_UPDATE:
1284 // handle the screen font changes.
1285 lyxrc.set_font_norm_type();
1286 lyx_gui::update_fonts();
1287 // All visible buffers will need resize
1291 case LFUN_SET_COLOR: {
1293 string const x11_name = split(argument, lyx_name, ' ');
1294 if (lyx_name.empty() || x11_name.empty()) {
1295 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1300 bool const graphicsbg_changed =
1301 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1302 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1304 if (!lcolor.setColor(lyx_name, x11_name)) {
1306 bformat(_("Set-color \"%1$s\" failed "
1307 "- color is undefined or "
1308 "may not be redefined"), lyx_name));
1312 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1314 if (graphicsbg_changed) {
1315 #ifdef WITH_WARNINGS
1316 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1319 lyx::graphics::GCache::get().changeDisplay(true);
1326 owner->message(argument);
1329 case LFUN_TOOLTIPS_TOGGLE:
1330 owner->getDialogs().toggleTooltips();
1333 case LFUN_EXTERNAL_EDIT: {
1334 FuncRequest fr(action, argument);
1335 InsetExternal().dispatch(view()->cursor(), fr);
1339 case LFUN_GRAPHICS_EDIT: {
1340 FuncRequest fr(action, argument);
1341 InsetGraphics().dispatch(view()->cursor(), fr);
1345 case LFUN_INSET_APPLY: {
1346 string const name = cmd.getArg(0);
1347 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1349 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1350 inset->dispatch(view()->cursor(), fr);
1352 FuncRequest fr(LFUN_INSET_INSERT, argument);
1358 case LFUN_ALL_INSETS_TOGGLE: {
1360 string const name = split(argument, action, ' ');
1361 InsetBase::Code const inset_code =
1362 InsetBase::translate(name);
1364 LCursor & cur = view()->cursor();
1365 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1367 InsetBase & inset = owner->buffer()->inset();
1368 InsetIterator it = inset_iterator_begin(inset);
1369 InsetIterator const end = inset_iterator_end(inset);
1370 for (; it != end; ++it) {
1371 if (inset_code == InsetBase::NO_CODE
1372 || inset_code == it->lyxCode())
1373 it->dispatch(cur, fr);
1378 case LFUN_LANGUAGE_BUFFER: {
1379 Buffer & buffer = *owner->buffer();
1380 Language const * oldL = buffer.params().language;
1381 Language const * newL = languages.getLanguage(argument);
1382 if (!newL || oldL == newL)
1385 if (oldL->RightToLeft() == newL->RightToLeft()
1386 && !buffer.isMultiLingual())
1387 buffer.changeLanguage(oldL, newL);
1389 buffer.updateDocLang(newL);
1393 case LFUN_SAVE_AS_DEFAULT: {
1394 string const fname =
1395 AddName(AddPath(package().user_support(), "templates/"),
1397 Buffer defaults(fname);
1399 istringstream ss(argument);
1402 int const unknown_tokens = defaults.readHeader(lex);
1404 if (unknown_tokens != 0) {
1405 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1406 << unknown_tokens << " unknown token"
1407 << (unknown_tokens == 1 ? "" : "s")
1411 if (defaults.writeFile(defaults.fileName()))
1412 setMessage(_("Document defaults saved in ")
1413 + MakeDisplayPath(fname));
1415 setErrorMessage(_("Unable to save document defaults"));
1419 case LFUN_BUFFERPARAMS_APPLY: {
1420 biblio::CiteEngine const engine =
1421 owner->buffer()->params().cite_engine;
1423 istringstream ss(argument);
1426 int const unknown_tokens =
1427 owner->buffer()->readHeader(lex);
1429 if (unknown_tokens != 0) {
1430 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1431 << unknown_tokens << " unknown token"
1432 << (unknown_tokens == 1 ? "" : "s")
1435 if (engine == owner->buffer()->params().cite_engine)
1438 LCursor & cur = view()->cursor();
1439 FuncRequest fr(LFUN_INSET_REFRESH);
1441 InsetBase & inset = owner->buffer()->inset();
1442 InsetIterator it = inset_iterator_begin(inset);
1443 InsetIterator const end = inset_iterator_end(inset);
1444 for (; it != end; ++it)
1445 if (it->lyxCode() == InsetBase::CITE_CODE)
1446 it->dispatch(cur, fr);
1450 case LFUN_TEXTCLASS_APPLY: {
1451 Buffer * buffer = owner->buffer();
1453 lyx::textclass_type const old_class =
1454 buffer->params().textclass;
1456 loadTextclass(argument);
1458 std::pair<bool, lyx::textclass_type> const tc_pair =
1459 textclasslist.NumberOfClass(argument);
1464 lyx::textclass_type const new_class = tc_pair.second;
1465 if (old_class == new_class)
1469 owner->message(_("Converting document to new document class..."));
1471 lyx::cap::SwitchBetweenClasses(
1472 old_class, new_class,
1473 buffer->paragraphs(), el);
1475 bufferErrors(*buffer, el);
1476 view()->showErrorList(_("Class switch"));
1477 updateCounters(*buffer);
1482 case LFUN_TEXTCLASS_LOAD:
1483 loadTextclass(argument);
1486 case LFUN_LYXRC_APPLY: {
1487 LyXRC const lyxrc_orig = lyxrc;
1489 istringstream ss(argument);
1490 bool const success = lyxrc.read(ss) == 0;
1493 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1494 << "Unable to read lyxrc data"
1499 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1504 view()->cursor().dispatch(cmd);
1505 update |= view()->cursor().result().update();
1506 if (!view()->cursor().result().dispatched()) {
1507 update |= view()->dispatch(cmd);
1514 if (view()->available()) {
1515 // Redraw screen unless explicitly told otherwise.
1516 // This also initializes the position cache for all insets
1517 // in (at least partially) visible top-level paragraphs.
1518 view()->update(true, update);
1520 // if we executed a mutating lfun, mark the buffer as dirty
1521 // FIXME: Why not use flag.enabled() but call getStatus again?
1522 if (getStatus(cmd).enabled()
1523 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1524 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1525 view()->buffer()->markDirty();
1528 if (view()->cursor().inTexted()) {
1529 view()->owner()->updateLayoutChoice();
1532 sendDispatchMessage(_(getMessage()), cmd);
1536 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1538 owner->updateMenubar();
1539 owner->updateToolbars();
1541 const bool verbose = (cmd.origin == FuncRequest::UI
1542 || cmd.origin == FuncRequest::COMMANDBUFFER);
1544 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1545 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1547 owner->message(msg);
1551 string dispatch_msg = msg;
1552 if (!dispatch_msg.empty())
1553 dispatch_msg += ' ';
1555 string comname = lyxaction.getActionName(cmd.action);
1557 bool argsadded = false;
1559 if (!cmd.argument.empty()) {
1560 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1561 comname += ' ' + cmd.argument;
1566 string const shortcuts = toplevel_keymap->printbindings(cmd);
1568 if (!shortcuts.empty()) {
1569 comname += ": " + shortcuts;
1570 } else if (!argsadded && !cmd.argument.empty()) {
1571 comname += ' ' + cmd.argument;
1574 if (!comname.empty()) {
1575 comname = rtrim(comname);
1576 dispatch_msg += '(' + comname + ')';
1579 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1580 if (!dispatch_msg.empty())
1581 owner->message(dispatch_msg);
1585 void LyXFunc::setupLocalKeymap()
1587 keyseq.stdmap = toplevel_keymap.get();
1588 keyseq.curmap = toplevel_keymap.get();
1589 cancel_meta_seq.stdmap = toplevel_keymap.get();
1590 cancel_meta_seq.curmap = toplevel_keymap.get();
1594 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1596 string initpath = lyxrc.document_path;
1597 string filename(name);
1599 if (view()->available()) {
1600 string const trypath = owner->buffer()->filePath();
1601 // If directory is writeable, use this as default.
1602 if (IsDirWriteable(trypath))
1606 static int newfile_number;
1608 if (filename.empty()) {
1609 filename = AddName(lyxrc.document_path,
1610 "newfile" + convert<string>(++newfile_number) + ".lyx");
1611 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1613 filename = AddName(lyxrc.document_path,
1614 "newfile" + convert<string>(newfile_number) +
1619 // The template stuff
1622 FileDialog fileDlg(_("Select template file"),
1623 LFUN_SELECT_FILE_SYNC,
1624 make_pair(string(_("Documents|#o#O")),
1625 string(lyxrc.document_path)),
1626 make_pair(string(_("Templates|#T#t")),
1627 string(lyxrc.template_path)));
1629 FileDialog::Result result =
1630 fileDlg.open(lyxrc.template_path,
1631 FileFilterList(_("LyX Documents (*.lyx)")),
1634 if (result.first == FileDialog::Later)
1636 if (result.second.empty())
1638 templname = result.second;
1641 view()->newFile(filename, templname, !name.empty());
1645 void LyXFunc::open(string const & fname)
1647 string initpath = lyxrc.document_path;
1649 if (view()->available()) {
1650 string const trypath = owner->buffer()->filePath();
1651 // If directory is writeable, use this as default.
1652 if (IsDirWriteable(trypath))
1658 if (fname.empty()) {
1659 FileDialog fileDlg(_("Select document to open"),
1661 make_pair(string(_("Documents|#o#O")),
1662 string(lyxrc.document_path)),
1663 make_pair(string(_("Examples|#E#e")),
1664 string(AddPath(package().system_support(), "examples"))));
1666 FileDialog::Result result =
1667 fileDlg.open(initpath,
1668 FileFilterList(_("LyX Documents (*.lyx)")),
1671 if (result.first == FileDialog::Later)
1674 filename = result.second;
1676 // check selected filename
1677 if (filename.empty()) {
1678 owner->message(_("Canceled."));
1684 // get absolute path of file and add ".lyx" to the filename if
1686 string const fullpath = FileSearch(string(), filename, "lyx");
1687 if (!fullpath.empty()) {
1688 filename = fullpath;
1691 string const disp_fn(MakeDisplayPath(filename));
1693 // if the file doesn't exist, let the user create one
1694 if (!fs::exists(filename)) {
1695 // the user specifically chose this name. Believe them.
1696 view()->newFile(filename, "", true);
1700 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1703 if (view()->loadLyXFile(filename)) {
1704 str2 = bformat(_("Document %1$s opened."), disp_fn);
1706 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1708 owner->message(str2);
1712 void LyXFunc::doImport(string const & argument)
1715 string filename = split(argument, format, ' ');
1717 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1718 << " file: " << filename << endl;
1720 // need user interaction
1721 if (filename.empty()) {
1722 string initpath = lyxrc.document_path;
1724 if (view()->available()) {
1725 string const trypath = owner->buffer()->filePath();
1726 // If directory is writeable, use this as default.
1727 if (IsDirWriteable(trypath))
1731 string const text = bformat(_("Select %1$s file to import"),
1732 formats.prettyName(format));
1734 FileDialog fileDlg(text,
1736 make_pair(string(_("Documents|#o#O")),
1737 string(lyxrc.document_path)),
1738 make_pair(string(_("Examples|#E#e")),
1739 string(AddPath(package().system_support(), "examples"))));
1741 string const filter = formats.prettyName(format)
1742 + " (*." + formats.extension(format) + ')';
1744 FileDialog::Result result =
1745 fileDlg.open(initpath,
1746 FileFilterList(filter),
1749 if (result.first == FileDialog::Later)
1752 filename = result.second;
1754 // check selected filename
1755 if (filename.empty())
1756 owner->message(_("Canceled."));
1759 if (filename.empty())
1762 // get absolute path of file
1763 filename = MakeAbsPath(filename);
1765 string const lyxfile = ChangeExtension(filename, ".lyx");
1767 // Check if the document already is open
1768 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1769 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1770 owner->message(_("Canceled."));
1775 // if the file exists already, and we didn't do
1776 // -i lyx thefile.lyx, warn
1777 if (fs::exists(lyxfile) && filename != lyxfile) {
1778 string const file = MakeDisplayPath(lyxfile, 30);
1780 string text = bformat(_("The document %1$s already exists.\n\n"
1781 "Do you want to over-write that document?"), file);
1782 int const ret = Alert::prompt(_("Over-write document?"),
1783 text, 0, 1, _("&Over-write"), _("&Cancel"));
1786 owner->message(_("Canceled."));
1791 Importer::Import(owner, filename, format);
1795 void LyXFunc::closeBuffer()
1797 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1798 if (bufferlist.empty()) {
1799 // need this otherwise SEGV may occur while
1800 // trying to set variables that don't exist
1801 // since there's no current buffer
1802 owner->getDialogs().hideBufferDependent();
1804 view()->setBuffer(bufferlist.first());
1810 // Each "owner" should have it's own message method. lyxview and
1811 // the minibuffer would use the minibuffer, but lyxserver would
1812 // send an ERROR signal to its client. Alejandro 970603
1813 // This function is bit problematic when it comes to NLS, to make the
1814 // lyx servers client be language indepenent we must not translate
1815 // strings sent to this func.
1816 void LyXFunc::setErrorMessage(string const & m) const
1818 dispatch_buffer = m;
1823 void LyXFunc::setMessage(string const & m) const
1825 dispatch_buffer = m;
1829 string const LyXFunc::viewStatusMessage()
1831 // When meta-fake key is pressed, show the key sequence so far + "M-".
1833 return keyseq.print() + "M-";
1835 // Else, when a non-complete key sequence is pressed,
1836 // show the available options.
1837 if (keyseq.length() > 0 && !keyseq.deleted())
1838 return keyseq.printOptions();
1840 if (!view()->available())
1841 return _("Welcome to LyX!");
1843 return view()->cursor().currentState();
1847 BufferView * LyXFunc::view() const
1849 BOOST_ASSERT(owner);
1850 return owner->view().get();
1854 bool LyXFunc::wasMetaKey() const
1856 return (meta_fake_bit != key_modifier::none);
1862 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1864 // Why the switch you might ask. It is a trick to ensure that all
1865 // the elements in the LyXRCTags enum is handled. As you can see
1866 // there are no breaks at all. So it is just a huge fall-through.
1867 // The nice thing is that we will get a warning from the compiler
1868 // if we forget an element.
1869 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1871 case LyXRC::RC_ACCEPT_COMPOUND:
1872 case LyXRC::RC_ALT_LANG:
1873 case LyXRC::RC_ASCIIROFF_COMMAND:
1874 case LyXRC::RC_ASCII_LINELEN:
1875 case LyXRC::RC_AUTOREGIONDELETE:
1876 case LyXRC::RC_AUTORESET_OPTIONS:
1877 case LyXRC::RC_AUTOSAVE:
1878 case LyXRC::RC_AUTO_NUMBER:
1879 case LyXRC::RC_BACKUPDIR_PATH:
1880 case LyXRC::RC_BIBTEX_COMMAND:
1881 case LyXRC::RC_BINDFILE:
1882 case LyXRC::RC_CHECKLASTFILES:
1883 case LyXRC::RC_CHKTEX_COMMAND:
1884 case LyXRC::RC_CONVERTER:
1885 case LyXRC::RC_COPIER:
1886 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1887 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1888 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1889 case LyXRC::RC_CYGWIN_PATH_FIX:
1890 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1891 namespace os = lyx::support::os;
1892 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1894 case LyXRC::RC_DATE_INSERT_FORMAT:
1895 case LyXRC::RC_DEFAULT_LANGUAGE:
1896 case LyXRC::RC_DEFAULT_PAPERSIZE:
1897 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1898 case LyXRC::RC_DISPLAY_GRAPHICS:
1899 case LyXRC::RC_DOCUMENTPATH:
1900 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1901 if (fs::exists(lyxrc_new.document_path) &&
1902 fs::is_directory(lyxrc_new.document_path)) {
1903 using lyx::support::package;
1904 package().document_dir() = lyxrc.document_path;
1907 case LyXRC::RC_ESC_CHARS:
1908 case LyXRC::RC_FONT_ENCODING:
1909 case LyXRC::RC_FORMAT:
1910 case LyXRC::RC_INDEX_COMMAND:
1911 case LyXRC::RC_INPUT:
1912 case LyXRC::RC_KBMAP:
1913 case LyXRC::RC_KBMAP_PRIMARY:
1914 case LyXRC::RC_KBMAP_SECONDARY:
1915 case LyXRC::RC_LABEL_INIT_LENGTH:
1916 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1917 case LyXRC::RC_LANGUAGE_AUTO_END:
1918 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1919 case LyXRC::RC_LANGUAGE_COMMAND_END:
1920 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1921 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1922 case LyXRC::RC_LANGUAGE_PACKAGE:
1923 case LyXRC::RC_LANGUAGE_USE_BABEL:
1924 case LyXRC::RC_LASTFILES:
1925 case LyXRC::RC_MAKE_BACKUP:
1926 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1927 case LyXRC::RC_NUMLASTFILES:
1928 case LyXRC::RC_PATH_PREFIX:
1929 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1930 using lyx::support::prependEnvPath;
1931 prependEnvPath("PATH", lyxrc.path_prefix);
1933 case LyXRC::RC_PERS_DICT:
1934 case LyXRC::RC_POPUP_BOLD_FONT:
1935 case LyXRC::RC_POPUP_FONT_ENCODING:
1936 case LyXRC::RC_POPUP_NORMAL_FONT:
1937 case LyXRC::RC_PREVIEW:
1938 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1939 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1940 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1941 case LyXRC::RC_PRINTCOPIESFLAG:
1942 case LyXRC::RC_PRINTER:
1943 case LyXRC::RC_PRINTEVENPAGEFLAG:
1944 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1945 case LyXRC::RC_PRINTFILEEXTENSION:
1946 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1947 case LyXRC::RC_PRINTODDPAGEFLAG:
1948 case LyXRC::RC_PRINTPAGERANGEFLAG:
1949 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1950 case LyXRC::RC_PRINTPAPERFLAG:
1951 case LyXRC::RC_PRINTREVERSEFLAG:
1952 case LyXRC::RC_PRINTSPOOL_COMMAND:
1953 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1954 case LyXRC::RC_PRINTTOFILE:
1955 case LyXRC::RC_PRINTTOPRINTER:
1956 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1957 case LyXRC::RC_PRINT_COMMAND:
1958 case LyXRC::RC_RTL_SUPPORT:
1959 case LyXRC::RC_SCREEN_DPI:
1960 case LyXRC::RC_SCREEN_FONT_ENCODING:
1961 case LyXRC::RC_SCREEN_FONT_ROMAN:
1962 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1963 case LyXRC::RC_SCREEN_FONT_SANS:
1964 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1965 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1966 case LyXRC::RC_SCREEN_FONT_SIZES:
1967 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1968 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1969 case LyXRC::RC_SCREEN_ZOOM:
1970 case LyXRC::RC_SERVERPIPE:
1971 case LyXRC::RC_SET_COLOR:
1972 case LyXRC::RC_SHOW_BANNER:
1973 case LyXRC::RC_SPELL_COMMAND:
1974 case LyXRC::RC_TEMPDIRPATH:
1975 case LyXRC::RC_TEMPLATEPATH:
1976 case LyXRC::RC_TEX_ALLOWS_SPACES:
1977 case LyXRC::RC_UIFILE:
1978 case LyXRC::RC_USER_EMAIL:
1979 case LyXRC::RC_USER_NAME:
1980 case LyXRC::RC_USETEMPDIR:
1981 case LyXRC::RC_USE_ALT_LANG:
1982 case LyXRC::RC_USE_ESC_CHARS:
1983 case LyXRC::RC_USE_INP_ENC:
1984 case LyXRC::RC_USE_PERS_DICT:
1985 case LyXRC::RC_USE_SPELL_LIB:
1986 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1987 case LyXRC::RC_VIEWER:
1988 case LyXRC::RC_WHEEL_JUMP:
1989 case LyXRC::RC_LAST: