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/filefilterlist.h"
82 #include "support/filetools.h"
83 #include "support/forkedcontr.h"
84 #include "support/fs_extras.h"
85 #include "support/lstrings.h"
86 #include "support/path.h"
87 #include "support/package.h"
88 #include "support/systemcall.h"
89 #include "support/convert.h"
90 #include "support/os.h"
92 #include <boost/filesystem/operations.hpp>
96 using bv_funcs::freefont2string;
98 using lyx::support::AbsolutePath;
99 using lyx::support::AddName;
100 using lyx::support::AddPath;
101 using lyx::support::bformat;
102 using lyx::support::ChangeExtension;
103 using lyx::support::contains;
104 using lyx::support::FileFilterList;
105 using lyx::support::FileSearch;
106 using lyx::support::ForkedcallsController;
107 using lyx::support::i18nLibFileSearch;
108 using lyx::support::IsDirWriteable;
109 using lyx::support::IsFileReadable;
110 using lyx::support::isStrInt;
111 using lyx::support::MakeAbsPath;
112 using lyx::support::MakeDisplayPath;
113 using lyx::support::package;
114 using lyx::support::Path;
115 using lyx::support::QuoteName;
116 using lyx::support::rtrim;
117 using lyx::support::split;
118 using lyx::support::subst;
119 using lyx::support::Systemcall;
120 using lyx::support::token;
121 using lyx::support::trim;
122 using lyx::support::prefixIs;
125 using std::make_pair;
128 using std::istringstream;
130 namespace biblio = lyx::biblio;
131 namespace fs = boost::filesystem;
134 extern BufferList bufferlist;
135 extern LyXServer * lyxserver;
137 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
140 extern tex_accent_struct get_accent(kb_action action);
145 bool getStatus(LCursor cursor,
146 FuncRequest const & cmd, FuncStatus & status)
148 // This is, of course, a mess. Better create a new doc iterator and use
149 // this in Inset::getStatus. This might require an additional
150 // BufferView * arg, though (which should be avoided)
151 //LCursor safe = *this;
153 for ( ; cursor.depth(); cursor.pop()) {
154 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
155 DocIterator::idx_type & idx = cursor.idx();
156 DocIterator::idx_type const lastidx = cursor.lastidx();
159 lyxerr << "wrong idx " << idx << ", max is " << lastidx
160 << ". Trying to correct this." << endl;
164 DocIterator::pit_type & pit = cursor.pit();
165 DocIterator::pit_type const lastpit = cursor.lastpit();
168 lyxerr << "wrong par " << pit << ", max is " << lastpit
169 << ". Trying to correct this." << endl;
173 DocIterator::pos_type & pos = cursor.pos();
174 DocIterator::pos_type const lastpos = cursor.lastpos();
177 lyxerr << "wrong pos " << pos << ", max is " << lastpos
178 << ". Trying to correct this." << endl;
182 // The inset's getStatus() will return 'true' if it made
183 // a definitive decision on whether it want to handle the
184 // request or not. The result of this decision is put into
185 // the 'status' parameter.
186 if (cursor.inset().getStatus(cursor, cmd, status)) {
196 LyXFunc::LyXFunc(LyXView * lv)
199 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
200 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
201 meta_fake_bit(key_modifier::none)
206 void LyXFunc::handleKeyFunc(kb_action action)
208 char c = encoded_last_key;
210 if (keyseq.length()) {
214 owner->getIntl().getTransManager()
215 .deadkey(c, get_accent(action).accent, view()->getLyXText());
216 // Need to clear, in case the minibuffer calls these
219 // copied verbatim from do_accent_char
220 view()->cursor().resetAnchor();
225 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
227 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
229 // Do nothing if we have nothing (JMarc)
230 if (!keysym->isOK()) {
231 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
236 if (keysym->isModifier()) {
237 lyxerr[Debug::KEY] << "isModifier true" << endl;
241 Encoding const * encoding = view()->cursor().getEncoding();
243 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
245 // Do a one-deep top-level lookup for
246 // cancel and meta-fake keys. RVDK_PATCH_5
247 cancel_meta_seq.reset();
249 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
250 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
251 << " action first set to [" << func.action << ']'
254 // When not cancel or meta-fake, do the normal lookup.
255 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
256 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
257 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
258 // remove Caps Lock and Mod2 as a modifiers
259 func = keyseq.addkey(keysym, (state | meta_fake_bit));
260 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
261 << "action now set to ["
262 << func.action << ']' << endl;
265 // Dont remove this unless you know what you are doing.
266 meta_fake_bit = key_modifier::none;
268 // Can this happen now ?
269 if (func.action == LFUN_NOACTION) {
270 func = FuncRequest(LFUN_PREFIX);
273 if (lyxerr.debugging(Debug::KEY)) {
274 lyxerr << BOOST_CURRENT_FUNCTION
276 << func.action << "]["
277 << keyseq.print() << ']'
281 // already here we know if it any point in going further
282 // why not return already here if action == -1 and
283 // num_bytes == 0? (Lgb)
285 if (keyseq.length() > 1) {
286 owner->message(keyseq.print());
290 // Maybe user can only reach the key via holding down shift.
291 // Let's see. But only if shift is the only modifier
292 if (func.action == LFUN_UNKNOWN_ACTION &&
293 state == key_modifier::shift) {
294 lyxerr[Debug::KEY] << "Trying without shift" << endl;
295 func = keyseq.addkey(keysym, key_modifier::none);
296 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
299 if (func.action == LFUN_UNKNOWN_ACTION) {
300 // Hmm, we didn't match any of the keysequences. See
301 // if it's normal insertable text not already covered
303 if (keysym->isText() && keyseq.length() == 1) {
304 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
305 func = FuncRequest(LFUN_SELFINSERT);
307 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
308 owner->message(_("Unknown function."));
313 if (func.action == LFUN_SELFINSERT) {
314 if (encoded_last_key != 0) {
315 string const arg(1, encoded_last_key);
316 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
318 << "SelfInsert arg[`" << arg << "']" << endl;
326 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
328 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
330 LCursor & cur = view()->cursor();
332 /* In LyX/Mac, when a dialog is open, the menus of the
333 application can still be accessed without giving focus to
334 the main window. In this case, we want to disable the menu
335 entries that are buffer-related.
338 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
341 buf = owner->buffer();
343 if (cmd.action == LFUN_NOACTION) {
344 flag.message(N_("Nothing to do"));
349 switch (cmd.action) {
350 case LFUN_UNKNOWN_ACTION:
351 #ifndef HAVE_LIBAIKSAURUS
352 case LFUN_THESAURUS_ENTRY:
358 flag |= lyx_gui::getStatus(cmd);
361 if (flag.unknown()) {
362 flag.message(N_("Unknown action"));
366 if (!flag.enabled()) {
367 if (flag.message().empty())
368 flag.message(N_("Command disabled"));
372 // Check whether we need a buffer
373 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
375 flag.message(N_("Command not allowed with"
376 "out any document open"));
381 // I would really like to avoid having this switch and rather try to
382 // encode this in the function itself.
383 // -- And I'd rather let an inset decide which LFUNs it is willing
384 // to handle (Andre')
386 switch (cmd.action) {
387 case LFUN_TOOLTIPS_TOGGLE:
388 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
391 case LFUN_READ_ONLY_TOGGLE:
392 flag.setOnOff(buf->isReadonly());
395 case LFUN_SWITCHBUFFER:
396 // toggle on the current buffer, but do not toggle off
397 // the other ones (is that a good idea?)
398 if (cmd.argument == buf->fileName())
403 enable = cmd.argument == "custom"
404 || Exporter::IsExportable(*buf, cmd.argument);
408 enable = cur.selection();
412 enable = buf->isLatex() && lyxrc.chktex_command != "none";
416 enable = Exporter::IsExportable(*buf, "program");
419 case LFUN_LAYOUT_TABULAR:
420 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
424 case LFUN_LAYOUT_PARAGRAPH:
425 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
428 case LFUN_VC_REGISTER:
429 enable = !buf->lyxvc().inUse();
431 case LFUN_VC_CHECKIN:
432 enable = buf->lyxvc().inUse() && !buf->isReadonly();
434 case LFUN_VC_CHECKOUT:
435 enable = buf->lyxvc().inUse() && buf->isReadonly();
439 enable = buf->lyxvc().inUse();
441 case LFUN_MENURELOAD:
442 enable = !buf->isUnnamed() && !buf->isClean();
445 case LFUN_INSET_SETTINGS: {
449 UpdatableInset * inset = cur.inset().asUpdatableInset();
450 lyxerr << "inset: " << inset << endl;
454 InsetBase::Code code = inset->lyxCode();
456 case InsetBase::TABULAR_CODE:
457 enable = cmd.argument == "tabular";
459 case InsetBase::ERT_CODE:
460 enable = cmd.argument == "ert";
462 case InsetBase::FLOAT_CODE:
463 enable = cmd.argument == "float";
465 case InsetBase::WRAP_CODE:
466 enable = cmd.argument == "wrap";
468 case InsetBase::NOTE_CODE:
469 enable = cmd.argument == "note";
471 case InsetBase::BRANCH_CODE:
472 enable = cmd.argument == "branch";
474 case InsetBase::BOX_CODE:
475 enable = cmd.argument == "box";
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_ALL_INSETS_TOGGLE: {
1347 string const name = split(argument, action, ' ');
1348 InsetBase::Code const inset_code =
1349 InsetBase::translate(name);
1351 LCursor & cur = view()->cursor();
1352 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1354 InsetBase & inset = owner->buffer()->inset();
1355 InsetIterator it = inset_iterator_begin(inset);
1356 InsetIterator const end = inset_iterator_end(inset);
1357 for (; it != end; ++it) {
1358 if (inset_code == InsetBase::NO_CODE
1359 || inset_code == it->lyxCode())
1360 it->dispatch(cur, fr);
1365 case LFUN_LANGUAGE_BUFFER: {
1366 Buffer & buffer = *owner->buffer();
1367 Language const * oldL = buffer.params().language;
1368 Language const * newL = languages.getLanguage(argument);
1369 if (!newL || oldL == newL)
1372 if (oldL->RightToLeft() == newL->RightToLeft()
1373 && !buffer.isMultiLingual())
1374 buffer.changeLanguage(oldL, newL);
1376 buffer.updateDocLang(newL);
1380 case LFUN_SAVE_AS_DEFAULT: {
1381 string const fname =
1382 AddName(AddPath(package().user_support(), "templates/"),
1384 Buffer defaults(fname);
1386 istringstream ss(argument);
1389 int const unknown_tokens = defaults.readHeader(lex);
1391 if (unknown_tokens != 0) {
1392 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1393 << unknown_tokens << " unknown token"
1394 << (unknown_tokens == 1 ? "" : "s")
1398 if (defaults.writeFile(defaults.fileName()))
1399 setMessage(_("Document defaults saved in ")
1400 + MakeDisplayPath(fname));
1402 setErrorMessage(_("Unable to save document defaults"));
1406 case LFUN_BUFFERPARAMS_APPLY: {
1407 biblio::CiteEngine const engine =
1408 owner->buffer()->params().cite_engine;
1410 istringstream ss(argument);
1413 int const unknown_tokens =
1414 owner->buffer()->readHeader(lex);
1416 if (unknown_tokens != 0) {
1417 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1418 << unknown_tokens << " unknown token"
1419 << (unknown_tokens == 1 ? "" : "s")
1422 if (engine == owner->buffer()->params().cite_engine)
1425 LCursor & cur = view()->cursor();
1426 FuncRequest fr(LFUN_INSET_REFRESH);
1428 InsetBase & inset = owner->buffer()->inset();
1429 InsetIterator it = inset_iterator_begin(inset);
1430 InsetIterator const end = inset_iterator_end(inset);
1431 for (; it != end; ++it)
1432 if (it->lyxCode() == InsetBase::CITE_CODE)
1433 it->dispatch(cur, fr);
1437 case LFUN_TEXTCLASS_APPLY: {
1438 Buffer * buffer = owner->buffer();
1440 lyx::textclass_type const old_class =
1441 buffer->params().textclass;
1443 loadTextclass(argument);
1445 std::pair<bool, lyx::textclass_type> const tc_pair =
1446 textclasslist.NumberOfClass(argument);
1451 lyx::textclass_type const new_class = tc_pair.second;
1452 if (old_class == new_class)
1456 owner->message(_("Converting document to new document class..."));
1458 lyx::cap::SwitchLayoutsBetweenClasses(
1459 old_class, new_class,
1460 buffer->paragraphs(), el);
1462 bufferErrors(*buffer, el);
1463 view()->showErrorList(_("Class switch"));
1467 case LFUN_TEXTCLASS_LOAD:
1468 loadTextclass(argument);
1471 case LFUN_LYXRC_APPLY: {
1472 LyXRC const lyxrc_orig = lyxrc;
1474 istringstream ss(argument);
1475 bool const success = lyxrc.read(ss) == 0;
1478 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1479 << "Unable to read lyxrc data"
1484 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1489 view()->cursor().dispatch(cmd);
1490 update |= view()->cursor().result().update();
1491 if (!view()->cursor().result().dispatched()) {
1492 update |= view()->dispatch(cmd);
1499 if (view()->available()) {
1500 // Redraw screen unless explicitly told otherwise.
1501 // This also initializes the position cache for all insets
1502 // in (at least partially) visible top-level paragraphs.
1503 view()->update(true, update);
1505 // if we executed a mutating lfun, mark the buffer as dirty
1506 if (getStatus(cmd).enabled()
1507 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1508 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1509 view()->buffer()->markDirty();
1512 if (view()->cursor().inTexted()) {
1513 view()->owner()->updateLayoutChoice();
1516 sendDispatchMessage(getMessage(), cmd);
1520 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1522 owner->updateMenubar();
1523 owner->updateToolbars();
1525 const bool verbose = (cmd.origin == FuncRequest::UI
1526 || cmd.origin == FuncRequest::COMMANDBUFFER);
1528 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1529 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1531 owner->message(msg);
1535 string dispatch_msg = msg;
1536 if (!dispatch_msg.empty())
1537 dispatch_msg += ' ';
1539 string comname = lyxaction.getActionName(cmd.action);
1541 bool argsadded = false;
1543 if (!cmd.argument.empty()) {
1544 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1545 comname += ' ' + cmd.argument;
1550 string const shortcuts = toplevel_keymap->printbindings(cmd);
1552 if (!shortcuts.empty()) {
1553 comname += ": " + shortcuts;
1554 } else if (!argsadded && !cmd.argument.empty()) {
1555 comname += ' ' + cmd.argument;
1558 if (!comname.empty()) {
1559 comname = rtrim(comname);
1560 dispatch_msg += '(' + comname + ')';
1563 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1564 if (!dispatch_msg.empty())
1565 owner->message(dispatch_msg);
1569 void LyXFunc::setupLocalKeymap()
1571 keyseq.stdmap = toplevel_keymap.get();
1572 keyseq.curmap = toplevel_keymap.get();
1573 cancel_meta_seq.stdmap = toplevel_keymap.get();
1574 cancel_meta_seq.curmap = toplevel_keymap.get();
1578 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1580 string initpath = lyxrc.document_path;
1581 string filename(name);
1583 if (view()->available()) {
1584 string const trypath = owner->buffer()->filePath();
1585 // If directory is writeable, use this as default.
1586 if (IsDirWriteable(trypath))
1590 static int newfile_number;
1592 if (filename.empty()) {
1593 filename = AddName(lyxrc.document_path,
1594 "newfile" + convert<string>(++newfile_number) + ".lyx");
1595 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1597 filename = AddName(lyxrc.document_path,
1598 "newfile" + convert<string>(newfile_number) +
1603 // The template stuff
1606 FileDialog fileDlg(_("Select template file"),
1607 LFUN_SELECT_FILE_SYNC,
1608 make_pair(string(_("Documents|#o#O")),
1609 string(lyxrc.document_path)),
1610 make_pair(string(_("Templates|#T#t")),
1611 string(lyxrc.template_path)));
1613 FileDialog::Result result =
1614 fileDlg.open(lyxrc.template_path,
1615 FileFilterList(_("LyX Documents (*.lyx)")),
1618 if (result.first == FileDialog::Later)
1620 if (result.second.empty())
1622 templname = result.second;
1625 view()->newFile(filename, templname, !name.empty());
1629 void LyXFunc::open(string const & fname)
1631 string initpath = lyxrc.document_path;
1633 if (view()->available()) {
1634 string const trypath = owner->buffer()->filePath();
1635 // If directory is writeable, use this as default.
1636 if (IsDirWriteable(trypath))
1642 if (fname.empty()) {
1643 FileDialog fileDlg(_("Select document to open"),
1645 make_pair(string(_("Documents|#o#O")),
1646 string(lyxrc.document_path)),
1647 make_pair(string(_("Examples|#E#e")),
1648 string(AddPath(package().system_support(), "examples"))));
1650 FileDialog::Result result =
1651 fileDlg.open(initpath,
1652 FileFilterList(_("LyX Documents (*.lyx)")),
1655 if (result.first == FileDialog::Later)
1658 filename = result.second;
1660 // check selected filename
1661 if (filename.empty()) {
1662 owner->message(_("Canceled."));
1668 // get absolute path of file and add ".lyx" to the filename if
1670 string const fullpath = FileSearch(string(), filename, "lyx");
1671 if (!fullpath.empty()) {
1672 filename = fullpath;
1675 string const disp_fn(MakeDisplayPath(filename));
1677 // if the file doesn't exist, let the user create one
1678 if (!fs::exists(filename)) {
1679 // the user specifically chose this name. Believe them.
1680 view()->newFile(filename, "", true);
1684 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1687 if (view()->loadLyXFile(filename)) {
1688 str2 = bformat(_("Document %1$s opened."), disp_fn);
1690 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1692 owner->message(str2);
1696 void LyXFunc::doImport(string const & argument)
1699 string filename = split(argument, format, ' ');
1701 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1702 << " file: " << filename << endl;
1704 // need user interaction
1705 if (filename.empty()) {
1706 string initpath = lyxrc.document_path;
1708 if (view()->available()) {
1709 string const trypath = owner->buffer()->filePath();
1710 // If directory is writeable, use this as default.
1711 if (IsDirWriteable(trypath))
1715 string const text = bformat(_("Select %1$s file to import"),
1716 formats.prettyName(format));
1718 FileDialog fileDlg(text,
1720 make_pair(string(_("Documents|#o#O")),
1721 string(lyxrc.document_path)),
1722 make_pair(string(_("Examples|#E#e")),
1723 string(AddPath(package().system_support(), "examples"))));
1725 string const filter = formats.prettyName(format)
1726 + " (*." + formats.extension(format) + ')';
1728 FileDialog::Result result =
1729 fileDlg.open(initpath,
1730 FileFilterList(filter),
1733 if (result.first == FileDialog::Later)
1736 filename = result.second;
1738 // check selected filename
1739 if (filename.empty())
1740 owner->message(_("Canceled."));
1743 if (filename.empty())
1746 // get absolute path of file
1747 filename = MakeAbsPath(filename);
1749 string const lyxfile = ChangeExtension(filename, ".lyx");
1751 // Check if the document already is open
1752 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1753 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1754 owner->message(_("Canceled."));
1759 // if the file exists already, and we didn't do
1760 // -i lyx thefile.lyx, warn
1761 if (fs::exists(lyxfile) && filename != lyxfile) {
1762 string const file = MakeDisplayPath(lyxfile, 30);
1764 string text = bformat(_("The document %1$s already exists.\n\n"
1765 "Do you want to over-write that document?"), file);
1766 int const ret = Alert::prompt(_("Over-write document?"),
1767 text, 0, 1, _("&Over-write"), _("&Cancel"));
1770 owner->message(_("Canceled."));
1775 Importer::Import(owner, filename, format);
1779 void LyXFunc::closeBuffer()
1781 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1782 if (bufferlist.empty()) {
1783 // need this otherwise SEGV may occur while
1784 // trying to set variables that don't exist
1785 // since there's no current buffer
1786 owner->getDialogs().hideBufferDependent();
1788 view()->setBuffer(bufferlist.first());
1794 // Each "owner" should have it's own message method. lyxview and
1795 // the minibuffer would use the minibuffer, but lyxserver would
1796 // send an ERROR signal to its client. Alejandro 970603
1797 // This function is bit problematic when it comes to NLS, to make the
1798 // lyx servers client be language indepenent we must not translate
1799 // strings sent to this func.
1800 void LyXFunc::setErrorMessage(string const & m) const
1802 dispatch_buffer = m;
1807 void LyXFunc::setMessage(string const & m) const
1809 dispatch_buffer = m;
1813 string const LyXFunc::viewStatusMessage()
1815 // When meta-fake key is pressed, show the key sequence so far + "M-".
1817 return keyseq.print() + "M-";
1819 // Else, when a non-complete key sequence is pressed,
1820 // show the available options.
1821 if (keyseq.length() > 0 && !keyseq.deleted())
1822 return keyseq.printOptions();
1824 if (!view()->available())
1825 return _("Welcome to LyX!");
1827 return view()->cursor().currentState();
1831 BufferView * LyXFunc::view() const
1833 BOOST_ASSERT(owner);
1834 return owner->view().get();
1838 bool LyXFunc::wasMetaKey() const
1840 return (meta_fake_bit != key_modifier::none);
1846 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1848 // Why the switch you might ask. It is a trick to ensure that all
1849 // the elements in the LyXRCTags enum is handled. As you can see
1850 // there are no breaks at all. So it is just a huge fall-through.
1851 // The nice thing is that we will get a warning from the compiler
1852 // if we forget an element.
1853 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1855 case LyXRC::RC_ACCEPT_COMPOUND:
1856 case LyXRC::RC_ALT_LANG:
1857 case LyXRC::RC_ASCIIROFF_COMMAND:
1858 case LyXRC::RC_ASCII_LINELEN:
1859 case LyXRC::RC_AUTOREGIONDELETE:
1860 case LyXRC::RC_AUTORESET_OPTIONS:
1861 case LyXRC::RC_AUTOSAVE:
1862 case LyXRC::RC_AUTO_NUMBER:
1863 case LyXRC::RC_BACKUPDIR_PATH:
1864 case LyXRC::RC_BIBTEX_COMMAND:
1865 case LyXRC::RC_BINDFILE:
1866 case LyXRC::RC_CHECKLASTFILES:
1867 case LyXRC::RC_CHKTEX_COMMAND:
1868 case LyXRC::RC_CONVERTER:
1869 case LyXRC::RC_COPIER:
1870 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1871 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1872 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1873 case LyXRC::RC_CYGWIN_PATH_FIX:
1874 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1875 namespace os = lyx::support::os;
1876 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1878 case LyXRC::RC_DATE_INSERT_FORMAT:
1879 case LyXRC::RC_DEFAULT_LANGUAGE:
1880 case LyXRC::RC_DEFAULT_PAPERSIZE:
1881 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1882 case LyXRC::RC_DISPLAY_GRAPHICS:
1883 case LyXRC::RC_DOCUMENTPATH:
1884 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1885 if (fs::exists(lyxrc_new.document_path) &&
1886 fs::is_directory(lyxrc_new.document_path)) {
1887 using lyx::support::package;
1888 package().document_dir() = lyxrc.document_path;
1891 case LyXRC::RC_ESC_CHARS:
1892 case LyXRC::RC_FONT_ENCODING:
1893 case LyXRC::RC_FORMAT:
1894 case LyXRC::RC_INDEX_COMMAND:
1895 case LyXRC::RC_INPUT:
1896 case LyXRC::RC_KBMAP:
1897 case LyXRC::RC_KBMAP_PRIMARY:
1898 case LyXRC::RC_KBMAP_SECONDARY:
1899 case LyXRC::RC_LABEL_INIT_LENGTH:
1900 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1901 case LyXRC::RC_LANGUAGE_AUTO_END:
1902 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1903 case LyXRC::RC_LANGUAGE_COMMAND_END:
1904 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1905 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1906 case LyXRC::RC_LANGUAGE_PACKAGE:
1907 case LyXRC::RC_LANGUAGE_USE_BABEL:
1908 case LyXRC::RC_LASTFILES:
1909 case LyXRC::RC_MAKE_BACKUP:
1910 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1911 case LyXRC::RC_NUMLASTFILES:
1912 case LyXRC::RC_PATH_PREFIX:
1913 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1914 using lyx::support::prependEnvPath;
1915 prependEnvPath("PATH", lyxrc.path_prefix);
1917 case LyXRC::RC_PERS_DICT:
1918 case LyXRC::RC_POPUP_BOLD_FONT:
1919 case LyXRC::RC_POPUP_FONT_ENCODING:
1920 case LyXRC::RC_POPUP_NORMAL_FONT:
1921 case LyXRC::RC_PREVIEW:
1922 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1923 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1924 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1925 case LyXRC::RC_PRINTCOPIESFLAG:
1926 case LyXRC::RC_PRINTER:
1927 case LyXRC::RC_PRINTEVENPAGEFLAG:
1928 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1929 case LyXRC::RC_PRINTFILEEXTENSION:
1930 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1931 case LyXRC::RC_PRINTODDPAGEFLAG:
1932 case LyXRC::RC_PRINTPAGERANGEFLAG:
1933 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1934 case LyXRC::RC_PRINTPAPERFLAG:
1935 case LyXRC::RC_PRINTREVERSEFLAG:
1936 case LyXRC::RC_PRINTSPOOL_COMMAND:
1937 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1938 case LyXRC::RC_PRINTTOFILE:
1939 case LyXRC::RC_PRINTTOPRINTER:
1940 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1941 case LyXRC::RC_PRINT_COMMAND:
1942 case LyXRC::RC_RTL_SUPPORT:
1943 case LyXRC::RC_SCREEN_DPI:
1944 case LyXRC::RC_SCREEN_FONT_ENCODING:
1945 case LyXRC::RC_SCREEN_FONT_ROMAN:
1946 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1947 case LyXRC::RC_SCREEN_FONT_SANS:
1948 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1949 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1950 case LyXRC::RC_SCREEN_FONT_SIZES:
1951 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1952 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1953 case LyXRC::RC_SCREEN_ZOOM:
1954 case LyXRC::RC_SERVERPIPE:
1955 case LyXRC::RC_SET_COLOR:
1956 case LyXRC::RC_SHOW_BANNER:
1957 case LyXRC::RC_SPELL_COMMAND:
1958 case LyXRC::RC_TEMPDIRPATH:
1959 case LyXRC::RC_TEMPLATEPATH:
1960 case LyXRC::RC_UIFILE:
1961 case LyXRC::RC_USER_EMAIL:
1962 case LyXRC::RC_USER_NAME:
1963 case LyXRC::RC_USETEMPDIR:
1964 case LyXRC::RC_USE_ALT_LANG:
1965 case LyXRC::RC_USE_ESC_CHARS:
1966 case LyXRC::RC_USE_INP_ENC:
1967 case LyXRC::RC_USE_PERS_DICT:
1968 case LyXRC::RC_USE_SPELL_LIB:
1969 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1970 case LyXRC::RC_VIEWER:
1971 case LyXRC::RC_WHEEL_JUMP:
1972 case LyXRC::RC_LAST: