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 Buffer * buffer = owner->buffer();
1460 lyx::textclass_type const old_class =
1461 buffer->params().textclass;
1463 loadTextclass(argument);
1465 std::pair<bool, lyx::textclass_type> const tc_pair =
1466 textclasslist.NumberOfClass(argument);
1471 lyx::textclass_type const new_class = tc_pair.second;
1472 if (old_class == new_class)
1476 owner->message(_("Converting document to new document class..."));
1478 lyx::cap::SwitchBetweenClasses(
1479 old_class, new_class,
1480 buffer->paragraphs(), el);
1482 bufferErrors(*buffer, el);
1483 view()->showErrorList(_("Class switch"));
1484 updateCounters(*buffer);
1489 case LFUN_TEXTCLASS_LOAD:
1490 loadTextclass(argument);
1493 case LFUN_LYXRC_APPLY: {
1494 LyXRC const lyxrc_orig = lyxrc;
1496 istringstream ss(argument);
1497 bool const success = lyxrc.read(ss) == 0;
1500 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1501 << "Unable to read lyxrc data"
1506 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1511 view()->cursor().dispatch(cmd);
1512 update |= view()->cursor().result().update();
1513 if (!view()->cursor().result().dispatched()) {
1514 update |= view()->dispatch(cmd);
1521 if (view()->available()) {
1522 // Redraw screen unless explicitly told otherwise.
1523 // This also initializes the position cache for all insets
1524 // in (at least partially) visible top-level paragraphs.
1526 view()->update(Update::FitCursor | Update::Force);
1528 view()->update(Update::FitCursor);
1530 // if we executed a mutating lfun, mark the buffer as dirty
1531 // FIXME: Why not use flag.enabled() but call getStatus again?
1532 if (getStatus(cmd).enabled()
1533 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1534 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1535 view()->buffer()->markDirty();
1538 if (view()->cursor().inTexted()) {
1539 view()->owner()->updateLayoutChoice();
1542 sendDispatchMessage(_(getMessage()), cmd);
1546 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1548 owner->updateMenubar();
1549 owner->updateToolbars();
1551 const bool verbose = (cmd.origin == FuncRequest::UI
1552 || cmd.origin == FuncRequest::COMMANDBUFFER);
1554 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1555 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1557 owner->message(msg);
1561 string dispatch_msg = msg;
1562 if (!dispatch_msg.empty())
1563 dispatch_msg += ' ';
1565 string comname = lyxaction.getActionName(cmd.action);
1567 bool argsadded = false;
1569 if (!cmd.argument.empty()) {
1570 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1571 comname += ' ' + cmd.argument;
1576 string const shortcuts = toplevel_keymap->printbindings(cmd);
1578 if (!shortcuts.empty()) {
1579 comname += ": " + shortcuts;
1580 } else if (!argsadded && !cmd.argument.empty()) {
1581 comname += ' ' + cmd.argument;
1584 if (!comname.empty()) {
1585 comname = rtrim(comname);
1586 dispatch_msg += '(' + comname + ')';
1589 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1590 if (!dispatch_msg.empty())
1591 owner->message(dispatch_msg);
1595 void LyXFunc::setupLocalKeymap()
1597 keyseq.stdmap = toplevel_keymap.get();
1598 keyseq.curmap = toplevel_keymap.get();
1599 cancel_meta_seq.stdmap = toplevel_keymap.get();
1600 cancel_meta_seq.curmap = toplevel_keymap.get();
1604 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1606 string initpath = lyxrc.document_path;
1607 string filename(name);
1609 if (view()->available()) {
1610 string const trypath = owner->buffer()->filePath();
1611 // If directory is writeable, use this as default.
1612 if (IsDirWriteable(trypath))
1616 static int newfile_number;
1618 if (filename.empty()) {
1619 filename = AddName(lyxrc.document_path,
1620 "newfile" + convert<string>(++newfile_number) + ".lyx");
1621 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1623 filename = AddName(lyxrc.document_path,
1624 "newfile" + convert<string>(newfile_number) +
1629 // The template stuff
1632 FileDialog fileDlg(_("Select template file"),
1633 LFUN_SELECT_FILE_SYNC,
1634 make_pair(string(_("Documents|#o#O")),
1635 string(lyxrc.document_path)),
1636 make_pair(string(_("Templates|#T#t")),
1637 string(lyxrc.template_path)));
1639 FileDialog::Result result =
1640 fileDlg.open(lyxrc.template_path,
1641 FileFilterList(_("LyX Documents (*.lyx)")),
1644 if (result.first == FileDialog::Later)
1646 if (result.second.empty())
1648 templname = result.second;
1651 view()->newFile(filename, templname, !name.empty());
1655 void LyXFunc::open(string const & fname)
1657 string initpath = lyxrc.document_path;
1659 if (view()->available()) {
1660 string const trypath = owner->buffer()->filePath();
1661 // If directory is writeable, use this as default.
1662 if (IsDirWriteable(trypath))
1668 if (fname.empty()) {
1669 FileDialog fileDlg(_("Select document to open"),
1671 make_pair(string(_("Documents|#o#O")),
1672 string(lyxrc.document_path)),
1673 make_pair(string(_("Examples|#E#e")),
1674 string(AddPath(package().system_support(), "examples"))));
1676 FileDialog::Result result =
1677 fileDlg.open(initpath,
1678 FileFilterList(_("LyX Documents (*.lyx)")),
1681 if (result.first == FileDialog::Later)
1684 filename = result.second;
1686 // check selected filename
1687 if (filename.empty()) {
1688 owner->message(_("Canceled."));
1694 // get absolute path of file and add ".lyx" to the filename if
1696 string const fullpath = FileSearch(string(), filename, "lyx");
1697 if (!fullpath.empty()) {
1698 filename = fullpath;
1701 string const disp_fn(MakeDisplayPath(filename));
1703 // if the file doesn't exist, let the user create one
1704 if (!fs::exists(filename)) {
1705 // the user specifically chose this name. Believe them.
1706 view()->newFile(filename, "", true);
1710 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1713 if (view()->loadLyXFile(filename)) {
1714 str2 = bformat(_("Document %1$s opened."), disp_fn);
1716 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1718 owner->message(str2);
1722 void LyXFunc::doImport(string const & argument)
1725 string filename = split(argument, format, ' ');
1727 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1728 << " file: " << filename << endl;
1730 // need user interaction
1731 if (filename.empty()) {
1732 string initpath = lyxrc.document_path;
1734 if (view()->available()) {
1735 string const trypath = owner->buffer()->filePath();
1736 // If directory is writeable, use this as default.
1737 if (IsDirWriteable(trypath))
1741 string const text = bformat(_("Select %1$s file to import"),
1742 formats.prettyName(format));
1744 FileDialog fileDlg(text,
1746 make_pair(string(_("Documents|#o#O")),
1747 string(lyxrc.document_path)),
1748 make_pair(string(_("Examples|#E#e")),
1749 string(AddPath(package().system_support(), "examples"))));
1751 string const filter = formats.prettyName(format)
1752 + " (*." + formats.extension(format) + ')';
1754 FileDialog::Result result =
1755 fileDlg.open(initpath,
1756 FileFilterList(filter),
1759 if (result.first == FileDialog::Later)
1762 filename = result.second;
1764 // check selected filename
1765 if (filename.empty())
1766 owner->message(_("Canceled."));
1769 if (filename.empty())
1772 // get absolute path of file
1773 filename = MakeAbsPath(filename);
1775 string const lyxfile = ChangeExtension(filename, ".lyx");
1777 // Check if the document already is open
1778 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1779 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1780 owner->message(_("Canceled."));
1785 // if the file exists already, and we didn't do
1786 // -i lyx thefile.lyx, warn
1787 if (fs::exists(lyxfile) && filename != lyxfile) {
1788 string const file = MakeDisplayPath(lyxfile, 30);
1790 string text = bformat(_("The document %1$s already exists.\n\n"
1791 "Do you want to over-write that document?"), file);
1792 int const ret = Alert::prompt(_("Over-write document?"),
1793 text, 0, 1, _("&Over-write"), _("&Cancel"));
1796 owner->message(_("Canceled."));
1801 Importer::Import(owner, filename, format);
1805 void LyXFunc::closeBuffer()
1807 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1808 if (bufferlist.empty()) {
1809 // need this otherwise SEGV may occur while
1810 // trying to set variables that don't exist
1811 // since there's no current buffer
1812 owner->getDialogs().hideBufferDependent();
1814 view()->setBuffer(bufferlist.first());
1820 // Each "owner" should have it's own message method. lyxview and
1821 // the minibuffer would use the minibuffer, but lyxserver would
1822 // send an ERROR signal to its client. Alejandro 970603
1823 // This function is bit problematic when it comes to NLS, to make the
1824 // lyx servers client be language indepenent we must not translate
1825 // strings sent to this func.
1826 void LyXFunc::setErrorMessage(string const & m) const
1828 dispatch_buffer = m;
1833 void LyXFunc::setMessage(string const & m) const
1835 dispatch_buffer = m;
1839 string const LyXFunc::viewStatusMessage()
1841 // When meta-fake key is pressed, show the key sequence so far + "M-".
1843 return keyseq.print() + "M-";
1845 // Else, when a non-complete key sequence is pressed,
1846 // show the available options.
1847 if (keyseq.length() > 0 && !keyseq.deleted())
1848 return keyseq.printOptions();
1850 if (!view()->available())
1851 return _("Welcome to LyX!");
1853 return view()->cursor().currentState();
1857 BufferView * LyXFunc::view() const
1859 BOOST_ASSERT(owner);
1860 return owner->view().get();
1864 bool LyXFunc::wasMetaKey() const
1866 return (meta_fake_bit != key_modifier::none);
1872 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1874 // Why the switch you might ask. It is a trick to ensure that all
1875 // the elements in the LyXRCTags enum is handled. As you can see
1876 // there are no breaks at all. So it is just a huge fall-through.
1877 // The nice thing is that we will get a warning from the compiler
1878 // if we forget an element.
1879 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1881 case LyXRC::RC_ACCEPT_COMPOUND:
1882 case LyXRC::RC_ALT_LANG:
1883 case LyXRC::RC_ASCIIROFF_COMMAND:
1884 case LyXRC::RC_ASCII_LINELEN:
1885 case LyXRC::RC_AUTOREGIONDELETE:
1886 case LyXRC::RC_AUTORESET_OPTIONS:
1887 case LyXRC::RC_AUTOSAVE:
1888 case LyXRC::RC_AUTO_NUMBER:
1889 case LyXRC::RC_BACKUPDIR_PATH:
1890 case LyXRC::RC_BIBTEX_COMMAND:
1891 case LyXRC::RC_BINDFILE:
1892 case LyXRC::RC_CHECKLASTFILES:
1893 case LyXRC::RC_CHKTEX_COMMAND:
1894 case LyXRC::RC_CONVERTER:
1895 case LyXRC::RC_COPIER:
1896 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1897 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1898 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1899 case LyXRC::RC_CYGWIN_PATH_FIX:
1900 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1901 namespace os = lyx::support::os;
1902 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1904 case LyXRC::RC_DATE_INSERT_FORMAT:
1905 case LyXRC::RC_DEFAULT_LANGUAGE:
1906 case LyXRC::RC_DEFAULT_PAPERSIZE:
1907 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1908 case LyXRC::RC_DISPLAY_GRAPHICS:
1909 case LyXRC::RC_DOCUMENTPATH:
1910 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1911 if (fs::exists(lyxrc_new.document_path) &&
1912 fs::is_directory(lyxrc_new.document_path)) {
1913 using lyx::support::package;
1914 package().document_dir() = lyxrc.document_path;
1917 case LyXRC::RC_ESC_CHARS:
1918 case LyXRC::RC_FONT_ENCODING:
1919 case LyXRC::RC_FORMAT:
1920 case LyXRC::RC_INDEX_COMMAND:
1921 case LyXRC::RC_INPUT:
1922 case LyXRC::RC_KBMAP:
1923 case LyXRC::RC_KBMAP_PRIMARY:
1924 case LyXRC::RC_KBMAP_SECONDARY:
1925 case LyXRC::RC_LABEL_INIT_LENGTH:
1926 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1927 case LyXRC::RC_LANGUAGE_AUTO_END:
1928 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1929 case LyXRC::RC_LANGUAGE_COMMAND_END:
1930 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1931 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1932 case LyXRC::RC_LANGUAGE_PACKAGE:
1933 case LyXRC::RC_LANGUAGE_USE_BABEL:
1934 case LyXRC::RC_LASTFILES:
1935 case LyXRC::RC_MAKE_BACKUP:
1936 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1937 case LyXRC::RC_NUMLASTFILES:
1938 case LyXRC::RC_PATH_PREFIX:
1939 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1940 using lyx::support::prependEnvPath;
1941 prependEnvPath("PATH", lyxrc.path_prefix);
1943 case LyXRC::RC_PERS_DICT:
1944 case LyXRC::RC_POPUP_BOLD_FONT:
1945 case LyXRC::RC_POPUP_FONT_ENCODING:
1946 case LyXRC::RC_POPUP_NORMAL_FONT:
1947 case LyXRC::RC_PREVIEW:
1948 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1949 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1950 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1951 case LyXRC::RC_PRINTCOPIESFLAG:
1952 case LyXRC::RC_PRINTER:
1953 case LyXRC::RC_PRINTEVENPAGEFLAG:
1954 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1955 case LyXRC::RC_PRINTFILEEXTENSION:
1956 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1957 case LyXRC::RC_PRINTODDPAGEFLAG:
1958 case LyXRC::RC_PRINTPAGERANGEFLAG:
1959 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1960 case LyXRC::RC_PRINTPAPERFLAG:
1961 case LyXRC::RC_PRINTREVERSEFLAG:
1962 case LyXRC::RC_PRINTSPOOL_COMMAND:
1963 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1964 case LyXRC::RC_PRINTTOFILE:
1965 case LyXRC::RC_PRINTTOPRINTER:
1966 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1967 case LyXRC::RC_PRINT_COMMAND:
1968 case LyXRC::RC_RTL_SUPPORT:
1969 case LyXRC::RC_SCREEN_DPI:
1970 case LyXRC::RC_SCREEN_FONT_ENCODING:
1971 case LyXRC::RC_SCREEN_FONT_ROMAN:
1972 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1973 case LyXRC::RC_SCREEN_FONT_SANS:
1974 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1975 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1976 case LyXRC::RC_SCREEN_FONT_SIZES:
1977 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1978 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1979 case LyXRC::RC_SCREEN_ZOOM:
1980 case LyXRC::RC_SERVERPIPE:
1981 case LyXRC::RC_SET_COLOR:
1982 case LyXRC::RC_SHOW_BANNER:
1983 case LyXRC::RC_SPELL_COMMAND:
1984 case LyXRC::RC_TEMPDIRPATH:
1985 case LyXRC::RC_TEMPLATEPATH:
1986 case LyXRC::RC_TEX_ALLOWS_SPACES:
1987 case LyXRC::RC_UIFILE:
1988 case LyXRC::RC_USER_EMAIL:
1989 case LyXRC::RC_USER_NAME:
1990 case LyXRC::RC_USETEMPDIR:
1991 case LyXRC::RC_USE_ALT_LANG:
1992 case LyXRC::RC_USE_ESC_CHARS:
1993 case LyXRC::RC_USE_INP_ENC:
1994 case LyXRC::RC_USE_PERS_DICT:
1995 case LyXRC::RC_USE_SPELL_LIB:
1996 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1997 case LyXRC::RC_VIEWER:
1998 case LyXRC::RC_WHEEL_JUMP:
1999 case LyXRC::RC_LAST: