3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetnote.h"
68 #include "insets/insettabular.h"
69 #include "insets/insetvspace.h"
70 #include "insets/insetwrap.h"
72 #include "frontends/Alert.h"
73 #include "frontends/Dialogs.h"
74 #include "frontends/FileDialog.h"
75 #include "frontends/lyx_gui.h"
76 #include "frontends/LyXKeySym.h"
77 #include "frontends/LyXView.h"
78 #include "frontends/Menubar.h"
79 #include "frontends/Toolbars.h"
81 #include "support/environment.h"
82 #include "support/filefilterlist.h"
83 #include "support/filetools.h"
84 #include "support/forkedcontr.h"
85 #include "support/fs_extras.h"
86 #include "support/lstrings.h"
87 #include "support/path.h"
88 #include "support/package.h"
89 #include "support/systemcall.h"
90 #include "support/convert.h"
91 #include "support/os.h"
93 #include <boost/current_function.hpp>
94 #include <boost/filesystem/operations.hpp>
98 using bv_funcs::freefont2string;
100 using lyx::support::AbsolutePath;
101 using lyx::support::AddName;
102 using lyx::support::AddPath;
103 using lyx::support::bformat;
104 using lyx::support::ChangeExtension;
105 using lyx::support::contains;
106 using lyx::support::FileFilterList;
107 using lyx::support::FileSearch;
108 using lyx::support::ForkedcallsController;
109 using lyx::support::i18nLibFileSearch;
110 using lyx::support::IsDirWriteable;
111 using lyx::support::IsFileReadable;
112 using lyx::support::isStrInt;
113 using lyx::support::MakeAbsPath;
114 using lyx::support::MakeDisplayPath;
115 using lyx::support::package;
116 using lyx::support::Path;
117 using lyx::support::QuoteName;
118 using lyx::support::rtrim;
119 using lyx::support::split;
120 using lyx::support::subst;
121 using lyx::support::Systemcall;
122 using lyx::support::token;
123 using lyx::support::trim;
124 using lyx::support::prefixIs;
127 using std::make_pair;
130 using std::istringstream;
132 namespace biblio = lyx::biblio;
133 namespace fs = boost::filesystem;
136 extern BufferList bufferlist;
137 extern LyXServer * lyxserver;
139 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
142 extern tex_accent_struct get_accent(kb_action action);
147 bool getStatus(LCursor cursor,
148 FuncRequest const & cmd, FuncStatus & status)
150 // Try to fix cursor in case it is broken.
151 cursor.fixIfBroken();
153 // This is, of course, a mess. Better create a new doc iterator and use
154 // this in Inset::getStatus. This might require an additional
155 // BufferView * arg, though (which should be avoided)
156 //LCursor safe = *this;
158 for ( ; cursor.depth(); cursor.pop()) {
159 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
160 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
161 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
162 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
164 // The inset's getStatus() will return 'true' if it made
165 // a definitive decision on whether it want to handle the
166 // request or not. The result of this decision is put into
167 // the 'status' parameter.
168 if (cursor.inset().getStatus(cursor, cmd, status)) {
178 LyXFunc::LyXFunc(LyXView * lv)
181 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
182 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
183 meta_fake_bit(key_modifier::none)
188 void LyXFunc::handleKeyFunc(kb_action action)
190 char c = encoded_last_key;
192 if (keyseq.length()) {
196 owner->getIntl().getTransManager()
197 .deadkey(c, get_accent(action).accent, view()->getLyXText());
198 // Need to clear, in case the minibuffer calls these
201 // copied verbatim from do_accent_char
202 view()->cursor().resetAnchor();
207 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
209 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
211 // Do nothing if we have nothing (JMarc)
212 if (!keysym->isOK()) {
213 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
218 if (keysym->isModifier()) {
219 lyxerr[Debug::KEY] << "isModifier true" << endl;
223 Encoding const * encoding = view()->cursor().getEncoding();
225 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
227 // Do a one-deep top-level lookup for
228 // cancel and meta-fake keys. RVDK_PATCH_5
229 cancel_meta_seq.reset();
231 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
232 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
233 << " action first set to [" << func.action << ']'
236 // When not cancel or meta-fake, do the normal lookup.
237 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
238 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
239 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
240 // remove Caps Lock and Mod2 as a modifiers
241 func = keyseq.addkey(keysym, (state | meta_fake_bit));
242 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
243 << "action now set to ["
244 << func.action << ']' << endl;
247 // Dont remove this unless you know what you are doing.
248 meta_fake_bit = key_modifier::none;
250 // Can this happen now ?
251 if (func.action == LFUN_NOACTION) {
252 func = FuncRequest(LFUN_PREFIX);
255 if (lyxerr.debugging(Debug::KEY)) {
256 lyxerr << BOOST_CURRENT_FUNCTION
258 << func.action << "]["
259 << keyseq.print() << ']'
263 // already here we know if it any point in going further
264 // why not return already here if action == -1 and
265 // num_bytes == 0? (Lgb)
267 if (keyseq.length() > 1) {
268 owner->message(keyseq.print());
272 // Maybe user can only reach the key via holding down shift.
273 // Let's see. But only if shift is the only modifier
274 if (func.action == LFUN_UNKNOWN_ACTION &&
275 state == key_modifier::shift) {
276 lyxerr[Debug::KEY] << "Trying without shift" << endl;
277 func = keyseq.addkey(keysym, key_modifier::none);
278 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
281 if (func.action == LFUN_UNKNOWN_ACTION) {
282 // Hmm, we didn't match any of the keysequences. See
283 // if it's normal insertable text not already covered
285 if (keysym->isText() && keyseq.length() == 1) {
286 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
287 func = FuncRequest(LFUN_SELFINSERT);
289 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
290 owner->message(_("Unknown function."));
295 if (func.action == LFUN_SELFINSERT) {
296 if (encoded_last_key != 0) {
297 string const arg(1, encoded_last_key);
298 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
300 << "SelfInsert arg[`" << arg << "']" << endl;
308 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
310 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
312 LCursor & cur = view()->cursor();
314 /* In LyX/Mac, when a dialog is open, the menus of the
315 application can still be accessed without giving focus to
316 the main window. In this case, we want to disable the menu
317 entries that are buffer-related.
320 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
323 buf = owner->buffer();
325 if (cmd.action == LFUN_NOACTION) {
326 flag.message(N_("Nothing to do"));
331 switch (cmd.action) {
332 case LFUN_UNKNOWN_ACTION:
333 #ifndef HAVE_LIBAIKSAURUS
334 case LFUN_THESAURUS_ENTRY:
340 flag |= lyx_gui::getStatus(cmd);
343 if (flag.unknown()) {
344 flag.message(N_("Unknown action"));
348 if (!flag.enabled()) {
349 if (flag.message().empty())
350 flag.message(N_("Command disabled"));
354 // Check whether we need a buffer
355 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
357 flag.message(N_("Command not allowed with"
358 "out any document open"));
363 // I would really like to avoid having this switch and rather try to
364 // encode this in the function itself.
365 // -- And I'd rather let an inset decide which LFUNs it is willing
366 // to handle (Andre')
368 switch (cmd.action) {
369 case LFUN_TOOLTIPS_TOGGLE:
370 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
373 case LFUN_READ_ONLY_TOGGLE:
374 flag.setOnOff(buf->isReadonly());
377 case LFUN_SWITCHBUFFER:
378 // toggle on the current buffer, but do not toggle off
379 // the other ones (is that a good idea?)
380 if (cmd.argument == buf->fileName())
385 enable = cmd.argument == "custom"
386 || Exporter::IsExportable(*buf, cmd.argument);
390 enable = cur.selection();
394 enable = buf->isLatex() && lyxrc.chktex_command != "none";
398 enable = Exporter::IsExportable(*buf, "program");
401 case LFUN_LAYOUT_TABULAR:
402 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
406 case LFUN_LAYOUT_PARAGRAPH:
407 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
410 case LFUN_VC_REGISTER:
411 enable = !buf->lyxvc().inUse();
413 case LFUN_VC_CHECKIN:
414 enable = buf->lyxvc().inUse() && !buf->isReadonly();
416 case LFUN_VC_CHECKOUT:
417 enable = buf->lyxvc().inUse() && buf->isReadonly();
421 enable = buf->lyxvc().inUse();
423 case LFUN_MENURELOAD:
424 enable = !buf->isUnnamed() && !buf->isClean();
427 case LFUN_INSET_SETTINGS: {
431 UpdatableInset * inset = cur.inset().asUpdatableInset();
432 lyxerr << "inset: " << inset << endl;
436 InsetBase::Code code = inset->lyxCode();
438 case InsetBase::TABULAR_CODE:
439 enable = cmd.argument == "tabular";
441 case InsetBase::ERT_CODE:
442 enable = cmd.argument == "ert";
444 case InsetBase::FLOAT_CODE:
445 enable = cmd.argument == "float";
447 case InsetBase::WRAP_CODE:
448 enable = cmd.argument == "wrap";
450 case InsetBase::NOTE_CODE:
451 enable = cmd.argument == "note";
453 case InsetBase::BRANCH_CODE:
454 enable = cmd.argument == "branch";
456 case InsetBase::BOX_CODE:
457 enable = cmd.argument == "box";
465 case LFUN_INSET_APPLY: {
466 string const name = cmd.getArg(0);
467 InsetBase * inset = owner->getDialogs().getOpenInset(name);
469 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
471 bool const success = inset->getStatus(cur, fr, fs);
472 // Every inset is supposed to handle this
473 BOOST_ASSERT(success);
476 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
477 flag |= getStatus(fr);
479 enable = flag.enabled();
483 case LFUN_DIALOG_SHOW: {
484 string const name = cmd.getArg(0);
486 enable = name == "aboutlyx"
490 || name == "texinfo";
491 else if (name == "print")
492 enable = Exporter::IsExportable(*buf, "dvi")
493 && lyxrc.print_command != "none";
494 else if (name == "character" || name == "mathpanel")
495 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
496 else if (name == "latexlog")
497 enable = IsFileReadable(buf->getLogName().second);
498 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
499 else if (name == "spellchecker")
502 else if (name == "vclog")
503 enable = buf->lyxvc().inUse();
507 case LFUN_DIALOG_SHOW_NEW_INSET:
508 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
511 case LFUN_DIALOG_UPDATE: {
512 string const name = cmd.getArg(0);
514 enable = name == "prefs";
518 // this one is difficult to get right. As a half-baked
519 // solution, we consider only the first action of the sequence
520 case LFUN_SEQUENCE: {
521 // argument contains ';'-terminated commands
522 string const firstcmd = token(cmd.argument, ';', 0);
523 FuncRequest func(lyxaction.lookupFunc(firstcmd));
524 func.origin = cmd.origin;
525 flag = getStatus(func);
529 case LFUN_MENUNEWTMPLT:
530 case LFUN_WORDFINDFORWARD:
531 case LFUN_WORDFINDBACKWARD:
533 case LFUN_EXEC_COMMAND:
536 case LFUN_CLOSEBUFFER:
545 case LFUN_RECONFIGURE:
549 case LFUN_DROP_LAYOUTS_CHOICE:
550 case LFUN_MENU_OPEN_BY_NAME:
553 case LFUN_GOTOFILEROW:
554 case LFUN_DIALOG_SHOW_NEXT_INSET:
555 case LFUN_DIALOG_HIDE:
556 case LFUN_DIALOG_DISCONNECT_INSET:
558 case LFUN_TOGGLECURSORFOLLOW:
562 case LFUN_KMAP_TOGGLE:
564 case LFUN_EXPORT_CUSTOM:
566 case LFUN_SAVEPREFERENCES:
567 case LFUN_SCREEN_FONT_UPDATE:
570 case LFUN_EXTERNAL_EDIT:
571 case LFUN_GRAPHICS_EDIT:
572 case LFUN_ALL_INSETS_TOGGLE:
573 case LFUN_LANGUAGE_BUFFER:
574 case LFUN_TEXTCLASS_APPLY:
575 case LFUN_TEXTCLASS_LOAD:
576 case LFUN_SAVE_AS_DEFAULT:
577 case LFUN_BUFFERPARAMS_APPLY:
578 case LFUN_LYXRC_APPLY:
579 case LFUN_NEXTBUFFER:
580 case LFUN_PREVIOUSBUFFER:
581 // these are handled in our dispatch()
586 if (!::getStatus(cur, cmd, flag))
587 flag = view()->getStatus(cmd);
593 // Can we use a readonly buffer?
594 if (buf && buf->isReadonly()
595 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
596 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
597 flag.message(N_("Document is read-only"));
601 // the default error message if we disable the command
602 if (!flag.enabled() && flag.message().empty())
603 flag.message(N_("Command disabled"));
611 bool ensureBufferClean(BufferView * bv)
613 Buffer & buf = *bv->buffer();
617 string const file = MakeDisplayPath(buf.fileName(), 30);
618 string text = bformat(_("The document %1$s has unsaved "
619 "changes.\n\nDo you want to save "
620 "the document?"), file);
621 int const ret = Alert::prompt(_("Save changed document?"),
622 text, 0, 1, _("&Save"),
626 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
628 return buf.isClean();
632 void showPrintError(string const & name)
634 string str = bformat(_("Could not print the document %1$s.\n"
635 "Check that your printer is set up correctly."),
636 MakeDisplayPath(name, 50));
637 Alert::error(_("Print document failed"), str);
641 void loadTextclass(string const & name)
643 std::pair<bool, lyx::textclass_type> const tc_pair =
644 textclasslist.NumberOfClass(name);
646 if (!tc_pair.first) {
647 lyxerr << "Document class \"" << name
648 << "\" does not exist."
653 lyx::textclass_type const tc = tc_pair.second;
655 if (!textclasslist[tc].load()) {
656 string s = bformat(_("The document could not be converted\n"
657 "into the document class %1$s."),
658 textclasslist[tc].name());
659 Alert::error(_("Could not change class"), s);
664 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
669 void LyXFunc::dispatch(FuncRequest const & cmd)
671 BOOST_ASSERT(view());
672 string const argument = cmd.argument;
673 kb_action const action = cmd.action;
675 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
676 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
678 // we have not done anything wrong yet.
680 dispatch_buffer.erase();
684 FuncStatus const flag = getStatus(cmd);
685 if (!flag.enabled()) {
686 // We cannot use this function here
687 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
688 << lyxaction.getActionName(action)
689 << " [" << action << "] is disabled at this location"
691 setErrorMessage(flag.message());
694 if (view()->available())
695 view()->hideCursor();
699 case LFUN_WORDFINDFORWARD:
700 case LFUN_WORDFINDBACKWARD: {
701 static string last_search;
702 string searched_string;
704 if (!argument.empty()) {
705 last_search = argument;
706 searched_string = argument;
708 searched_string = last_search;
711 if (searched_string.empty())
714 bool const fw = action == LFUN_WORDFINDFORWARD;
716 lyx::find::find2string(searched_string, true, false, fw);
717 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
722 owner->message(keyseq.printOptions());
725 case LFUN_EXEC_COMMAND:
726 owner->getToolbars().display("minibuffer", true);
727 owner->focus_command_buffer();
732 meta_fake_bit = key_modifier::none;
733 if (view()->available())
734 // cancel any selection
735 dispatch(FuncRequest(LFUN_MARK_OFF));
736 setMessage(N_("Cancel"));
740 meta_fake_bit = key_modifier::alt;
741 setMessage(keyseq.print());
744 case LFUN_READ_ONLY_TOGGLE:
745 if (owner->buffer()->lyxvc().inUse())
746 owner->buffer()->lyxvc().toggleReadOnly();
748 owner->buffer()->setReadonly(
749 !owner->buffer()->isReadonly());
752 // --- Menus -----------------------------------------------
754 menuNew(argument, false);
757 case LFUN_MENUNEWTMPLT:
758 menuNew(argument, true);
761 case LFUN_CLOSEBUFFER:
766 if (!owner->buffer()->isUnnamed()) {
767 string const str = bformat(_("Saving document %1$s..."),
768 MakeDisplayPath(owner->buffer()->fileName()));
770 MenuWrite(owner->buffer());
771 owner->message(str + _(" done."));
773 WriteAs(owner->buffer());
777 WriteAs(owner->buffer(), argument);
780 case LFUN_MENURELOAD: {
781 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
782 string text = bformat(_("Any changes will be lost. Are you sure "
783 "you want to revert to the saved version of the document %1$s?"), file);
784 int const ret = Alert::prompt(_("Revert to saved document?"),
785 text, 0, 1, _("&Revert"), _("&Cancel"));
793 Exporter::Export(owner->buffer(), argument, true);
794 view()->showErrorList(BufferFormat(*owner->buffer()));
798 Exporter::Preview(owner->buffer(), argument);
799 view()->showErrorList(BufferFormat(*owner->buffer()));
803 Exporter::Export(owner->buffer(), "program", true);
804 view()->showErrorList(_("Build"));
808 owner->buffer()->runChktex();
809 view()->showErrorList(_("ChkTeX"));
813 if (argument == "custom")
814 owner->getDialogs().show("sendto");
816 Exporter::Export(owner->buffer(), argument, false);
817 view()->showErrorList(BufferFormat(*owner->buffer()));
821 case LFUN_EXPORT_CUSTOM: {
823 string command = split(argument, format_name, ' ');
824 Format const * format = formats.getFormat(format_name);
826 lyxerr << "Format \"" << format_name
827 << "\" not recognized!"
832 Buffer * buffer = owner->buffer();
834 // The name of the file created by the conversion process
837 // Output to filename
838 if (format->name() == "lyx") {
839 string const latexname =
840 buffer->getLatexName(false);
841 filename = ChangeExtension(latexname,
842 format->extension());
843 filename = AddName(buffer->temppath(), filename);
845 if (!buffer->writeFile(filename))
849 Exporter::Export(buffer, format_name, true,
853 // Substitute $$FName for filename
854 if (!contains(command, "$$FName"))
855 command = "( " + command + " ) < $$FName";
856 command = subst(command, "$$FName", filename);
858 // Execute the command in the background
860 call.startscript(Systemcall::DontWait, command);
867 string command = split(split(argument, target, ' '),
871 || target_name.empty()
872 || command.empty()) {
873 lyxerr << "Unable to parse \""
874 << argument << '"' << std::endl;
877 if (target != "printer" && target != "file") {
878 lyxerr << "Unrecognized target \""
879 << target << '"' << std::endl;
883 Buffer * buffer = owner->buffer();
885 if (!Exporter::Export(buffer, "dvi", true)) {
886 showPrintError(buffer->fileName());
890 // Push directory path.
891 string const path = buffer->temppath();
894 // there are three cases here:
895 // 1. we print to a file
896 // 2. we print directly to a printer
897 // 3. we print using a spool command (print to file first)
900 string const dviname =
901 ChangeExtension(buffer->getLatexName(true),
904 if (target == "printer") {
905 if (!lyxrc.print_spool_command.empty()) {
906 // case 3: print using a spool
907 string const psname =
908 ChangeExtension(dviname,".ps");
909 command += lyxrc.print_to_file
912 + QuoteName(dviname);
915 lyxrc.print_spool_command +' ';
916 if (target_name != "default") {
917 command2 += lyxrc.print_spool_printerprefix
921 command2 += QuoteName(psname);
923 // If successful, then spool command
924 res = one.startscript(
929 res = one.startscript(
930 Systemcall::DontWait,
933 // case 2: print directly to a printer
934 res = one.startscript(
935 Systemcall::DontWait,
936 command + QuoteName(dviname));
940 // case 1: print to a file
941 command += lyxrc.print_to_file
942 + QuoteName(MakeAbsPath(target_name,
945 + QuoteName(dviname);
946 res = one.startscript(Systemcall::DontWait,
951 showPrintError(buffer->fileName());
964 InsetCommandParams p("tableofcontents");
965 string const data = InsetCommandMailer::params2string("toc", p);
966 owner->getDialogs().show("toc", data, 0);
974 case LFUN_RECONFIGURE:
978 case LFUN_HELP_OPEN: {
979 string const arg = argument;
981 setErrorMessage(N_("Missing argument"));
984 string const fname = i18nLibFileSearch("doc", arg, "lyx");
986 lyxerr << "LyX: unable to find documentation file `"
987 << arg << "'. Bad installation?" << endl;
990 owner->message(bformat(_("Opening help file %1$s..."),
991 MakeDisplayPath(fname)));
992 view()->loadLyXFile(fname, false);
996 // --- version control -------------------------------
997 case LFUN_VC_REGISTER:
998 if (!ensureBufferClean(view()))
1000 if (!owner->buffer()->lyxvc().inUse()) {
1001 owner->buffer()->lyxvc().registrer();
1006 case LFUN_VC_CHECKIN:
1007 if (!ensureBufferClean(view()))
1009 if (owner->buffer()->lyxvc().inUse()
1010 && !owner->buffer()->isReadonly()) {
1011 owner->buffer()->lyxvc().checkIn();
1016 case LFUN_VC_CHECKOUT:
1017 if (!ensureBufferClean(view()))
1019 if (owner->buffer()->lyxvc().inUse()
1020 && owner->buffer()->isReadonly()) {
1021 owner->buffer()->lyxvc().checkOut();
1026 case LFUN_VC_REVERT:
1027 owner->buffer()->lyxvc().revert();
1032 owner->buffer()->lyxvc().undoLast();
1036 // --- buffers ----------------------------------------
1037 case LFUN_SWITCHBUFFER:
1038 view()->setBuffer(bufferlist.getBuffer(argument));
1041 case LFUN_NEXTBUFFER:
1042 view()->setBuffer(bufferlist.next(view()->buffer()));
1045 case LFUN_PREVIOUSBUFFER:
1046 view()->setBuffer(bufferlist.previous(view()->buffer()));
1050 NewFile(view(), argument);
1053 case LFUN_FILE_OPEN:
1057 case LFUN_DROP_LAYOUTS_CHOICE:
1058 owner->getToolbars().openLayoutList();
1061 case LFUN_MENU_OPEN_BY_NAME:
1062 owner->getMenubar().openByName(argument);
1065 // --- lyxserver commands ----------------------------
1067 setMessage(owner->buffer()->fileName());
1068 lyxerr[Debug::INFO] << "FNAME["
1069 << owner->buffer()->fileName()
1074 dispatch_buffer = keyseq.print();
1075 lyxserver->notifyClient(dispatch_buffer);
1078 case LFUN_GOTOFILEROW: {
1081 istringstream is(argument);
1082 is >> file_name >> row;
1083 if (prefixIs(file_name, package().temp_dir())) {
1084 // Needed by inverse dvi search. If it is a file
1085 // in tmpdir, call the apropriated function
1086 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1088 // Must replace extension of the file to be .lyx
1089 // and get full path
1090 string const s = ChangeExtension(file_name, ".lyx");
1091 // Either change buffer or load the file
1092 if (bufferlist.exists(s)) {
1093 view()->setBuffer(bufferlist.getBuffer(s));
1095 view()->loadLyXFile(s);
1099 view()->setCursorFromRow(row);
1102 // see BufferView_pimpl::center()
1103 view()->updateScrollbar();
1107 case LFUN_DIALOG_SHOW: {
1108 string const name = cmd.getArg(0);
1109 string data = trim(cmd.argument.substr(name.size()));
1111 if (name == "character") {
1112 data = freefont2string();
1114 owner->getDialogs().show("character", data);
1117 else if (name == "latexlog") {
1118 pair<Buffer::LogType, string> const logfile =
1119 owner->buffer()->getLogName();
1120 switch (logfile.first) {
1121 case Buffer::latexlog:
1124 case Buffer::buildlog:
1128 data += logfile.second;
1129 owner->getDialogs().show("log", data);
1131 else if (name == "vclog") {
1132 string const data = "vc " +
1133 owner->buffer()->lyxvc().getLogFile();
1134 owner->getDialogs().show("log", data);
1137 owner->getDialogs().show(name, data);
1141 case LFUN_DIALOG_SHOW_NEW_INSET: {
1142 string const name = cmd.getArg(0);
1143 string data = trim(cmd.argument.substr(name.size()));
1144 if (name == "bibitem" ||
1146 name == "include" ||
1152 InsetCommandParams p(name);
1153 data = InsetCommandMailer::params2string(name, p);
1154 } else if (name == "box") {
1155 // \c data == "Boxed" || "Frameless" etc
1156 InsetBoxParams p(data);
1157 data = InsetBoxMailer::params2string(p);
1158 } else if (name == "branch") {
1159 InsetBranchParams p;
1160 data = InsetBranchMailer::params2string(p);
1161 } else if (name == "citation") {
1162 InsetCommandParams p("cite");
1163 data = InsetCommandMailer::params2string(name, p);
1164 } else if (name == "ert") {
1165 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1166 } else if (name == "external") {
1167 InsetExternalParams p;
1168 Buffer const & buffer = *owner->buffer();
1169 data = InsetExternalMailer::params2string(p, buffer);
1170 } else if (name == "float") {
1172 data = InsetFloatMailer::params2string(p);
1173 } else if (name == "graphics") {
1174 InsetGraphicsParams p;
1175 Buffer const & buffer = *owner->buffer();
1176 data = InsetGraphicsMailer::params2string(p, buffer);
1177 } else if (name == "note") {
1179 data = InsetNoteMailer::params2string(p);
1180 } else if (name == "vspace") {
1182 data = InsetVSpaceMailer::params2string(space);
1183 } else if (name == "wrap") {
1185 data = InsetWrapMailer::params2string(p);
1187 owner->getDialogs().show(name, data, 0);
1191 case LFUN_DIALOG_SHOW_NEXT_INSET:
1194 case LFUN_DIALOG_UPDATE: {
1195 string const & name = argument;
1196 // Can only update a dialog connected to an existing inset
1197 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1199 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1200 inset->dispatch(view()->cursor(), fr);
1201 } else if (name == "paragraph") {
1202 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1203 } else if (name == "prefs") {
1204 owner->getDialogs().update(name, string());
1209 case LFUN_DIALOG_HIDE:
1210 Dialogs::hide(argument, 0);
1213 case LFUN_DIALOG_DISCONNECT_INSET:
1214 owner->getDialogs().disconnect(argument);
1217 case LFUN_CHILDOPEN: {
1218 string const filename =
1219 MakeAbsPath(argument, owner->buffer()->filePath());
1220 setMessage(N_("Opening child document ") +
1221 MakeDisplayPath(filename) + "...");
1222 view()->savePosition(0);
1223 string const parentfilename = owner->buffer()->fileName();
1224 if (bufferlist.exists(filename))
1225 view()->setBuffer(bufferlist.getBuffer(filename));
1227 view()->loadLyXFile(filename);
1228 // Set the parent name of the child document.
1229 // This makes insertion of citations and references in the child work,
1230 // when the target is in the parent or another child document.
1231 owner->buffer()->setParentName(parentfilename);
1235 case LFUN_TOGGLECURSORFOLLOW:
1236 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1240 owner->getIntl().KeyMapOn(false);
1243 case LFUN_KMAP_PRIM:
1244 owner->getIntl().KeyMapPrim();
1248 owner->getIntl().KeyMapSec();
1251 case LFUN_KMAP_TOGGLE:
1252 owner->getIntl().ToggleKeyMap();
1258 string rest = split(argument, countstr, ' ');
1259 istringstream is(countstr);
1262 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1263 for (int i = 0; i < count; ++i)
1264 dispatch(lyxaction.lookupFunc(rest));
1268 case LFUN_SEQUENCE: {
1269 // argument contains ';'-terminated commands
1270 string arg = argument;
1271 while (!arg.empty()) {
1273 arg = split(arg, first, ';');
1274 FuncRequest func(lyxaction.lookupFunc(first));
1275 func.origin = cmd.origin;
1281 case LFUN_SAVEPREFERENCES: {
1282 Path p(package().user_support());
1283 lyxrc.write("preferences", false);
1287 case LFUN_SCREEN_FONT_UPDATE:
1288 // handle the screen font changes.
1289 lyxrc.set_font_norm_type();
1290 lyx_gui::update_fonts();
1291 // All visible buffers will need resize
1295 case LFUN_SET_COLOR: {
1297 string const x11_name = split(argument, lyx_name, ' ');
1298 if (lyx_name.empty() || x11_name.empty()) {
1299 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1304 bool const graphicsbg_changed =
1305 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1306 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1308 if (!lcolor.setColor(lyx_name, x11_name)) {
1310 bformat(_("Set-color \"%1$s\" failed "
1311 "- color is undefined or "
1312 "may not be redefined"), lyx_name));
1316 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1318 if (graphicsbg_changed) {
1319 #ifdef WITH_WARNINGS
1320 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1323 lyx::graphics::GCache::get().changeDisplay(true);
1330 owner->message(argument);
1333 case LFUN_TOOLTIPS_TOGGLE:
1334 owner->getDialogs().toggleTooltips();
1337 case LFUN_EXTERNAL_EDIT: {
1338 FuncRequest fr(action, argument);
1339 InsetExternal().dispatch(view()->cursor(), fr);
1343 case LFUN_GRAPHICS_EDIT: {
1344 FuncRequest fr(action, argument);
1345 InsetGraphics().dispatch(view()->cursor(), fr);
1349 case LFUN_INSET_APPLY: {
1350 string const name = cmd.getArg(0);
1351 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1353 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1354 inset->dispatch(view()->cursor(), fr);
1356 FuncRequest fr(LFUN_INSET_INSERT, argument);
1359 // ideally, the update flag should be set by the insets,
1360 // but this is not possible currently
1365 case LFUN_ALL_INSETS_TOGGLE: {
1367 string const name = split(argument, action, ' ');
1368 InsetBase::Code const inset_code =
1369 InsetBase::translate(name);
1371 LCursor & cur = view()->cursor();
1372 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1374 InsetBase & inset = owner->buffer()->inset();
1375 InsetIterator it = inset_iterator_begin(inset);
1376 InsetIterator const end = inset_iterator_end(inset);
1377 for (; it != end; ++it) {
1378 if (inset_code == InsetBase::NO_CODE
1379 || inset_code == it->lyxCode())
1380 it->dispatch(cur, fr);
1385 case LFUN_LANGUAGE_BUFFER: {
1386 Buffer & buffer = *owner->buffer();
1387 Language const * oldL = buffer.params().language;
1388 Language const * newL = languages.getLanguage(argument);
1389 if (!newL || oldL == newL)
1392 if (oldL->RightToLeft() == newL->RightToLeft()
1393 && !buffer.isMultiLingual())
1394 buffer.changeLanguage(oldL, newL);
1396 buffer.updateDocLang(newL);
1400 case LFUN_SAVE_AS_DEFAULT: {
1401 string const fname =
1402 AddName(AddPath(package().user_support(), "templates/"),
1404 Buffer defaults(fname);
1406 istringstream ss(argument);
1409 int const unknown_tokens = defaults.readHeader(lex);
1411 if (unknown_tokens != 0) {
1412 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1413 << unknown_tokens << " unknown token"
1414 << (unknown_tokens == 1 ? "" : "s")
1418 if (defaults.writeFile(defaults.fileName()))
1419 setMessage(_("Document defaults saved in ")
1420 + MakeDisplayPath(fname));
1422 setErrorMessage(_("Unable to save document defaults"));
1426 case LFUN_BUFFERPARAMS_APPLY: {
1427 biblio::CiteEngine const engine =
1428 owner->buffer()->params().cite_engine;
1430 istringstream ss(argument);
1433 int const unknown_tokens =
1434 owner->buffer()->readHeader(lex);
1436 if (unknown_tokens != 0) {
1437 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1438 << unknown_tokens << " unknown token"
1439 << (unknown_tokens == 1 ? "" : "s")
1442 if (engine == owner->buffer()->params().cite_engine)
1445 LCursor & cur = view()->cursor();
1446 FuncRequest fr(LFUN_INSET_REFRESH);
1448 InsetBase & inset = owner->buffer()->inset();
1449 InsetIterator it = inset_iterator_begin(inset);
1450 InsetIterator const end = inset_iterator_end(inset);
1451 for (; it != end; ++it)
1452 if (it->lyxCode() == InsetBase::CITE_CODE)
1453 it->dispatch(cur, fr);
1457 case LFUN_TEXTCLASS_APPLY: {
1458 recordUndoFullDocument(view());
1459 Buffer * buffer = owner->buffer();
1461 lyx::textclass_type const old_class =
1462 buffer->params().textclass;
1464 loadTextclass(argument);
1466 std::pair<bool, lyx::textclass_type> const tc_pair =
1467 textclasslist.NumberOfClass(argument);
1472 lyx::textclass_type const new_class = tc_pair.second;
1473 if (old_class == new_class)
1477 owner->message(_("Converting document to new document class..."));
1479 lyx::cap::SwitchBetweenClasses(
1480 old_class, new_class,
1481 buffer->paragraphs(), el);
1483 bufferErrors(*buffer, el);
1484 view()->showErrorList(_("Class switch"));
1485 updateCounters(*buffer);
1490 case LFUN_TEXTCLASS_LOAD:
1491 loadTextclass(argument);
1494 case LFUN_LYXRC_APPLY: {
1495 LyXRC const lyxrc_orig = lyxrc;
1497 istringstream ss(argument);
1498 bool const success = lyxrc.read(ss) == 0;
1501 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1502 << "Unable to read lyxrc data"
1507 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1512 view()->cursor().dispatch(cmd);
1513 update |= view()->cursor().result().update();
1514 if (!view()->cursor().result().dispatched())
1515 update |= view()->dispatch(cmd);
1520 if (view()->available()) {
1521 // Redraw screen unless explicitly told otherwise.
1522 // This also initializes the position cache for all insets
1523 // in (at least partially) visible top-level paragraphs.
1525 view()->update(Update::FitCursor | Update::Force);
1527 view()->update(Update::FitCursor);
1529 // if we executed a mutating lfun, mark the buffer as dirty
1530 // FIXME: Why not use flag.enabled() but call getStatus again?
1531 if (getStatus(cmd).enabled()
1532 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1533 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1534 view()->buffer()->markDirty();
1537 if (view()->cursor().inTexted()) {
1538 view()->owner()->updateLayoutChoice();
1541 sendDispatchMessage(_(getMessage()), cmd);
1545 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1547 owner->updateMenubar();
1548 owner->updateToolbars();
1550 const bool verbose = (cmd.origin == FuncRequest::UI
1551 || cmd.origin == FuncRequest::COMMANDBUFFER);
1553 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1554 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1556 owner->message(msg);
1560 string dispatch_msg = msg;
1561 if (!dispatch_msg.empty())
1562 dispatch_msg += ' ';
1564 string comname = lyxaction.getActionName(cmd.action);
1566 bool argsadded = false;
1568 if (!cmd.argument.empty()) {
1569 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1570 comname += ' ' + cmd.argument;
1575 string const shortcuts = toplevel_keymap->printbindings(cmd);
1577 if (!shortcuts.empty())
1578 comname += ": " + shortcuts;
1579 else if (!argsadded && !cmd.argument.empty())
1580 comname += ' ' + cmd.argument;
1582 if (!comname.empty()) {
1583 comname = rtrim(comname);
1584 dispatch_msg += '(' + rtrim(comname) + ')';
1587 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1588 if (!dispatch_msg.empty())
1589 owner->message(dispatch_msg);
1593 void LyXFunc::setupLocalKeymap()
1595 keyseq.stdmap = toplevel_keymap.get();
1596 keyseq.curmap = toplevel_keymap.get();
1597 cancel_meta_seq.stdmap = toplevel_keymap.get();
1598 cancel_meta_seq.curmap = toplevel_keymap.get();
1602 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1604 string initpath = lyxrc.document_path;
1605 string filename(name);
1607 if (view()->available()) {
1608 string const trypath = owner->buffer()->filePath();
1609 // If directory is writeable, use this as default.
1610 if (IsDirWriteable(trypath))
1614 static int newfile_number;
1616 if (filename.empty()) {
1617 filename = AddName(lyxrc.document_path,
1618 "newfile" + convert<string>(++newfile_number) + ".lyx");
1619 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1621 filename = AddName(lyxrc.document_path,
1622 "newfile" + convert<string>(newfile_number) +
1627 // The template stuff
1630 FileDialog fileDlg(_("Select template file"),
1631 LFUN_SELECT_FILE_SYNC,
1632 make_pair(string(_("Documents|#o#O")),
1633 string(lyxrc.document_path)),
1634 make_pair(string(_("Templates|#T#t")),
1635 string(lyxrc.template_path)));
1637 FileDialog::Result result =
1638 fileDlg.open(lyxrc.template_path,
1639 FileFilterList(_("LyX Documents (*.lyx)")),
1642 if (result.first == FileDialog::Later)
1644 if (result.second.empty())
1646 templname = result.second;
1649 view()->newFile(filename, templname, !name.empty());
1653 void LyXFunc::open(string const & fname)
1655 string initpath = lyxrc.document_path;
1657 if (view()->available()) {
1658 string const trypath = owner->buffer()->filePath();
1659 // If directory is writeable, use this as default.
1660 if (IsDirWriteable(trypath))
1666 if (fname.empty()) {
1667 FileDialog fileDlg(_("Select document to open"),
1669 make_pair(string(_("Documents|#o#O")),
1670 string(lyxrc.document_path)),
1671 make_pair(string(_("Examples|#E#e")),
1672 string(AddPath(package().system_support(), "examples"))));
1674 FileDialog::Result result =
1675 fileDlg.open(initpath,
1676 FileFilterList(_("LyX Documents (*.lyx)")),
1679 if (result.first == FileDialog::Later)
1682 filename = result.second;
1684 // check selected filename
1685 if (filename.empty()) {
1686 owner->message(_("Canceled."));
1692 // get absolute path of file and add ".lyx" to the filename if
1694 string const fullpath = FileSearch(string(), filename, "lyx");
1695 if (!fullpath.empty()) {
1696 filename = fullpath;
1699 string const disp_fn(MakeDisplayPath(filename));
1701 // if the file doesn't exist, let the user create one
1702 if (!fs::exists(filename)) {
1703 // the user specifically chose this name. Believe them.
1704 view()->newFile(filename, "", true);
1708 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1711 if (view()->loadLyXFile(filename)) {
1712 str2 = bformat(_("Document %1$s opened."), disp_fn);
1714 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1716 owner->message(str2);
1720 void LyXFunc::doImport(string const & argument)
1723 string filename = split(argument, format, ' ');
1725 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1726 << " file: " << filename << endl;
1728 // need user interaction
1729 if (filename.empty()) {
1730 string initpath = lyxrc.document_path;
1732 if (view()->available()) {
1733 string const trypath = owner->buffer()->filePath();
1734 // If directory is writeable, use this as default.
1735 if (IsDirWriteable(trypath))
1739 string const text = bformat(_("Select %1$s file to import"),
1740 formats.prettyName(format));
1742 FileDialog fileDlg(text,
1744 make_pair(string(_("Documents|#o#O")),
1745 string(lyxrc.document_path)),
1746 make_pair(string(_("Examples|#E#e")),
1747 string(AddPath(package().system_support(), "examples"))));
1749 string const filter = formats.prettyName(format)
1750 + " (*." + formats.extension(format) + ')';
1752 FileDialog::Result result =
1753 fileDlg.open(initpath,
1754 FileFilterList(filter),
1757 if (result.first == FileDialog::Later)
1760 filename = result.second;
1762 // check selected filename
1763 if (filename.empty())
1764 owner->message(_("Canceled."));
1767 if (filename.empty())
1770 // get absolute path of file
1771 filename = MakeAbsPath(filename);
1773 string const lyxfile = ChangeExtension(filename, ".lyx");
1775 // Check if the document already is open
1776 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1777 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1778 owner->message(_("Canceled."));
1783 // if the file exists already, and we didn't do
1784 // -i lyx thefile.lyx, warn
1785 if (fs::exists(lyxfile) && filename != lyxfile) {
1786 string const file = MakeDisplayPath(lyxfile, 30);
1788 string text = bformat(_("The document %1$s already exists.\n\n"
1789 "Do you want to over-write that document?"), file);
1790 int const ret = Alert::prompt(_("Over-write document?"),
1791 text, 0, 1, _("&Over-write"), _("&Cancel"));
1794 owner->message(_("Canceled."));
1799 Importer::Import(owner, filename, format);
1803 void LyXFunc::closeBuffer()
1805 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1806 if (bufferlist.empty()) {
1807 // need this otherwise SEGV may occur while
1808 // trying to set variables that don't exist
1809 // since there's no current buffer
1810 owner->getDialogs().hideBufferDependent();
1812 view()->setBuffer(bufferlist.first());
1818 // Each "owner" should have it's own message method. lyxview and
1819 // the minibuffer would use the minibuffer, but lyxserver would
1820 // send an ERROR signal to its client. Alejandro 970603
1821 // This function is bit problematic when it comes to NLS, to make the
1822 // lyx servers client be language indepenent we must not translate
1823 // strings sent to this func.
1824 void LyXFunc::setErrorMessage(string const & m) const
1826 dispatch_buffer = m;
1831 void LyXFunc::setMessage(string const & m) const
1833 dispatch_buffer = m;
1837 string const LyXFunc::viewStatusMessage()
1839 // When meta-fake key is pressed, show the key sequence so far + "M-".
1841 return keyseq.print() + "M-";
1843 // Else, when a non-complete key sequence is pressed,
1844 // show the available options.
1845 if (keyseq.length() > 0 && !keyseq.deleted())
1846 return keyseq.printOptions();
1848 if (!view()->available())
1849 return _("Welcome to LyX!");
1851 return view()->cursor().currentState();
1855 BufferView * LyXFunc::view() const
1857 BOOST_ASSERT(owner);
1858 return owner->view().get();
1862 bool LyXFunc::wasMetaKey() const
1864 return (meta_fake_bit != key_modifier::none);
1870 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1872 // Why the switch you might ask. It is a trick to ensure that all
1873 // the elements in the LyXRCTags enum is handled. As you can see
1874 // there are no breaks at all. So it is just a huge fall-through.
1875 // The nice thing is that we will get a warning from the compiler
1876 // if we forget an element.
1877 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1879 case LyXRC::RC_ACCEPT_COMPOUND:
1880 case LyXRC::RC_ALT_LANG:
1881 case LyXRC::RC_ASCIIROFF_COMMAND:
1882 case LyXRC::RC_ASCII_LINELEN:
1883 case LyXRC::RC_AUTOREGIONDELETE:
1884 case LyXRC::RC_AUTORESET_OPTIONS:
1885 case LyXRC::RC_AUTOSAVE:
1886 case LyXRC::RC_AUTO_NUMBER:
1887 case LyXRC::RC_BACKUPDIR_PATH:
1888 case LyXRC::RC_BIBTEX_COMMAND:
1889 case LyXRC::RC_BINDFILE:
1890 case LyXRC::RC_CHECKLASTFILES:
1891 case LyXRC::RC_CHKTEX_COMMAND:
1892 case LyXRC::RC_CONVERTER:
1893 case LyXRC::RC_COPIER:
1894 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1895 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1896 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1897 case LyXRC::RC_CYGWIN_PATH_FIX:
1898 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1899 namespace os = lyx::support::os;
1900 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1902 case LyXRC::RC_DATE_INSERT_FORMAT:
1903 case LyXRC::RC_DEFAULT_LANGUAGE:
1904 case LyXRC::RC_DEFAULT_PAPERSIZE:
1905 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1906 case LyXRC::RC_DISPLAY_GRAPHICS:
1907 case LyXRC::RC_DOCUMENTPATH:
1908 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1909 if (fs::exists(lyxrc_new.document_path) &&
1910 fs::is_directory(lyxrc_new.document_path)) {
1911 using lyx::support::package;
1912 package().document_dir() = lyxrc.document_path;
1915 case LyXRC::RC_ESC_CHARS:
1916 case LyXRC::RC_FONT_ENCODING:
1917 case LyXRC::RC_FORMAT:
1918 case LyXRC::RC_INDEX_COMMAND:
1919 case LyXRC::RC_INPUT:
1920 case LyXRC::RC_KBMAP:
1921 case LyXRC::RC_KBMAP_PRIMARY:
1922 case LyXRC::RC_KBMAP_SECONDARY:
1923 case LyXRC::RC_LABEL_INIT_LENGTH:
1924 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1925 case LyXRC::RC_LANGUAGE_AUTO_END:
1926 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1927 case LyXRC::RC_LANGUAGE_COMMAND_END:
1928 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1929 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1930 case LyXRC::RC_LANGUAGE_PACKAGE:
1931 case LyXRC::RC_LANGUAGE_USE_BABEL:
1932 case LyXRC::RC_LASTFILES:
1933 case LyXRC::RC_MAKE_BACKUP:
1934 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1935 case LyXRC::RC_NUMLASTFILES:
1936 case LyXRC::RC_PATH_PREFIX:
1937 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1938 using lyx::support::prependEnvPath;
1939 prependEnvPath("PATH", lyxrc.path_prefix);
1941 case LyXRC::RC_PERS_DICT:
1942 case LyXRC::RC_POPUP_BOLD_FONT:
1943 case LyXRC::RC_POPUP_FONT_ENCODING:
1944 case LyXRC::RC_POPUP_NORMAL_FONT:
1945 case LyXRC::RC_PREVIEW:
1946 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1947 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1948 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1949 case LyXRC::RC_PRINTCOPIESFLAG:
1950 case LyXRC::RC_PRINTER:
1951 case LyXRC::RC_PRINTEVENPAGEFLAG:
1952 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1953 case LyXRC::RC_PRINTFILEEXTENSION:
1954 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1955 case LyXRC::RC_PRINTODDPAGEFLAG:
1956 case LyXRC::RC_PRINTPAGERANGEFLAG:
1957 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1958 case LyXRC::RC_PRINTPAPERFLAG:
1959 case LyXRC::RC_PRINTREVERSEFLAG:
1960 case LyXRC::RC_PRINTSPOOL_COMMAND:
1961 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1962 case LyXRC::RC_PRINTTOFILE:
1963 case LyXRC::RC_PRINTTOPRINTER:
1964 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1965 case LyXRC::RC_PRINT_COMMAND:
1966 case LyXRC::RC_RTL_SUPPORT:
1967 case LyXRC::RC_SCREEN_DPI:
1968 case LyXRC::RC_SCREEN_FONT_ENCODING:
1969 case LyXRC::RC_SCREEN_FONT_ROMAN:
1970 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1971 case LyXRC::RC_SCREEN_FONT_SANS:
1972 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1973 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1974 case LyXRC::RC_SCREEN_FONT_SIZES:
1975 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1976 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1977 case LyXRC::RC_SCREEN_ZOOM:
1978 case LyXRC::RC_SERVERPIPE:
1979 case LyXRC::RC_SET_COLOR:
1980 case LyXRC::RC_SHOW_BANNER:
1981 case LyXRC::RC_SPELL_COMMAND:
1982 case LyXRC::RC_TEMPDIRPATH:
1983 case LyXRC::RC_TEMPLATEPATH:
1984 case LyXRC::RC_TEX_ALLOWS_SPACES:
1985 case LyXRC::RC_UIFILE:
1986 case LyXRC::RC_USER_EMAIL:
1987 case LyXRC::RC_USER_NAME:
1988 case LyXRC::RC_USETEMPDIR:
1989 case LyXRC::RC_USE_ALT_LANG:
1990 case LyXRC::RC_USE_ESC_CHARS:
1991 case LyXRC::RC_USE_INP_ENC:
1992 case LyXRC::RC_USE_PERS_DICT:
1993 case LyXRC::RC_USE_SPELL_LIB:
1994 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1995 case LyXRC::RC_VIEWER:
1996 case LyXRC::RC_WHEEL_JUMP:
1997 case LyXRC::RC_LAST: