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/filesystem/operations.hpp>
97 using bv_funcs::freefont2string;
99 using lyx::support::AbsolutePath;
100 using lyx::support::AddName;
101 using lyx::support::AddPath;
102 using lyx::support::bformat;
103 using lyx::support::ChangeExtension;
104 using lyx::support::contains;
105 using lyx::support::FileFilterList;
106 using lyx::support::FileSearch;
107 using lyx::support::ForkedcallsController;
108 using lyx::support::i18nLibFileSearch;
109 using lyx::support::IsDirWriteable;
110 using lyx::support::IsFileReadable;
111 using lyx::support::isStrInt;
112 using lyx::support::MakeAbsPath;
113 using lyx::support::MakeDisplayPath;
114 using lyx::support::package;
115 using lyx::support::Path;
116 using lyx::support::QuoteName;
117 using lyx::support::rtrim;
118 using lyx::support::split;
119 using lyx::support::subst;
120 using lyx::support::Systemcall;
121 using lyx::support::token;
122 using lyx::support::trim;
123 using lyx::support::prefixIs;
126 using std::make_pair;
129 using std::istringstream;
131 namespace biblio = lyx::biblio;
132 namespace fs = boost::filesystem;
135 extern BufferList bufferlist;
136 extern LyXServer * lyxserver;
138 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
141 extern tex_accent_struct get_accent(kb_action action);
146 bool getStatus(LCursor cursor,
147 FuncRequest const & cmd, FuncStatus & status)
149 // Try to fix cursor in case it is broken.
150 cursor.fixIfBroken();
152 // This is, of course, a mess. Better create a new doc iterator and use
153 // this in Inset::getStatus. This might require an additional
154 // BufferView * arg, though (which should be avoided)
155 //LCursor safe = *this;
157 for ( ; cursor.depth(); cursor.pop()) {
158 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
159 DocIterator::idx_type & idx = cursor.idx();
160 DocIterator::idx_type const lastidx = cursor.lastidx();
161 BOOST_ASSERT(idx <= lastidx);
163 DocIterator::pit_type & pit = cursor.pit();
164 DocIterator::pit_type const lastpit = cursor.lastpit();
165 BOOST_ASSERT(pit <= lastpit);
167 DocIterator::pos_type & pos = cursor.pos();
168 DocIterator::pos_type const lastpos = cursor.lastpos();
169 BOOST_ASSERT(pos <= lastpos);
171 // The inset's getStatus() will return 'true' if it made
172 // a definitive decision on whether it want to handle the
173 // request or not. The result of this decision is put into
174 // the 'status' parameter.
175 if (cursor.inset().getStatus(cursor, cmd, status)) {
185 LyXFunc::LyXFunc(LyXView * lv)
188 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
189 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
190 meta_fake_bit(key_modifier::none)
195 void LyXFunc::handleKeyFunc(kb_action action)
197 char c = encoded_last_key;
199 if (keyseq.length()) {
203 owner->getIntl().getTransManager()
204 .deadkey(c, get_accent(action).accent, view()->getLyXText());
205 // Need to clear, in case the minibuffer calls these
208 // copied verbatim from do_accent_char
209 view()->cursor().resetAnchor();
214 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
216 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
218 // Do nothing if we have nothing (JMarc)
219 if (!keysym->isOK()) {
220 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
225 if (keysym->isModifier()) {
226 lyxerr[Debug::KEY] << "isModifier true" << endl;
230 Encoding const * encoding = view()->cursor().getEncoding();
232 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
234 // Do a one-deep top-level lookup for
235 // cancel and meta-fake keys. RVDK_PATCH_5
236 cancel_meta_seq.reset();
238 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
239 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
240 << " action first set to [" << func.action << ']'
243 // When not cancel or meta-fake, do the normal lookup.
244 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
245 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
246 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
247 // remove Caps Lock and Mod2 as a modifiers
248 func = keyseq.addkey(keysym, (state | meta_fake_bit));
249 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
250 << "action now set to ["
251 << func.action << ']' << endl;
254 // Dont remove this unless you know what you are doing.
255 meta_fake_bit = key_modifier::none;
257 // Can this happen now ?
258 if (func.action == LFUN_NOACTION) {
259 func = FuncRequest(LFUN_PREFIX);
262 if (lyxerr.debugging(Debug::KEY)) {
263 lyxerr << BOOST_CURRENT_FUNCTION
265 << func.action << "]["
266 << keyseq.print() << ']'
270 // already here we know if it any point in going further
271 // why not return already here if action == -1 and
272 // num_bytes == 0? (Lgb)
274 if (keyseq.length() > 1) {
275 owner->message(keyseq.print());
279 // Maybe user can only reach the key via holding down shift.
280 // Let's see. But only if shift is the only modifier
281 if (func.action == LFUN_UNKNOWN_ACTION &&
282 state == key_modifier::shift) {
283 lyxerr[Debug::KEY] << "Trying without shift" << endl;
284 func = keyseq.addkey(keysym, key_modifier::none);
285 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
288 if (func.action == LFUN_UNKNOWN_ACTION) {
289 // Hmm, we didn't match any of the keysequences. See
290 // if it's normal insertable text not already covered
292 if (keysym->isText() && keyseq.length() == 1) {
293 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
294 func = FuncRequest(LFUN_SELFINSERT);
296 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
297 owner->message(_("Unknown function."));
302 if (func.action == LFUN_SELFINSERT) {
303 if (encoded_last_key != 0) {
304 string const arg(1, encoded_last_key);
305 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
307 << "SelfInsert arg[`" << arg << "']" << endl;
315 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
317 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
319 LCursor & cur = view()->cursor();
321 /* In LyX/Mac, when a dialog is open, the menus of the
322 application can still be accessed without giving focus to
323 the main window. In this case, we want to disable the menu
324 entries that are buffer-related.
327 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
330 buf = owner->buffer();
332 if (cmd.action == LFUN_NOACTION) {
333 flag.message(N_("Nothing to do"));
338 switch (cmd.action) {
339 case LFUN_UNKNOWN_ACTION:
340 #ifndef HAVE_LIBAIKSAURUS
341 case LFUN_THESAURUS_ENTRY:
347 flag |= lyx_gui::getStatus(cmd);
350 if (flag.unknown()) {
351 flag.message(N_("Unknown action"));
355 if (!flag.enabled()) {
356 if (flag.message().empty())
357 flag.message(N_("Command disabled"));
361 // Check whether we need a buffer
362 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
364 flag.message(N_("Command not allowed with"
365 "out any document open"));
370 // I would really like to avoid having this switch and rather try to
371 // encode this in the function itself.
372 // -- And I'd rather let an inset decide which LFUNs it is willing
373 // to handle (Andre')
375 switch (cmd.action) {
376 case LFUN_TOOLTIPS_TOGGLE:
377 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
380 case LFUN_READ_ONLY_TOGGLE:
381 flag.setOnOff(buf->isReadonly());
384 case LFUN_SWITCHBUFFER:
385 // toggle on the current buffer, but do not toggle off
386 // the other ones (is that a good idea?)
387 if (cmd.argument == buf->fileName())
392 enable = cmd.argument == "custom"
393 || Exporter::IsExportable(*buf, cmd.argument);
397 enable = cur.selection();
401 enable = buf->isLatex() && lyxrc.chktex_command != "none";
405 enable = Exporter::IsExportable(*buf, "program");
408 case LFUN_LAYOUT_TABULAR:
409 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
413 case LFUN_LAYOUT_PARAGRAPH:
414 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
417 case LFUN_VC_REGISTER:
418 enable = !buf->lyxvc().inUse();
420 case LFUN_VC_CHECKIN:
421 enable = buf->lyxvc().inUse() && !buf->isReadonly();
423 case LFUN_VC_CHECKOUT:
424 enable = buf->lyxvc().inUse() && buf->isReadonly();
428 enable = buf->lyxvc().inUse();
430 case LFUN_MENURELOAD:
431 enable = !buf->isUnnamed() && !buf->isClean();
434 case LFUN_INSET_SETTINGS: {
438 UpdatableInset * inset = cur.inset().asUpdatableInset();
439 lyxerr << "inset: " << inset << endl;
443 InsetBase::Code code = inset->lyxCode();
445 case InsetBase::TABULAR_CODE:
446 enable = cmd.argument == "tabular";
448 case InsetBase::ERT_CODE:
449 enable = cmd.argument == "ert";
451 case InsetBase::FLOAT_CODE:
452 enable = cmd.argument == "float";
454 case InsetBase::WRAP_CODE:
455 enable = cmd.argument == "wrap";
457 case InsetBase::NOTE_CODE:
458 enable = cmd.argument == "note";
460 case InsetBase::BRANCH_CODE:
461 enable = cmd.argument == "branch";
463 case InsetBase::BOX_CODE:
464 enable = cmd.argument == "box";
472 case LFUN_DIALOG_SHOW: {
473 string const name = cmd.getArg(0);
475 enable = name == "aboutlyx"
479 || name == "texinfo";
480 else if (name == "print")
481 enable = Exporter::IsExportable(*buf, "dvi")
482 && lyxrc.print_command != "none";
483 else if (name == "character" || name == "mathpanel")
484 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
485 else if (name == "vclog")
486 enable = buf->lyxvc().inUse();
487 else if (name == "latexlog")
488 enable = IsFileReadable(buf->getLogName().second);
492 case LFUN_DIALOG_SHOW_NEW_INSET:
493 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
496 case LFUN_DIALOG_UPDATE: {
497 string const name = cmd.getArg(0);
499 enable = name == "prefs";
503 // this one is difficult to get right. As a half-baked
504 // solution, we consider only the first action of the sequence
505 case LFUN_SEQUENCE: {
506 // argument contains ';'-terminated commands
507 string const firstcmd = token(cmd.argument, ';', 0);
508 FuncRequest func(lyxaction.lookupFunc(firstcmd));
509 func.origin = cmd.origin;
510 flag = getStatus(func);
514 case LFUN_MENUNEWTMPLT:
515 case LFUN_WORDFINDFORWARD:
516 case LFUN_WORDFINDBACKWARD:
518 case LFUN_EXEC_COMMAND:
521 case LFUN_CLOSEBUFFER:
530 case LFUN_RECONFIGURE:
534 case LFUN_DROP_LAYOUTS_CHOICE:
535 case LFUN_MENU_OPEN_BY_NAME:
538 case LFUN_GOTOFILEROW:
539 case LFUN_DIALOG_SHOW_NEXT_INSET:
540 case LFUN_DIALOG_HIDE:
541 case LFUN_DIALOG_DISCONNECT_INSET:
543 case LFUN_TOGGLECURSORFOLLOW:
547 case LFUN_KMAP_TOGGLE:
549 case LFUN_EXPORT_CUSTOM:
551 case LFUN_SAVEPREFERENCES:
552 case LFUN_SCREEN_FONT_UPDATE:
555 case LFUN_EXTERNAL_EDIT:
556 case LFUN_GRAPHICS_EDIT:
557 case LFUN_ALL_INSETS_TOGGLE:
558 case LFUN_LANGUAGE_BUFFER:
559 case LFUN_TEXTCLASS_APPLY:
560 case LFUN_TEXTCLASS_LOAD:
561 case LFUN_SAVE_AS_DEFAULT:
562 case LFUN_BUFFERPARAMS_APPLY:
563 case LFUN_LYXRC_APPLY:
564 case LFUN_NEXTBUFFER:
565 case LFUN_PREVIOUSBUFFER:
566 // these are handled in our dispatch()
571 if (!::getStatus(cur, cmd, flag))
572 flag = view()->getStatus(cmd);
578 // Can we use a readonly buffer?
579 if (buf && buf->isReadonly()
580 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
581 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
582 flag.message(N_("Document is read-only"));
586 // the default error message if we disable the command
587 if (!flag.enabled() && flag.message().empty())
588 flag.message(N_("Command disabled"));
596 bool ensureBufferClean(BufferView * bv)
598 Buffer & buf = *bv->buffer();
602 string const file = MakeDisplayPath(buf.fileName(), 30);
603 string text = bformat(_("The document %1$s has unsaved "
604 "changes.\n\nDo you want to save "
605 "the document?"), file);
606 int const ret = Alert::prompt(_("Save changed document?"),
607 text, 0, 1, _("&Save"),
611 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
613 return buf.isClean();
617 void showPrintError(string const & name)
619 string str = bformat(_("Could not print the document %1$s.\n"
620 "Check that your printer is set up correctly."),
621 MakeDisplayPath(name, 50));
622 Alert::error(_("Print document failed"), str);
626 void loadTextclass(string const & name)
628 std::pair<bool, lyx::textclass_type> const tc_pair =
629 textclasslist.NumberOfClass(name);
631 if (!tc_pair.first) {
632 lyxerr << "Document class \"" << name
633 << "\" does not exist."
638 lyx::textclass_type const tc = tc_pair.second;
640 if (!textclasslist[tc].load()) {
641 string s = bformat(_("The document could not be converted\n"
642 "into the document class %1$s."),
643 textclasslist[tc].name());
644 Alert::error(_("Could not change class"), s);
649 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
654 void LyXFunc::dispatch(FuncRequest const & cmd)
656 BOOST_ASSERT(view());
657 string const argument = cmd.argument;
658 kb_action const action = cmd.action;
660 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
661 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
663 // we have not done anything wrong yet.
665 dispatch_buffer.erase();
669 FuncStatus const flag = getStatus(cmd);
670 if (!flag.enabled()) {
671 // We cannot use this function here
672 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
673 << lyxaction.getActionName(action)
674 << " [" << action << "] is disabled at this location"
676 setErrorMessage(flag.message());
679 if (view()->available())
680 view()->hideCursor();
684 case LFUN_WORDFINDFORWARD:
685 case LFUN_WORDFINDBACKWARD: {
686 static string last_search;
687 string searched_string;
689 if (!argument.empty()) {
690 last_search = argument;
691 searched_string = argument;
693 searched_string = last_search;
696 if (searched_string.empty())
699 bool const fw = action == LFUN_WORDFINDFORWARD;
701 lyx::find::find2string(searched_string, true, false, fw);
702 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
707 owner->message(keyseq.printOptions());
710 case LFUN_EXEC_COMMAND:
711 owner->getToolbars().display("minibuffer", true);
712 owner->focus_command_buffer();
717 meta_fake_bit = key_modifier::none;
718 if (view()->available())
719 // cancel any selection
720 dispatch(FuncRequest(LFUN_MARK_OFF));
721 setMessage(N_("Cancel"));
725 meta_fake_bit = key_modifier::alt;
726 setMessage(keyseq.print());
729 case LFUN_READ_ONLY_TOGGLE:
730 if (owner->buffer()->lyxvc().inUse())
731 owner->buffer()->lyxvc().toggleReadOnly();
733 owner->buffer()->setReadonly(
734 !owner->buffer()->isReadonly());
737 // --- Menus -----------------------------------------------
739 menuNew(argument, false);
742 case LFUN_MENUNEWTMPLT:
743 menuNew(argument, true);
746 case LFUN_CLOSEBUFFER:
751 if (!owner->buffer()->isUnnamed()) {
752 string const str = bformat(_("Saving document %1$s..."),
753 MakeDisplayPath(owner->buffer()->fileName()));
755 MenuWrite(owner->buffer());
756 owner->message(str + _(" done."));
758 WriteAs(owner->buffer());
762 WriteAs(owner->buffer(), argument);
765 case LFUN_MENURELOAD: {
766 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
767 string text = bformat(_("Any changes will be lost. Are you sure "
768 "you want to revert to the saved version of the document %1$s?"), file);
769 int const ret = Alert::prompt(_("Revert to saved document?"),
770 text, 0, 1, _("&Revert"), _("&Cancel"));
778 Exporter::Export(owner->buffer(), argument, true);
779 view()->showErrorList(BufferFormat(*owner->buffer()));
783 Exporter::Preview(owner->buffer(), argument);
784 view()->showErrorList(BufferFormat(*owner->buffer()));
788 Exporter::Export(owner->buffer(), "program", true);
789 view()->showErrorList(_("Build"));
793 owner->buffer()->runChktex();
794 view()->showErrorList(_("ChkTeX"));
798 if (argument == "custom")
799 owner->getDialogs().show("sendto");
801 Exporter::Export(owner->buffer(), argument, false);
802 view()->showErrorList(BufferFormat(*owner->buffer()));
806 case LFUN_EXPORT_CUSTOM: {
808 string command = split(argument, format_name, ' ');
809 Format const * format = formats.getFormat(format_name);
811 lyxerr << "Format \"" << format_name
812 << "\" not recognized!"
817 Buffer * buffer = owner->buffer();
819 // The name of the file created by the conversion process
822 // Output to filename
823 if (format->name() == "lyx") {
824 string const latexname =
825 buffer->getLatexName(false);
826 filename = ChangeExtension(latexname,
827 format->extension());
828 filename = AddName(buffer->temppath(), filename);
830 if (!buffer->writeFile(filename))
834 Exporter::Export(buffer, format_name, true,
838 // Substitute $$FName for filename
839 if (!contains(command, "$$FName"))
840 command = "( " + command + " ) < $$FName";
841 command = subst(command, "$$FName", filename);
843 // Execute the command in the background
845 call.startscript(Systemcall::DontWait, command);
852 string command = split(split(argument, target, ' '),
856 || target_name.empty()
857 || command.empty()) {
858 lyxerr << "Unable to parse \""
859 << argument << '"' << std::endl;
862 if (target != "printer" && target != "file") {
863 lyxerr << "Unrecognized target \""
864 << target << '"' << std::endl;
868 Buffer * buffer = owner->buffer();
870 if (!Exporter::Export(buffer, "dvi", true)) {
871 showPrintError(buffer->fileName());
875 // Push directory path.
876 string const path = buffer->temppath();
879 // there are three cases here:
880 // 1. we print to a file
881 // 2. we print directly to a printer
882 // 3. we print using a spool command (print to file first)
885 string const dviname =
886 ChangeExtension(buffer->getLatexName(true),
889 if (target == "printer") {
890 if (!lyxrc.print_spool_command.empty()) {
891 // case 3: print using a spool
892 string const psname =
893 ChangeExtension(dviname,".ps");
894 command += lyxrc.print_to_file
897 + QuoteName(dviname);
900 lyxrc.print_spool_command +' ';
901 if (target_name != "default") {
902 command2 += lyxrc.print_spool_printerprefix
906 command2 += QuoteName(psname);
908 // If successful, then spool command
909 res = one.startscript(
914 res = one.startscript(
915 Systemcall::DontWait,
918 // case 2: print directly to a printer
919 res = one.startscript(
920 Systemcall::DontWait,
921 command + QuoteName(dviname));
925 // case 1: print to a file
926 command += lyxrc.print_to_file
927 + QuoteName(MakeAbsPath(target_name,
930 + QuoteName(dviname);
931 res = one.startscript(Systemcall::DontWait,
936 showPrintError(buffer->fileName());
949 InsetCommandParams p("tableofcontents");
950 string const data = InsetCommandMailer::params2string("toc", p);
951 owner->getDialogs().show("toc", data, 0);
959 case LFUN_RECONFIGURE:
963 case LFUN_HELP_OPEN: {
964 string const arg = argument;
966 setErrorMessage(N_("Missing argument"));
969 string const fname = i18nLibFileSearch("doc", arg, "lyx");
971 lyxerr << "LyX: unable to find documentation file `"
972 << arg << "'. Bad installation?" << endl;
975 owner->message(bformat(_("Opening help file %1$s..."),
976 MakeDisplayPath(fname)));
977 view()->loadLyXFile(fname, false);
981 // --- version control -------------------------------
982 case LFUN_VC_REGISTER:
983 if (!ensureBufferClean(view()))
985 if (!owner->buffer()->lyxvc().inUse()) {
986 owner->buffer()->lyxvc().registrer();
991 case LFUN_VC_CHECKIN:
992 if (!ensureBufferClean(view()))
994 if (owner->buffer()->lyxvc().inUse()
995 && !owner->buffer()->isReadonly()) {
996 owner->buffer()->lyxvc().checkIn();
1001 case LFUN_VC_CHECKOUT:
1002 if (!ensureBufferClean(view()))
1004 if (owner->buffer()->lyxvc().inUse()
1005 && owner->buffer()->isReadonly()) {
1006 owner->buffer()->lyxvc().checkOut();
1011 case LFUN_VC_REVERT:
1012 owner->buffer()->lyxvc().revert();
1017 owner->buffer()->lyxvc().undoLast();
1021 // --- buffers ----------------------------------------
1022 case LFUN_SWITCHBUFFER:
1023 view()->setBuffer(bufferlist.getBuffer(argument));
1026 case LFUN_NEXTBUFFER:
1027 view()->setBuffer(bufferlist.next(view()->buffer()));
1030 case LFUN_PREVIOUSBUFFER:
1031 view()->setBuffer(bufferlist.previous(view()->buffer()));
1035 NewFile(view(), argument);
1038 case LFUN_FILE_OPEN:
1042 case LFUN_DROP_LAYOUTS_CHOICE:
1043 owner->getToolbars().openLayoutList();
1046 case LFUN_MENU_OPEN_BY_NAME:
1047 owner->getMenubar().openByName(argument);
1050 // --- lyxserver commands ----------------------------
1052 setMessage(owner->buffer()->fileName());
1053 lyxerr[Debug::INFO] << "FNAME["
1054 << owner->buffer()->fileName()
1059 dispatch_buffer = keyseq.print();
1060 lyxserver->notifyClient(dispatch_buffer);
1063 case LFUN_GOTOFILEROW: {
1066 istringstream is(argument);
1067 is >> file_name >> row;
1068 if (prefixIs(file_name, package().temp_dir())) {
1069 // Needed by inverse dvi search. If it is a file
1070 // in tmpdir, call the apropriated function
1071 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1073 // Must replace extension of the file to be .lyx
1074 // and get full path
1075 string const s = ChangeExtension(file_name, ".lyx");
1076 // Either change buffer or load the file
1077 if (bufferlist.exists(s)) {
1078 view()->setBuffer(bufferlist.getBuffer(s));
1080 view()->loadLyXFile(s);
1084 view()->setCursorFromRow(row);
1087 // see BufferView_pimpl::center()
1088 view()->updateScrollbar();
1092 case LFUN_DIALOG_SHOW: {
1093 string const name = cmd.getArg(0);
1094 string data = trim(cmd.argument.substr(name.size()));
1096 if (name == "character") {
1097 data = freefont2string();
1099 owner->getDialogs().show("character", data);
1102 else if (name == "latexlog") {
1103 pair<Buffer::LogType, string> const logfile =
1104 owner->buffer()->getLogName();
1105 switch (logfile.first) {
1106 case Buffer::latexlog:
1109 case Buffer::buildlog:
1113 data += logfile.second;
1114 owner->getDialogs().show("log", data);
1116 else if (name == "vclog") {
1117 string const data = "vc " +
1118 owner->buffer()->lyxvc().getLogFile();
1119 owner->getDialogs().show("log", data);
1122 owner->getDialogs().show(name, data);
1126 case LFUN_DIALOG_SHOW_NEW_INSET: {
1127 string const name = cmd.getArg(0);
1128 string data = trim(cmd.argument.substr(name.size()));
1129 if (name == "bibitem" ||
1131 name == "include" ||
1137 InsetCommandParams p(name);
1138 data = InsetCommandMailer::params2string(name, p);
1139 } else if (name == "box") {
1140 // \c data == "Boxed" || "Frameless" etc
1141 InsetBoxParams p(data);
1142 data = InsetBoxMailer::params2string(p);
1143 } else if (name == "branch") {
1144 InsetBranchParams p;
1145 data = InsetBranchMailer::params2string(p);
1146 } else if (name == "citation") {
1147 InsetCommandParams p("cite");
1148 data = InsetCommandMailer::params2string(name, p);
1149 } else if (name == "ert") {
1150 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1151 } else if (name == "external") {
1152 InsetExternalParams p;
1153 Buffer const & buffer = *owner->buffer();
1154 data = InsetExternalMailer::params2string(p, buffer);
1155 } else if (name == "float") {
1157 data = InsetFloatMailer::params2string(p);
1158 } else if (name == "graphics") {
1159 InsetGraphicsParams p;
1160 Buffer const & buffer = *owner->buffer();
1161 data = InsetGraphicsMailer::params2string(p, buffer);
1162 } else if (name == "note") {
1164 data = InsetNoteMailer::params2string(p);
1165 } else if (name == "vspace") {
1167 data = InsetVSpaceMailer::params2string(space);
1168 } else if (name == "wrap") {
1170 data = InsetWrapMailer::params2string(p);
1172 owner->getDialogs().show(name, data, 0);
1176 case LFUN_DIALOG_SHOW_NEXT_INSET:
1179 case LFUN_DIALOG_UPDATE: {
1180 string const & name = argument;
1181 // Can only update a dialog connected to an existing inset
1182 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1184 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1185 inset->dispatch(view()->cursor(), fr);
1186 } else if (name == "paragraph") {
1187 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1188 } else if (name == "prefs") {
1189 owner->getDialogs().update(name, string());
1194 case LFUN_DIALOG_HIDE:
1195 Dialogs::hide(argument, 0);
1198 case LFUN_DIALOG_DISCONNECT_INSET:
1199 owner->getDialogs().disconnect(argument);
1202 case LFUN_CHILDOPEN: {
1203 string const filename =
1204 MakeAbsPath(argument, owner->buffer()->filePath());
1205 setMessage(N_("Opening child document ") +
1206 MakeDisplayPath(filename) + "...");
1207 view()->savePosition(0);
1208 string const parentfilename = owner->buffer()->fileName();
1209 if (bufferlist.exists(filename))
1210 view()->setBuffer(bufferlist.getBuffer(filename));
1212 view()->loadLyXFile(filename);
1213 // Set the parent name of the child document.
1214 // This makes insertion of citations and references in the child work,
1215 // when the target is in the parent or another child document.
1216 owner->buffer()->setParentName(parentfilename);
1220 case LFUN_TOGGLECURSORFOLLOW:
1221 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1225 owner->getIntl().KeyMapOn(false);
1228 case LFUN_KMAP_PRIM:
1229 owner->getIntl().KeyMapPrim();
1233 owner->getIntl().KeyMapSec();
1236 case LFUN_KMAP_TOGGLE:
1237 owner->getIntl().ToggleKeyMap();
1243 string rest = split(argument, countstr, ' ');
1244 istringstream is(countstr);
1247 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1248 for (int i = 0; i < count; ++i)
1249 dispatch(lyxaction.lookupFunc(rest));
1253 case LFUN_SEQUENCE: {
1254 // argument contains ';'-terminated commands
1255 string arg = argument;
1256 while (!arg.empty()) {
1258 arg = split(arg, first, ';');
1259 FuncRequest func(lyxaction.lookupFunc(first));
1260 func.origin = cmd.origin;
1266 case LFUN_SAVEPREFERENCES: {
1267 Path p(package().user_support());
1268 lyxrc.write("preferences", false);
1272 case LFUN_SCREEN_FONT_UPDATE:
1273 // handle the screen font changes.
1274 lyxrc.set_font_norm_type();
1275 lyx_gui::update_fonts();
1276 // All visible buffers will need resize
1280 case LFUN_SET_COLOR: {
1282 string const x11_name = split(argument, lyx_name, ' ');
1283 if (lyx_name.empty() || x11_name.empty()) {
1284 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1289 bool const graphicsbg_changed =
1290 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1291 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1293 if (!lcolor.setColor(lyx_name, x11_name)) {
1295 bformat(_("Set-color \"%1$s\" failed "
1296 "- color is undefined or "
1297 "may not be redefined"), lyx_name));
1301 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1303 if (graphicsbg_changed) {
1304 #ifdef WITH_WARNINGS
1305 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1308 lyx::graphics::GCache::get().changeDisplay(true);
1315 owner->message(argument);
1318 case LFUN_TOOLTIPS_TOGGLE:
1319 owner->getDialogs().toggleTooltips();
1322 case LFUN_EXTERNAL_EDIT: {
1323 FuncRequest fr(action, argument);
1324 InsetExternal().dispatch(view()->cursor(), fr);
1328 case LFUN_GRAPHICS_EDIT: {
1329 FuncRequest fr(action, argument);
1330 InsetGraphics().dispatch(view()->cursor(), fr);
1334 case LFUN_ALL_INSETS_TOGGLE: {
1336 string const name = split(argument, action, ' ');
1337 InsetBase::Code const inset_code =
1338 InsetBase::translate(name);
1340 LCursor & cur = view()->cursor();
1341 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1343 InsetBase & inset = owner->buffer()->inset();
1344 InsetIterator it = inset_iterator_begin(inset);
1345 InsetIterator const end = inset_iterator_end(inset);
1346 for (; it != end; ++it) {
1347 if (inset_code == InsetBase::NO_CODE
1348 || inset_code == it->lyxCode())
1349 it->dispatch(cur, fr);
1354 case LFUN_LANGUAGE_BUFFER: {
1355 Buffer & buffer = *owner->buffer();
1356 Language const * oldL = buffer.params().language;
1357 Language const * newL = languages.getLanguage(argument);
1358 if (!newL || oldL == newL)
1361 if (oldL->RightToLeft() == newL->RightToLeft()
1362 && !buffer.isMultiLingual())
1363 buffer.changeLanguage(oldL, newL);
1365 buffer.updateDocLang(newL);
1369 case LFUN_SAVE_AS_DEFAULT: {
1370 string const fname =
1371 AddName(AddPath(package().user_support(), "templates/"),
1373 Buffer defaults(fname);
1375 istringstream ss(argument);
1378 int const unknown_tokens = defaults.readHeader(lex);
1380 if (unknown_tokens != 0) {
1381 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1382 << unknown_tokens << " unknown token"
1383 << (unknown_tokens == 1 ? "" : "s")
1387 if (defaults.writeFile(defaults.fileName()))
1388 setMessage(_("Document defaults saved in ")
1389 + MakeDisplayPath(fname));
1391 setErrorMessage(_("Unable to save document defaults"));
1395 case LFUN_BUFFERPARAMS_APPLY: {
1396 biblio::CiteEngine const engine =
1397 owner->buffer()->params().cite_engine;
1399 istringstream ss(argument);
1402 int const unknown_tokens =
1403 owner->buffer()->readHeader(lex);
1405 if (unknown_tokens != 0) {
1406 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1407 << unknown_tokens << " unknown token"
1408 << (unknown_tokens == 1 ? "" : "s")
1411 if (engine == owner->buffer()->params().cite_engine)
1414 LCursor & cur = view()->cursor();
1415 FuncRequest fr(LFUN_INSET_REFRESH);
1417 InsetBase & inset = owner->buffer()->inset();
1418 InsetIterator it = inset_iterator_begin(inset);
1419 InsetIterator const end = inset_iterator_end(inset);
1420 for (; it != end; ++it)
1421 if (it->lyxCode() == InsetBase::CITE_CODE)
1422 it->dispatch(cur, fr);
1426 case LFUN_TEXTCLASS_APPLY: {
1427 Buffer * buffer = owner->buffer();
1429 lyx::textclass_type const old_class =
1430 buffer->params().textclass;
1432 loadTextclass(argument);
1434 std::pair<bool, lyx::textclass_type> const tc_pair =
1435 textclasslist.NumberOfClass(argument);
1440 lyx::textclass_type const new_class = tc_pair.second;
1441 if (old_class == new_class)
1445 owner->message(_("Converting document to new document class..."));
1447 lyx::cap::SwitchLayoutsBetweenClasses(
1448 old_class, new_class,
1449 buffer->paragraphs(), el);
1451 bufferErrors(*buffer, el);
1452 view()->showErrorList(_("Class switch"));
1456 case LFUN_TEXTCLASS_LOAD:
1457 loadTextclass(argument);
1460 case LFUN_LYXRC_APPLY: {
1461 LyXRC const lyxrc_orig = lyxrc;
1463 istringstream ss(argument);
1464 bool const success = lyxrc.read(ss) == 0;
1467 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1468 << "Unable to read lyxrc data"
1473 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1478 view()->cursor().dispatch(cmd);
1479 update |= view()->cursor().result().update();
1480 if (!view()->cursor().result().dispatched()) {
1481 update |= view()->dispatch(cmd);
1488 if (view()->available()) {
1489 // Redraw screen unless explicitly told otherwise.
1490 // This also initializes the position cache for all insets
1491 // in (at least partially) visible top-level paragraphs.
1492 view()->update(true, update);
1494 // if we executed a mutating lfun, mark the buffer as dirty
1495 if (getStatus(cmd).enabled()
1496 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1497 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1498 view()->buffer()->markDirty();
1501 if (view()->cursor().inTexted()) {
1502 view()->owner()->updateLayoutChoice();
1505 sendDispatchMessage(getMessage(), cmd);
1509 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1511 owner->updateMenubar();
1512 owner->updateToolbars();
1514 const bool verbose = (cmd.origin == FuncRequest::UI
1515 || cmd.origin == FuncRequest::COMMANDBUFFER);
1517 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1518 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1520 owner->message(msg);
1524 string dispatch_msg = msg;
1525 if (!dispatch_msg.empty())
1526 dispatch_msg += ' ';
1528 string comname = lyxaction.getActionName(cmd.action);
1530 bool argsadded = false;
1532 if (!cmd.argument.empty()) {
1533 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1534 comname += ' ' + cmd.argument;
1539 string const shortcuts = toplevel_keymap->printbindings(cmd);
1541 if (!shortcuts.empty()) {
1542 comname += ": " + shortcuts;
1543 } else if (!argsadded && !cmd.argument.empty()) {
1544 comname += ' ' + cmd.argument;
1547 if (!comname.empty()) {
1548 comname = rtrim(comname);
1549 dispatch_msg += '(' + comname + ')';
1552 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1553 if (!dispatch_msg.empty())
1554 owner->message(dispatch_msg);
1558 void LyXFunc::setupLocalKeymap()
1560 keyseq.stdmap = toplevel_keymap.get();
1561 keyseq.curmap = toplevel_keymap.get();
1562 cancel_meta_seq.stdmap = toplevel_keymap.get();
1563 cancel_meta_seq.curmap = toplevel_keymap.get();
1567 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1569 string initpath = lyxrc.document_path;
1570 string filename(name);
1572 if (view()->available()) {
1573 string const trypath = owner->buffer()->filePath();
1574 // If directory is writeable, use this as default.
1575 if (IsDirWriteable(trypath))
1579 static int newfile_number;
1581 if (filename.empty()) {
1582 filename = AddName(lyxrc.document_path,
1583 "newfile" + convert<string>(++newfile_number) + ".lyx");
1584 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1586 filename = AddName(lyxrc.document_path,
1587 "newfile" + convert<string>(newfile_number) +
1592 // The template stuff
1595 FileDialog fileDlg(_("Select template file"),
1596 LFUN_SELECT_FILE_SYNC,
1597 make_pair(string(_("Documents|#o#O")),
1598 string(lyxrc.document_path)),
1599 make_pair(string(_("Templates|#T#t")),
1600 string(lyxrc.template_path)));
1602 FileDialog::Result result =
1603 fileDlg.open(lyxrc.template_path,
1604 FileFilterList(_("LyX Documents (*.lyx)")),
1607 if (result.first == FileDialog::Later)
1609 if (result.second.empty())
1611 templname = result.second;
1614 view()->newFile(filename, templname, !name.empty());
1618 void LyXFunc::open(string const & fname)
1620 string initpath = lyxrc.document_path;
1622 if (view()->available()) {
1623 string const trypath = owner->buffer()->filePath();
1624 // If directory is writeable, use this as default.
1625 if (IsDirWriteable(trypath))
1631 if (fname.empty()) {
1632 FileDialog fileDlg(_("Select document to open"),
1634 make_pair(string(_("Documents|#o#O")),
1635 string(lyxrc.document_path)),
1636 make_pair(string(_("Examples|#E#e")),
1637 string(AddPath(package().system_support(), "examples"))));
1639 FileDialog::Result result =
1640 fileDlg.open(initpath,
1641 FileFilterList(_("LyX Documents (*.lyx)")),
1644 if (result.first == FileDialog::Later)
1647 filename = result.second;
1649 // check selected filename
1650 if (filename.empty()) {
1651 owner->message(_("Canceled."));
1657 // get absolute path of file and add ".lyx" to the filename if
1659 string const fullpath = FileSearch(string(), filename, "lyx");
1660 if (!fullpath.empty()) {
1661 filename = fullpath;
1664 string const disp_fn(MakeDisplayPath(filename));
1666 // if the file doesn't exist, let the user create one
1667 if (!fs::exists(filename)) {
1668 // the user specifically chose this name. Believe them.
1669 view()->newFile(filename, "", true);
1673 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1676 if (view()->loadLyXFile(filename)) {
1677 str2 = bformat(_("Document %1$s opened."), disp_fn);
1679 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1681 owner->message(str2);
1685 void LyXFunc::doImport(string const & argument)
1688 string filename = split(argument, format, ' ');
1690 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1691 << " file: " << filename << endl;
1693 // need user interaction
1694 if (filename.empty()) {
1695 string initpath = lyxrc.document_path;
1697 if (view()->available()) {
1698 string const trypath = owner->buffer()->filePath();
1699 // If directory is writeable, use this as default.
1700 if (IsDirWriteable(trypath))
1704 string const text = bformat(_("Select %1$s file to import"),
1705 formats.prettyName(format));
1707 FileDialog fileDlg(text,
1709 make_pair(string(_("Documents|#o#O")),
1710 string(lyxrc.document_path)),
1711 make_pair(string(_("Examples|#E#e")),
1712 string(AddPath(package().system_support(), "examples"))));
1714 string const filter = formats.prettyName(format)
1715 + " (*." + formats.extension(format) + ')';
1717 FileDialog::Result result =
1718 fileDlg.open(initpath,
1719 FileFilterList(filter),
1722 if (result.first == FileDialog::Later)
1725 filename = result.second;
1727 // check selected filename
1728 if (filename.empty())
1729 owner->message(_("Canceled."));
1732 if (filename.empty())
1735 // get absolute path of file
1736 filename = MakeAbsPath(filename);
1738 string const lyxfile = ChangeExtension(filename, ".lyx");
1740 // Check if the document already is open
1741 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1742 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1743 owner->message(_("Canceled."));
1748 // if the file exists already, and we didn't do
1749 // -i lyx thefile.lyx, warn
1750 if (fs::exists(lyxfile) && filename != lyxfile) {
1751 string const file = MakeDisplayPath(lyxfile, 30);
1753 string text = bformat(_("The document %1$s already exists.\n\n"
1754 "Do you want to over-write that document?"), file);
1755 int const ret = Alert::prompt(_("Over-write document?"),
1756 text, 0, 1, _("&Over-write"), _("&Cancel"));
1759 owner->message(_("Canceled."));
1764 Importer::Import(owner, filename, format);
1768 void LyXFunc::closeBuffer()
1770 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1771 if (bufferlist.empty()) {
1772 // need this otherwise SEGV may occur while
1773 // trying to set variables that don't exist
1774 // since there's no current buffer
1775 owner->getDialogs().hideBufferDependent();
1777 view()->setBuffer(bufferlist.first());
1783 // Each "owner" should have it's own message method. lyxview and
1784 // the minibuffer would use the minibuffer, but lyxserver would
1785 // send an ERROR signal to its client. Alejandro 970603
1786 // This function is bit problematic when it comes to NLS, to make the
1787 // lyx servers client be language indepenent we must not translate
1788 // strings sent to this func.
1789 void LyXFunc::setErrorMessage(string const & m) const
1791 dispatch_buffer = m;
1796 void LyXFunc::setMessage(string const & m) const
1798 dispatch_buffer = m;
1802 string const LyXFunc::viewStatusMessage()
1804 // When meta-fake key is pressed, show the key sequence so far + "M-".
1806 return keyseq.print() + "M-";
1808 // Else, when a non-complete key sequence is pressed,
1809 // show the available options.
1810 if (keyseq.length() > 0 && !keyseq.deleted())
1811 return keyseq.printOptions();
1813 if (!view()->available())
1814 return _("Welcome to LyX!");
1816 return view()->cursor().currentState();
1820 BufferView * LyXFunc::view() const
1822 BOOST_ASSERT(owner);
1823 return owner->view().get();
1827 bool LyXFunc::wasMetaKey() const
1829 return (meta_fake_bit != key_modifier::none);
1835 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1837 // Why the switch you might ask. It is a trick to ensure that all
1838 // the elements in the LyXRCTags enum is handled. As you can see
1839 // there are no breaks at all. So it is just a huge fall-through.
1840 // The nice thing is that we will get a warning from the compiler
1841 // if we forget an element.
1842 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1844 case LyXRC::RC_ACCEPT_COMPOUND:
1845 case LyXRC::RC_ALT_LANG:
1846 case LyXRC::RC_ASCIIROFF_COMMAND:
1847 case LyXRC::RC_ASCII_LINELEN:
1848 case LyXRC::RC_AUTOREGIONDELETE:
1849 case LyXRC::RC_AUTORESET_OPTIONS:
1850 case LyXRC::RC_AUTOSAVE:
1851 case LyXRC::RC_AUTO_NUMBER:
1852 case LyXRC::RC_BACKUPDIR_PATH:
1853 case LyXRC::RC_BIBTEX_COMMAND:
1854 case LyXRC::RC_BINDFILE:
1855 case LyXRC::RC_CHECKLASTFILES:
1856 case LyXRC::RC_CHKTEX_COMMAND:
1857 case LyXRC::RC_CONVERTER:
1858 case LyXRC::RC_COPIER:
1859 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1860 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1861 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1862 case LyXRC::RC_CYGWIN_PATH_FIX:
1863 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1864 namespace os = lyx::support::os;
1865 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1867 case LyXRC::RC_DATE_INSERT_FORMAT:
1868 case LyXRC::RC_DEFAULT_LANGUAGE:
1869 case LyXRC::RC_DEFAULT_PAPERSIZE:
1870 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1871 case LyXRC::RC_DISPLAY_GRAPHICS:
1872 case LyXRC::RC_DOCUMENTPATH:
1873 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1874 if (fs::exists(lyxrc_new.document_path) &&
1875 fs::is_directory(lyxrc_new.document_path)) {
1876 using lyx::support::package;
1877 package().document_dir() = lyxrc.document_path;
1880 case LyXRC::RC_ESC_CHARS:
1881 case LyXRC::RC_FONT_ENCODING:
1882 case LyXRC::RC_FORMAT:
1883 case LyXRC::RC_INDEX_COMMAND:
1884 case LyXRC::RC_INPUT:
1885 case LyXRC::RC_KBMAP:
1886 case LyXRC::RC_KBMAP_PRIMARY:
1887 case LyXRC::RC_KBMAP_SECONDARY:
1888 case LyXRC::RC_LABEL_INIT_LENGTH:
1889 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1890 case LyXRC::RC_LANGUAGE_AUTO_END:
1891 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1892 case LyXRC::RC_LANGUAGE_COMMAND_END:
1893 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1894 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1895 case LyXRC::RC_LANGUAGE_PACKAGE:
1896 case LyXRC::RC_LANGUAGE_USE_BABEL:
1897 case LyXRC::RC_LASTFILES:
1898 case LyXRC::RC_MAKE_BACKUP:
1899 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1900 case LyXRC::RC_NUMLASTFILES:
1901 case LyXRC::RC_PATH_PREFIX:
1902 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1903 using lyx::support::prependEnvPath;
1904 prependEnvPath("PATH", lyxrc.path_prefix);
1906 case LyXRC::RC_PERS_DICT:
1907 case LyXRC::RC_POPUP_BOLD_FONT:
1908 case LyXRC::RC_POPUP_FONT_ENCODING:
1909 case LyXRC::RC_POPUP_NORMAL_FONT:
1910 case LyXRC::RC_PREVIEW:
1911 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1912 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1913 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1914 case LyXRC::RC_PRINTCOPIESFLAG:
1915 case LyXRC::RC_PRINTER:
1916 case LyXRC::RC_PRINTEVENPAGEFLAG:
1917 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1918 case LyXRC::RC_PRINTFILEEXTENSION:
1919 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1920 case LyXRC::RC_PRINTODDPAGEFLAG:
1921 case LyXRC::RC_PRINTPAGERANGEFLAG:
1922 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1923 case LyXRC::RC_PRINTPAPERFLAG:
1924 case LyXRC::RC_PRINTREVERSEFLAG:
1925 case LyXRC::RC_PRINTSPOOL_COMMAND:
1926 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1927 case LyXRC::RC_PRINTTOFILE:
1928 case LyXRC::RC_PRINTTOPRINTER:
1929 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1930 case LyXRC::RC_PRINT_COMMAND:
1931 case LyXRC::RC_RTL_SUPPORT:
1932 case LyXRC::RC_SCREEN_DPI:
1933 case LyXRC::RC_SCREEN_FONT_ENCODING:
1934 case LyXRC::RC_SCREEN_FONT_ROMAN:
1935 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1936 case LyXRC::RC_SCREEN_FONT_SANS:
1937 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1938 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1939 case LyXRC::RC_SCREEN_FONT_SIZES:
1940 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1941 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1942 case LyXRC::RC_SCREEN_ZOOM:
1943 case LyXRC::RC_SERVERPIPE:
1944 case LyXRC::RC_SET_COLOR:
1945 case LyXRC::RC_SHOW_BANNER:
1946 case LyXRC::RC_SPELL_COMMAND:
1947 case LyXRC::RC_TEMPDIRPATH:
1948 case LyXRC::RC_TEMPLATEPATH:
1949 case LyXRC::RC_UIFILE:
1950 case LyXRC::RC_USER_EMAIL:
1951 case LyXRC::RC_USER_NAME:
1952 case LyXRC::RC_USETEMPDIR:
1953 case LyXRC::RC_USE_ALT_LANG:
1954 case LyXRC::RC_USE_ESC_CHARS:
1955 case LyXRC::RC_USE_INP_ENC:
1956 case LyXRC::RC_USE_PERS_DICT:
1957 case LyXRC::RC_USE_SPELL_LIB:
1958 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1959 case LyXRC::RC_VIEWER:
1960 case LyXRC::RC_WHEEL_JUMP:
1961 case LyXRC::RC_LAST: