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_DIALOG_SHOW: {
466 string const name = cmd.getArg(0);
468 enable = name == "aboutlyx"
472 || name == "texinfo";
473 else if (name == "print")
474 enable = Exporter::IsExportable(*buf, "dvi")
475 && lyxrc.print_command != "none";
476 else if (name == "character" || name == "mathpanel")
477 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
478 else if (name == "vclog")
479 enable = buf->lyxvc().inUse();
480 else if (name == "latexlog")
481 enable = IsFileReadable(buf->getLogName().second);
485 case LFUN_DIALOG_SHOW_NEW_INSET:
486 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
489 case LFUN_DIALOG_UPDATE: {
490 string const name = cmd.getArg(0);
492 enable = name == "prefs";
496 // this one is difficult to get right. As a half-baked
497 // solution, we consider only the first action of the sequence
498 case LFUN_SEQUENCE: {
499 // argument contains ';'-terminated commands
500 string const firstcmd = token(cmd.argument, ';', 0);
501 FuncRequest func(lyxaction.lookupFunc(firstcmd));
502 func.origin = cmd.origin;
503 flag = getStatus(func);
507 case LFUN_MENUNEWTMPLT:
508 case LFUN_WORDFINDFORWARD:
509 case LFUN_WORDFINDBACKWARD:
511 case LFUN_EXEC_COMMAND:
514 case LFUN_CLOSEBUFFER:
523 case LFUN_RECONFIGURE:
527 case LFUN_DROP_LAYOUTS_CHOICE:
528 case LFUN_MENU_OPEN_BY_NAME:
531 case LFUN_GOTOFILEROW:
532 case LFUN_DIALOG_SHOW_NEXT_INSET:
533 case LFUN_DIALOG_HIDE:
534 case LFUN_DIALOG_DISCONNECT_INSET:
536 case LFUN_TOGGLECURSORFOLLOW:
540 case LFUN_KMAP_TOGGLE:
542 case LFUN_EXPORT_CUSTOM:
544 case LFUN_SAVEPREFERENCES:
545 case LFUN_SCREEN_FONT_UPDATE:
548 case LFUN_EXTERNAL_EDIT:
549 case LFUN_GRAPHICS_EDIT:
550 case LFUN_ALL_INSETS_TOGGLE:
551 case LFUN_LANGUAGE_BUFFER:
552 case LFUN_TEXTCLASS_APPLY:
553 case LFUN_TEXTCLASS_LOAD:
554 case LFUN_SAVE_AS_DEFAULT:
555 case LFUN_BUFFERPARAMS_APPLY:
556 case LFUN_LYXRC_APPLY:
557 case LFUN_NEXTBUFFER:
558 case LFUN_PREVIOUSBUFFER:
559 // these are handled in our dispatch()
564 if (!::getStatus(cur, cmd, flag))
565 flag = view()->getStatus(cmd);
571 // Can we use a readonly buffer?
572 if (buf && buf->isReadonly()
573 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
574 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
575 flag.message(N_("Document is read-only"));
579 // the default error message if we disable the command
580 if (!flag.enabled() && flag.message().empty())
581 flag.message(N_("Command disabled"));
589 bool ensureBufferClean(BufferView * bv)
591 Buffer & buf = *bv->buffer();
595 string const file = MakeDisplayPath(buf.fileName(), 30);
596 string text = bformat(_("The document %1$s has unsaved "
597 "changes.\n\nDo you want to save "
598 "the document?"), file);
599 int const ret = Alert::prompt(_("Save changed document?"),
600 text, 0, 1, _("&Save"),
604 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
606 return buf.isClean();
610 void showPrintError(string const & name)
612 string str = bformat(_("Could not print the document %1$s.\n"
613 "Check that your printer is set up correctly."),
614 MakeDisplayPath(name, 50));
615 Alert::error(_("Print document failed"), str);
619 void loadTextclass(string const & name)
621 std::pair<bool, lyx::textclass_type> const tc_pair =
622 textclasslist.NumberOfClass(name);
624 if (!tc_pair.first) {
625 lyxerr << "Document class \"" << name
626 << "\" does not exist."
631 lyx::textclass_type const tc = tc_pair.second;
633 if (!textclasslist[tc].load()) {
634 string s = bformat(_("The document could not be converted\n"
635 "into the document class %1$s."),
636 textclasslist[tc].name());
637 Alert::error(_("Could not change class"), s);
642 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
647 void LyXFunc::dispatch(FuncRequest const & cmd)
649 BOOST_ASSERT(view());
650 string const argument = cmd.argument;
651 kb_action const action = cmd.action;
653 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
654 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
656 // we have not done anything wrong yet.
658 dispatch_buffer.erase();
662 FuncStatus const flag = getStatus(cmd);
663 if (!flag.enabled()) {
664 // We cannot use this function here
665 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
666 << lyxaction.getActionName(action)
667 << " [" << action << "] is disabled at this location"
669 setErrorMessage(flag.message());
672 if (view()->available())
673 view()->hideCursor();
677 case LFUN_WORDFINDFORWARD:
678 case LFUN_WORDFINDBACKWARD: {
679 static string last_search;
680 string searched_string;
682 if (!argument.empty()) {
683 last_search = argument;
684 searched_string = argument;
686 searched_string = last_search;
689 if (searched_string.empty())
692 bool const fw = action == LFUN_WORDFINDFORWARD;
694 lyx::find::find2string(searched_string, true, false, fw);
695 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
700 owner->message(keyseq.printOptions());
703 case LFUN_EXEC_COMMAND:
704 owner->getToolbars().display("minibuffer", true);
705 owner->focus_command_buffer();
710 meta_fake_bit = key_modifier::none;
711 if (view()->available())
712 // cancel any selection
713 dispatch(FuncRequest(LFUN_MARK_OFF));
714 setMessage(N_("Cancel"));
718 meta_fake_bit = key_modifier::alt;
719 setMessage(keyseq.print());
722 case LFUN_READ_ONLY_TOGGLE:
723 if (owner->buffer()->lyxvc().inUse())
724 owner->buffer()->lyxvc().toggleReadOnly();
726 owner->buffer()->setReadonly(
727 !owner->buffer()->isReadonly());
730 // --- Menus -----------------------------------------------
732 menuNew(argument, false);
735 case LFUN_MENUNEWTMPLT:
736 menuNew(argument, true);
739 case LFUN_CLOSEBUFFER:
744 if (!owner->buffer()->isUnnamed()) {
745 string const str = bformat(_("Saving document %1$s..."),
746 MakeDisplayPath(owner->buffer()->fileName()));
748 MenuWrite(owner->buffer());
749 owner->message(str + _(" done."));
751 WriteAs(owner->buffer());
755 WriteAs(owner->buffer(), argument);
758 case LFUN_MENURELOAD: {
759 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
760 string text = bformat(_("Any changes will be lost. Are you sure "
761 "you want to revert to the saved version of the document %1$s?"), file);
762 int const ret = Alert::prompt(_("Revert to saved document?"),
763 text, 0, 1, _("&Revert"), _("&Cancel"));
771 Exporter::Export(owner->buffer(), argument, true);
772 view()->showErrorList(BufferFormat(*owner->buffer()));
776 Exporter::Preview(owner->buffer(), argument);
777 view()->showErrorList(BufferFormat(*owner->buffer()));
781 Exporter::Export(owner->buffer(), "program", true);
782 view()->showErrorList(_("Build"));
786 owner->buffer()->runChktex();
787 view()->showErrorList(_("ChkTeX"));
791 if (argument == "custom")
792 owner->getDialogs().show("sendto");
794 Exporter::Export(owner->buffer(), argument, false);
795 view()->showErrorList(BufferFormat(*owner->buffer()));
799 case LFUN_EXPORT_CUSTOM: {
801 string command = split(argument, format_name, ' ');
802 Format const * format = formats.getFormat(format_name);
804 lyxerr << "Format \"" << format_name
805 << "\" not recognized!"
810 Buffer * buffer = owner->buffer();
812 // The name of the file created by the conversion process
815 // Output to filename
816 if (format->name() == "lyx") {
817 string const latexname =
818 buffer->getLatexName(false);
819 filename = ChangeExtension(latexname,
820 format->extension());
821 filename = AddName(buffer->temppath(), filename);
823 if (!buffer->writeFile(filename))
827 Exporter::Export(buffer, format_name, true,
831 // Substitute $$FName for filename
832 if (!contains(command, "$$FName"))
833 command = "( " + command + " ) < $$FName";
834 command = subst(command, "$$FName", filename);
836 // Execute the command in the background
838 call.startscript(Systemcall::DontWait, command);
845 string command = split(split(argument, target, ' '),
849 || target_name.empty()
850 || command.empty()) {
851 lyxerr << "Unable to parse \""
852 << argument << '"' << std::endl;
855 if (target != "printer" && target != "file") {
856 lyxerr << "Unrecognized target \""
857 << target << '"' << std::endl;
861 Buffer * buffer = owner->buffer();
863 if (!Exporter::Export(buffer, "dvi", true)) {
864 showPrintError(buffer->fileName());
868 // Push directory path.
869 string const path = buffer->temppath();
872 // there are three cases here:
873 // 1. we print to a file
874 // 2. we print directly to a printer
875 // 3. we print using a spool command (print to file first)
878 string const dviname =
879 ChangeExtension(buffer->getLatexName(true),
882 if (target == "printer") {
883 if (!lyxrc.print_spool_command.empty()) {
884 // case 3: print using a spool
885 string const psname =
886 ChangeExtension(dviname,".ps");
887 command += lyxrc.print_to_file
890 + QuoteName(dviname);
893 lyxrc.print_spool_command +' ';
894 if (target_name != "default") {
895 command2 += lyxrc.print_spool_printerprefix
899 command2 += QuoteName(psname);
901 // If successful, then spool command
902 res = one.startscript(
907 res = one.startscript(
908 Systemcall::DontWait,
911 // case 2: print directly to a printer
912 res = one.startscript(
913 Systemcall::DontWait,
914 command + QuoteName(dviname));
918 // case 1: print to a file
919 command += lyxrc.print_to_file
920 + QuoteName(MakeAbsPath(target_name,
923 + QuoteName(dviname);
924 res = one.startscript(Systemcall::DontWait,
929 showPrintError(buffer->fileName());
942 InsetCommandParams p("tableofcontents");
943 string const data = InsetCommandMailer::params2string("toc", p);
944 owner->getDialogs().show("toc", data, 0);
952 case LFUN_RECONFIGURE:
956 case LFUN_HELP_OPEN: {
957 string const arg = argument;
959 setErrorMessage(N_("Missing argument"));
962 string const fname = i18nLibFileSearch("doc", arg, "lyx");
964 lyxerr << "LyX: unable to find documentation file `"
965 << arg << "'. Bad installation?" << endl;
968 owner->message(bformat(_("Opening help file %1$s..."),
969 MakeDisplayPath(fname)));
970 view()->loadLyXFile(fname, false);
974 // --- version control -------------------------------
975 case LFUN_VC_REGISTER:
976 if (!ensureBufferClean(view()))
978 if (!owner->buffer()->lyxvc().inUse()) {
979 owner->buffer()->lyxvc().registrer();
984 case LFUN_VC_CHECKIN:
985 if (!ensureBufferClean(view()))
987 if (owner->buffer()->lyxvc().inUse()
988 && !owner->buffer()->isReadonly()) {
989 owner->buffer()->lyxvc().checkIn();
994 case LFUN_VC_CHECKOUT:
995 if (!ensureBufferClean(view()))
997 if (owner->buffer()->lyxvc().inUse()
998 && owner->buffer()->isReadonly()) {
999 owner->buffer()->lyxvc().checkOut();
1004 case LFUN_VC_REVERT:
1005 owner->buffer()->lyxvc().revert();
1010 owner->buffer()->lyxvc().undoLast();
1014 // --- buffers ----------------------------------------
1015 case LFUN_SWITCHBUFFER:
1016 view()->setBuffer(bufferlist.getBuffer(argument));
1019 case LFUN_NEXTBUFFER:
1020 view()->setBuffer(bufferlist.next(view()->buffer()));
1023 case LFUN_PREVIOUSBUFFER:
1024 view()->setBuffer(bufferlist.previous(view()->buffer()));
1028 NewFile(view(), argument);
1031 case LFUN_FILE_OPEN:
1035 case LFUN_DROP_LAYOUTS_CHOICE:
1036 owner->getToolbars().openLayoutList();
1039 case LFUN_MENU_OPEN_BY_NAME:
1040 owner->getMenubar().openByName(argument);
1043 // --- lyxserver commands ----------------------------
1045 setMessage(owner->buffer()->fileName());
1046 lyxerr[Debug::INFO] << "FNAME["
1047 << owner->buffer()->fileName()
1052 dispatch_buffer = keyseq.print();
1053 lyxserver->notifyClient(dispatch_buffer);
1056 case LFUN_GOTOFILEROW: {
1059 istringstream is(argument);
1060 is >> file_name >> row;
1061 if (prefixIs(file_name, package().temp_dir())) {
1062 // Needed by inverse dvi search. If it is a file
1063 // in tmpdir, call the apropriated function
1064 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1066 // Must replace extension of the file to be .lyx
1067 // and get full path
1068 string const s = ChangeExtension(file_name, ".lyx");
1069 // Either change buffer or load the file
1070 if (bufferlist.exists(s)) {
1071 view()->setBuffer(bufferlist.getBuffer(s));
1073 view()->loadLyXFile(s);
1077 view()->setCursorFromRow(row);
1080 // see BufferView_pimpl::center()
1081 view()->updateScrollbar();
1085 case LFUN_DIALOG_SHOW: {
1086 string const name = cmd.getArg(0);
1087 string data = trim(cmd.argument.substr(name.size()));
1089 if (name == "character") {
1090 data = freefont2string();
1092 owner->getDialogs().show("character", data);
1095 else if (name == "latexlog") {
1096 pair<Buffer::LogType, string> const logfile =
1097 owner->buffer()->getLogName();
1098 switch (logfile.first) {
1099 case Buffer::latexlog:
1102 case Buffer::buildlog:
1106 data += logfile.second;
1107 owner->getDialogs().show("log", data);
1109 else if (name == "vclog") {
1110 string const data = "vc " +
1111 owner->buffer()->lyxvc().getLogFile();
1112 owner->getDialogs().show("log", data);
1115 owner->getDialogs().show(name, data);
1119 case LFUN_DIALOG_SHOW_NEW_INSET: {
1120 string const name = cmd.getArg(0);
1121 string data = trim(cmd.argument.substr(name.size()));
1122 if (name == "bibitem" ||
1124 name == "include" ||
1130 InsetCommandParams p(name);
1131 data = InsetCommandMailer::params2string(name, p);
1132 } else if (name == "box") {
1133 // \c data == "Boxed" || "Frameless" etc
1134 InsetBoxParams p(data);
1135 data = InsetBoxMailer::params2string(p);
1136 } else if (name == "branch") {
1137 InsetBranchParams p;
1138 data = InsetBranchMailer::params2string(p);
1139 } else if (name == "citation") {
1140 InsetCommandParams p("cite");
1141 data = InsetCommandMailer::params2string(name, p);
1142 } else if (name == "ert") {
1143 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1144 } else if (name == "external") {
1145 InsetExternalParams p;
1146 Buffer const & buffer = *owner->buffer();
1147 data = InsetExternalMailer::params2string(p, buffer);
1148 } else if (name == "float") {
1150 data = InsetFloatMailer::params2string(p);
1151 } else if (name == "graphics") {
1152 InsetGraphicsParams p;
1153 Buffer const & buffer = *owner->buffer();
1154 data = InsetGraphicsMailer::params2string(p, buffer);
1155 } else if (name == "note") {
1157 data = InsetNoteMailer::params2string(p);
1158 } else if (name == "vspace") {
1160 data = InsetVSpaceMailer::params2string(space);
1161 } else if (name == "wrap") {
1163 data = InsetWrapMailer::params2string(p);
1165 owner->getDialogs().show(name, data, 0);
1169 case LFUN_DIALOG_SHOW_NEXT_INSET:
1172 case LFUN_DIALOG_UPDATE: {
1173 string const & name = argument;
1174 // Can only update a dialog connected to an existing inset
1175 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1177 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1178 inset->dispatch(view()->cursor(), fr);
1179 } else if (name == "paragraph") {
1180 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1181 } else if (name == "prefs") {
1182 owner->getDialogs().update(name, string());
1187 case LFUN_DIALOG_HIDE:
1188 Dialogs::hide(argument, 0);
1191 case LFUN_DIALOG_DISCONNECT_INSET:
1192 owner->getDialogs().disconnect(argument);
1195 case LFUN_CHILDOPEN: {
1196 string const filename =
1197 MakeAbsPath(argument, owner->buffer()->filePath());
1198 setMessage(N_("Opening child document ") +
1199 MakeDisplayPath(filename) + "...");
1200 view()->savePosition(0);
1201 string const parentfilename = owner->buffer()->fileName();
1202 if (bufferlist.exists(filename))
1203 view()->setBuffer(bufferlist.getBuffer(filename));
1205 view()->loadLyXFile(filename);
1206 // Set the parent name of the child document.
1207 // This makes insertion of citations and references in the child work,
1208 // when the target is in the parent or another child document.
1209 owner->buffer()->setParentName(parentfilename);
1213 case LFUN_TOGGLECURSORFOLLOW:
1214 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1218 owner->getIntl().KeyMapOn(false);
1221 case LFUN_KMAP_PRIM:
1222 owner->getIntl().KeyMapPrim();
1226 owner->getIntl().KeyMapSec();
1229 case LFUN_KMAP_TOGGLE:
1230 owner->getIntl().ToggleKeyMap();
1236 string rest = split(argument, countstr, ' ');
1237 istringstream is(countstr);
1240 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1241 for (int i = 0; i < count; ++i)
1242 dispatch(lyxaction.lookupFunc(rest));
1246 case LFUN_SEQUENCE: {
1247 // argument contains ';'-terminated commands
1248 string arg = argument;
1249 while (!arg.empty()) {
1251 arg = split(arg, first, ';');
1252 FuncRequest func(lyxaction.lookupFunc(first));
1253 func.origin = cmd.origin;
1259 case LFUN_SAVEPREFERENCES: {
1260 Path p(package().user_support());
1261 lyxrc.write("preferences", false);
1265 case LFUN_SCREEN_FONT_UPDATE:
1266 // handle the screen font changes.
1267 lyxrc.set_font_norm_type();
1268 lyx_gui::update_fonts();
1269 // All visible buffers will need resize
1273 case LFUN_SET_COLOR: {
1275 string const x11_name = split(argument, lyx_name, ' ');
1276 if (lyx_name.empty() || x11_name.empty()) {
1277 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1282 bool const graphicsbg_changed =
1283 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1284 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1286 if (!lcolor.setColor(lyx_name, x11_name)) {
1288 bformat(_("Set-color \"%1$s\" failed "
1289 "- color is undefined or "
1290 "may not be redefined"), lyx_name));
1294 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1296 if (graphicsbg_changed) {
1297 #ifdef WITH_WARNINGS
1298 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1301 lyx::graphics::GCache::get().changeDisplay(true);
1308 owner->message(argument);
1311 case LFUN_TOOLTIPS_TOGGLE:
1312 owner->getDialogs().toggleTooltips();
1315 case LFUN_EXTERNAL_EDIT: {
1316 FuncRequest fr(action, argument);
1317 InsetExternal().dispatch(view()->cursor(), fr);
1321 case LFUN_GRAPHICS_EDIT: {
1322 FuncRequest fr(action, argument);
1323 InsetGraphics().dispatch(view()->cursor(), fr);
1327 case LFUN_ALL_INSETS_TOGGLE: {
1329 string const name = split(argument, action, ' ');
1330 InsetBase::Code const inset_code =
1331 InsetBase::translate(name);
1333 LCursor & cur = view()->cursor();
1334 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1336 InsetBase & inset = owner->buffer()->inset();
1337 InsetIterator it = inset_iterator_begin(inset);
1338 InsetIterator const end = inset_iterator_end(inset);
1339 for (; it != end; ++it) {
1340 if (inset_code == InsetBase::NO_CODE
1341 || inset_code == it->lyxCode())
1342 it->dispatch(cur, fr);
1347 case LFUN_LANGUAGE_BUFFER: {
1348 Buffer & buffer = *owner->buffer();
1349 Language const * oldL = buffer.params().language;
1350 Language const * newL = languages.getLanguage(argument);
1351 if (!newL || oldL == newL)
1354 if (oldL->RightToLeft() == newL->RightToLeft()
1355 && !buffer.isMultiLingual())
1356 buffer.changeLanguage(oldL, newL);
1358 buffer.updateDocLang(newL);
1362 case LFUN_SAVE_AS_DEFAULT: {
1363 string const fname =
1364 AddName(AddPath(package().user_support(), "templates/"),
1366 Buffer defaults(fname);
1368 istringstream ss(argument);
1371 int const unknown_tokens = defaults.readHeader(lex);
1373 if (unknown_tokens != 0) {
1374 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1375 << unknown_tokens << " unknown token"
1376 << (unknown_tokens == 1 ? "" : "s")
1380 if (defaults.writeFile(defaults.fileName()))
1381 setMessage(_("Document defaults saved in ")
1382 + MakeDisplayPath(fname));
1384 setErrorMessage(_("Unable to save document defaults"));
1388 case LFUN_BUFFERPARAMS_APPLY: {
1389 biblio::CiteEngine const engine =
1390 owner->buffer()->params().cite_engine;
1392 istringstream ss(argument);
1395 int const unknown_tokens =
1396 owner->buffer()->readHeader(lex);
1398 if (unknown_tokens != 0) {
1399 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1400 << unknown_tokens << " unknown token"
1401 << (unknown_tokens == 1 ? "" : "s")
1404 if (engine == owner->buffer()->params().cite_engine)
1407 LCursor & cur = view()->cursor();
1408 FuncRequest fr(LFUN_INSET_REFRESH);
1410 InsetBase & inset = owner->buffer()->inset();
1411 InsetIterator it = inset_iterator_begin(inset);
1412 InsetIterator const end = inset_iterator_end(inset);
1413 for (; it != end; ++it)
1414 if (it->lyxCode() == InsetBase::CITE_CODE)
1415 it->dispatch(cur, fr);
1419 case LFUN_TEXTCLASS_APPLY: {
1420 Buffer * buffer = owner->buffer();
1422 lyx::textclass_type const old_class =
1423 buffer->params().textclass;
1425 loadTextclass(argument);
1427 std::pair<bool, lyx::textclass_type> const tc_pair =
1428 textclasslist.NumberOfClass(argument);
1433 lyx::textclass_type const new_class = tc_pair.second;
1434 if (old_class == new_class)
1438 owner->message(_("Converting document to new document class..."));
1440 lyx::cap::SwitchLayoutsBetweenClasses(
1441 old_class, new_class,
1442 buffer->paragraphs(), el);
1444 bufferErrors(*buffer, el);
1445 view()->showErrorList(_("Class switch"));
1449 case LFUN_TEXTCLASS_LOAD:
1450 loadTextclass(argument);
1453 case LFUN_LYXRC_APPLY: {
1454 LyXRC const lyxrc_orig = lyxrc;
1456 istringstream ss(argument);
1457 bool const success = lyxrc.read(ss) == 0;
1460 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1461 << "Unable to read lyxrc data"
1466 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1471 view()->cursor().dispatch(cmd);
1472 update |= view()->cursor().result().update();
1473 if (!view()->cursor().result().dispatched()) {
1474 update |= view()->dispatch(cmd);
1481 if (view()->available()) {
1482 // Redraw screen unless explicitly told otherwise.
1483 // This also initializes the position cache for all insets
1484 // in (at least partially) visible top-level paragraphs.
1485 view()->update(true, update);
1487 // if we executed a mutating lfun, mark the buffer as dirty
1488 if (getStatus(cmd).enabled()
1489 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1490 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1491 view()->buffer()->markDirty();
1494 if (view()->cursor().inTexted()) {
1495 view()->owner()->updateLayoutChoice();
1498 sendDispatchMessage(_(getMessage()), cmd);
1502 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1504 owner->updateMenubar();
1505 owner->updateToolbars();
1507 const bool verbose = (cmd.origin == FuncRequest::UI
1508 || cmd.origin == FuncRequest::COMMANDBUFFER);
1510 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1511 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1513 owner->message(msg);
1517 string dispatch_msg = msg;
1518 if (!dispatch_msg.empty())
1519 dispatch_msg += ' ';
1521 string comname = lyxaction.getActionName(cmd.action);
1523 bool argsadded = false;
1525 if (!cmd.argument.empty()) {
1526 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1527 comname += ' ' + cmd.argument;
1532 string const shortcuts = toplevel_keymap->printbindings(cmd);
1534 if (!shortcuts.empty()) {
1535 comname += ": " + shortcuts;
1536 } else if (!argsadded && !cmd.argument.empty()) {
1537 comname += ' ' + cmd.argument;
1540 if (!comname.empty()) {
1541 comname = rtrim(comname);
1542 dispatch_msg += '(' + comname + ')';
1545 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1546 if (!dispatch_msg.empty())
1547 owner->message(dispatch_msg);
1551 void LyXFunc::setupLocalKeymap()
1553 keyseq.stdmap = toplevel_keymap.get();
1554 keyseq.curmap = toplevel_keymap.get();
1555 cancel_meta_seq.stdmap = toplevel_keymap.get();
1556 cancel_meta_seq.curmap = toplevel_keymap.get();
1560 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1562 string initpath = lyxrc.document_path;
1563 string filename(name);
1565 if (view()->available()) {
1566 string const trypath = owner->buffer()->filePath();
1567 // If directory is writeable, use this as default.
1568 if (IsDirWriteable(trypath))
1572 static int newfile_number;
1574 if (filename.empty()) {
1575 filename = AddName(lyxrc.document_path,
1576 "newfile" + convert<string>(++newfile_number) + ".lyx");
1577 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1579 filename = AddName(lyxrc.document_path,
1580 "newfile" + convert<string>(newfile_number) +
1585 // The template stuff
1588 FileDialog fileDlg(_("Select template file"),
1589 LFUN_SELECT_FILE_SYNC,
1590 make_pair(string(_("Documents|#o#O")),
1591 string(lyxrc.document_path)),
1592 make_pair(string(_("Templates|#T#t")),
1593 string(lyxrc.template_path)));
1595 FileDialog::Result result =
1596 fileDlg.open(lyxrc.template_path,
1597 FileFilterList(_("LyX Documents (*.lyx)")),
1600 if (result.first == FileDialog::Later)
1602 if (result.second.empty())
1604 templname = result.second;
1607 view()->newFile(filename, templname, !name.empty());
1611 void LyXFunc::open(string const & fname)
1613 string initpath = lyxrc.document_path;
1615 if (view()->available()) {
1616 string const trypath = owner->buffer()->filePath();
1617 // If directory is writeable, use this as default.
1618 if (IsDirWriteable(trypath))
1624 if (fname.empty()) {
1625 FileDialog fileDlg(_("Select document to open"),
1627 make_pair(string(_("Documents|#o#O")),
1628 string(lyxrc.document_path)),
1629 make_pair(string(_("Examples|#E#e")),
1630 string(AddPath(package().system_support(), "examples"))));
1632 FileDialog::Result result =
1633 fileDlg.open(initpath,
1634 FileFilterList(_("LyX Documents (*.lyx)")),
1637 if (result.first == FileDialog::Later)
1640 filename = result.second;
1642 // check selected filename
1643 if (filename.empty()) {
1644 owner->message(_("Canceled."));
1650 // get absolute path of file and add ".lyx" to the filename if
1652 string const fullpath = FileSearch(string(), filename, "lyx");
1653 if (!fullpath.empty()) {
1654 filename = fullpath;
1657 string const disp_fn(MakeDisplayPath(filename));
1659 // if the file doesn't exist, let the user create one
1660 if (!fs::exists(filename)) {
1661 // the user specifically chose this name. Believe them.
1662 view()->newFile(filename, "", true);
1666 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1669 if (view()->loadLyXFile(filename)) {
1670 str2 = bformat(_("Document %1$s opened."), disp_fn);
1672 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1674 owner->message(str2);
1678 void LyXFunc::doImport(string const & argument)
1681 string filename = split(argument, format, ' ');
1683 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1684 << " file: " << filename << endl;
1686 // need user interaction
1687 if (filename.empty()) {
1688 string initpath = lyxrc.document_path;
1690 if (view()->available()) {
1691 string const trypath = owner->buffer()->filePath();
1692 // If directory is writeable, use this as default.
1693 if (IsDirWriteable(trypath))
1697 string const text = bformat(_("Select %1$s file to import"),
1698 formats.prettyName(format));
1700 FileDialog fileDlg(text,
1702 make_pair(string(_("Documents|#o#O")),
1703 string(lyxrc.document_path)),
1704 make_pair(string(_("Examples|#E#e")),
1705 string(AddPath(package().system_support(), "examples"))));
1707 string const filter = formats.prettyName(format)
1708 + " (*." + formats.extension(format) + ')';
1710 FileDialog::Result result =
1711 fileDlg.open(initpath,
1712 FileFilterList(filter),
1715 if (result.first == FileDialog::Later)
1718 filename = result.second;
1720 // check selected filename
1721 if (filename.empty())
1722 owner->message(_("Canceled."));
1725 if (filename.empty())
1728 // get absolute path of file
1729 filename = MakeAbsPath(filename);
1731 string const lyxfile = ChangeExtension(filename, ".lyx");
1733 // Check if the document already is open
1734 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1735 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1736 owner->message(_("Canceled."));
1741 // if the file exists already, and we didn't do
1742 // -i lyx thefile.lyx, warn
1743 if (fs::exists(lyxfile) && filename != lyxfile) {
1744 string const file = MakeDisplayPath(lyxfile, 30);
1746 string text = bformat(_("The document %1$s already exists.\n\n"
1747 "Do you want to over-write that document?"), file);
1748 int const ret = Alert::prompt(_("Over-write document?"),
1749 text, 0, 1, _("&Over-write"), _("&Cancel"));
1752 owner->message(_("Canceled."));
1757 Importer::Import(owner, filename, format);
1761 void LyXFunc::closeBuffer()
1763 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1764 if (bufferlist.empty()) {
1765 // need this otherwise SEGV may occur while
1766 // trying to set variables that don't exist
1767 // since there's no current buffer
1768 owner->getDialogs().hideBufferDependent();
1770 view()->setBuffer(bufferlist.first());
1776 // Each "owner" should have it's own message method. lyxview and
1777 // the minibuffer would use the minibuffer, but lyxserver would
1778 // send an ERROR signal to its client. Alejandro 970603
1779 // This function is bit problematic when it comes to NLS, to make the
1780 // lyx servers client be language indepenent we must not translate
1781 // strings sent to this func.
1782 void LyXFunc::setErrorMessage(string const & m) const
1784 dispatch_buffer = m;
1789 void LyXFunc::setMessage(string const & m) const
1791 dispatch_buffer = m;
1795 string const LyXFunc::viewStatusMessage()
1797 // When meta-fake key is pressed, show the key sequence so far + "M-".
1799 return keyseq.print() + "M-";
1801 // Else, when a non-complete key sequence is pressed,
1802 // show the available options.
1803 if (keyseq.length() > 0 && !keyseq.deleted())
1804 return keyseq.printOptions();
1806 if (!view()->available())
1807 return _("Welcome to LyX!");
1809 return view()->cursor().currentState();
1813 BufferView * LyXFunc::view() const
1815 BOOST_ASSERT(owner);
1816 return owner->view().get();
1820 bool LyXFunc::wasMetaKey() const
1822 return (meta_fake_bit != key_modifier::none);
1828 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1830 // Why the switch you might ask. It is a trick to ensure that all
1831 // the elements in the LyXRCTags enum is handled. As you can see
1832 // there are no breaks at all. So it is just a huge fall-through.
1833 // The nice thing is that we will get a warning from the compiler
1834 // if we forget an element.
1835 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1837 case LyXRC::RC_ACCEPT_COMPOUND:
1838 case LyXRC::RC_ALT_LANG:
1839 case LyXRC::RC_ASCIIROFF_COMMAND:
1840 case LyXRC::RC_ASCII_LINELEN:
1841 case LyXRC::RC_AUTOREGIONDELETE:
1842 case LyXRC::RC_AUTORESET_OPTIONS:
1843 case LyXRC::RC_AUTOSAVE:
1844 case LyXRC::RC_AUTO_NUMBER:
1845 case LyXRC::RC_BACKUPDIR_PATH:
1846 case LyXRC::RC_BIBTEX_COMMAND:
1847 case LyXRC::RC_BINDFILE:
1848 case LyXRC::RC_CHECKLASTFILES:
1849 case LyXRC::RC_CHKTEX_COMMAND:
1850 case LyXRC::RC_CONVERTER:
1851 case LyXRC::RC_COPIER:
1852 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1853 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1854 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1855 case LyXRC::RC_CYGWIN_PATH_FIX:
1856 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1857 namespace os = lyx::support::os;
1858 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1860 case LyXRC::RC_DATE_INSERT_FORMAT:
1861 case LyXRC::RC_DEFAULT_LANGUAGE:
1862 case LyXRC::RC_DEFAULT_PAPERSIZE:
1863 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1864 case LyXRC::RC_DISPLAY_GRAPHICS:
1865 case LyXRC::RC_DOCUMENTPATH:
1866 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1867 if (fs::exists(lyxrc_new.document_path) &&
1868 fs::is_directory(lyxrc_new.document_path)) {
1869 using lyx::support::package;
1870 package().document_dir() = lyxrc.document_path;
1873 case LyXRC::RC_ESC_CHARS:
1874 case LyXRC::RC_FONT_ENCODING:
1875 case LyXRC::RC_FORMAT:
1876 case LyXRC::RC_INDEX_COMMAND:
1877 case LyXRC::RC_INPUT:
1878 case LyXRC::RC_KBMAP:
1879 case LyXRC::RC_KBMAP_PRIMARY:
1880 case LyXRC::RC_KBMAP_SECONDARY:
1881 case LyXRC::RC_LABEL_INIT_LENGTH:
1882 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1883 case LyXRC::RC_LANGUAGE_AUTO_END:
1884 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1885 case LyXRC::RC_LANGUAGE_COMMAND_END:
1886 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1887 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1888 case LyXRC::RC_LANGUAGE_PACKAGE:
1889 case LyXRC::RC_LANGUAGE_USE_BABEL:
1890 case LyXRC::RC_LASTFILES:
1891 case LyXRC::RC_MAKE_BACKUP:
1892 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1893 case LyXRC::RC_NUMLASTFILES:
1894 case LyXRC::RC_PATH_PREFIX:
1895 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1896 using lyx::support::prependEnvPath;
1897 prependEnvPath("PATH", lyxrc.path_prefix);
1899 case LyXRC::RC_PERS_DICT:
1900 case LyXRC::RC_POPUP_BOLD_FONT:
1901 case LyXRC::RC_POPUP_FONT_ENCODING:
1902 case LyXRC::RC_POPUP_NORMAL_FONT:
1903 case LyXRC::RC_PREVIEW:
1904 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1905 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1906 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1907 case LyXRC::RC_PRINTCOPIESFLAG:
1908 case LyXRC::RC_PRINTER:
1909 case LyXRC::RC_PRINTEVENPAGEFLAG:
1910 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1911 case LyXRC::RC_PRINTFILEEXTENSION:
1912 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1913 case LyXRC::RC_PRINTODDPAGEFLAG:
1914 case LyXRC::RC_PRINTPAGERANGEFLAG:
1915 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1916 case LyXRC::RC_PRINTPAPERFLAG:
1917 case LyXRC::RC_PRINTREVERSEFLAG:
1918 case LyXRC::RC_PRINTSPOOL_COMMAND:
1919 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1920 case LyXRC::RC_PRINTTOFILE:
1921 case LyXRC::RC_PRINTTOPRINTER:
1922 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1923 case LyXRC::RC_PRINT_COMMAND:
1924 case LyXRC::RC_RTL_SUPPORT:
1925 case LyXRC::RC_SCREEN_DPI:
1926 case LyXRC::RC_SCREEN_FONT_ENCODING:
1927 case LyXRC::RC_SCREEN_FONT_ROMAN:
1928 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1929 case LyXRC::RC_SCREEN_FONT_SANS:
1930 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1931 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1932 case LyXRC::RC_SCREEN_FONT_SIZES:
1933 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1934 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1935 case LyXRC::RC_SCREEN_ZOOM:
1936 case LyXRC::RC_SERVERPIPE:
1937 case LyXRC::RC_SET_COLOR:
1938 case LyXRC::RC_SHOW_BANNER:
1939 case LyXRC::RC_SPELL_COMMAND:
1940 case LyXRC::RC_TEMPDIRPATH:
1941 case LyXRC::RC_TEMPLATEPATH:
1942 case LyXRC::RC_UIFILE:
1943 case LyXRC::RC_USER_EMAIL:
1944 case LyXRC::RC_USER_NAME:
1945 case LyXRC::RC_USETEMPDIR:
1946 case LyXRC::RC_USE_ALT_LANG:
1947 case LyXRC::RC_USE_ESC_CHARS:
1948 case LyXRC::RC_USE_INP_ENC:
1949 case LyXRC::RC_USE_PERS_DICT:
1950 case LyXRC::RC_USE_SPELL_LIB:
1951 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1952 case LyXRC::RC_VIEWER:
1953 case LyXRC::RC_WHEEL_JUMP:
1954 case LyXRC::RC_LAST: