3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
24 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
31 #include "CutAndPaste.h"
33 #include "dispatchresult.h"
35 #include "errorlist.h"
38 #include "funcrequest.h"
41 #include "insetiterator.h"
47 #include "LyXAction.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
60 #include "insets/insetbox.h"
61 #include "insets/insetbranch.h"
62 #include "insets/insetcommand.h"
63 #include "insets/insetert.h"
64 #include "insets/insetexternal.h"
65 #include "insets/insetfloat.h"
66 #include "insets/insetgraphics.h"
67 #include "insets/insetnote.h"
68 #include "insets/insettabular.h"
69 #include "insets/insetvspace.h"
70 #include "insets/insetwrap.h"
72 #include "frontends/Alert.h"
73 #include "frontends/Dialogs.h"
74 #include "frontends/FileDialog.h"
75 #include "frontends/lyx_gui.h"
76 #include "frontends/LyXKeySym.h"
77 #include "frontends/LyXView.h"
78 #include "frontends/Menubar.h"
79 #include "frontends/Toolbars.h"
81 #include "support/filefilterlist.h"
82 #include "support/filetools.h"
83 #include "support/forkedcontr.h"
84 #include "support/fs_extras.h"
85 #include "support/lstrings.h"
86 #include "support/path.h"
87 #include "support/package.h"
88 #include "support/systemcall.h"
89 #include "support/convert.h"
90 #include "support/os.h"
92 #include <boost/filesystem/operations.hpp>
96 using bv_funcs::freefont2string;
98 using lyx::support::AbsolutePath;
99 using lyx::support::AddName;
100 using lyx::support::AddPath;
101 using lyx::support::bformat;
102 using lyx::support::ChangeExtension;
103 using lyx::support::contains;
104 using lyx::support::FileFilterList;
105 using lyx::support::FileSearch;
106 using lyx::support::ForkedcallsController;
107 using lyx::support::i18nLibFileSearch;
108 using lyx::support::IsDirWriteable;
109 using lyx::support::IsFileReadable;
110 using lyx::support::isStrInt;
111 using lyx::support::MakeAbsPath;
112 using lyx::support::MakeDisplayPath;
113 using lyx::support::package;
114 using lyx::support::Path;
115 using lyx::support::QuoteName;
116 using lyx::support::rtrim;
117 using lyx::support::split;
118 using lyx::support::subst;
119 using lyx::support::Systemcall;
120 using lyx::support::token;
121 using lyx::support::trim;
122 using lyx::support::prefixIs;
125 using std::make_pair;
128 using std::istringstream;
130 namespace biblio = lyx::biblio;
131 namespace fs = boost::filesystem;
134 extern BufferList bufferlist;
135 extern LyXServer * lyxserver;
137 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
140 extern tex_accent_struct get_accent(kb_action action);
145 bool getStatus(LCursor cursor,
146 FuncRequest const & cmd, FuncStatus & status)
148 // This is, of course, a mess. Better create a new doc iterator and use
149 // this in Inset::getStatus. This might require an additional
150 // BufferView * arg, though (which should be avoided)
151 //LCursor safe = *this;
153 for ( ; cursor.depth(); cursor.pop()) {
154 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
155 DocIterator::idx_type & idx = cursor.idx();
156 DocIterator::idx_type const lastidx = cursor.lastidx();
159 lyxerr << "wrong idx " << idx << ", max is " << lastidx
160 << ". Trying to correct this." << endl;
164 DocIterator::pit_type & pit = cursor.pit();
165 DocIterator::pit_type const lastpit = cursor.lastpit();
168 lyxerr << "wrong par " << pit << ", max is " << lastpit
169 << ". Trying to correct this." << endl;
173 DocIterator::pos_type & pos = cursor.pos();
174 DocIterator::pos_type const lastpos = cursor.lastpos();
177 lyxerr << "wrong pos " << pos << ", max is " << lastpos
178 << ". Trying to correct this." << endl;
182 // The inset's getStatus() will return 'true' if it made
183 // a definitive decision on whether it want to handle the
184 // request or not. The result of this decision is put into
185 // the 'status' parameter.
186 if (cursor.inset().getStatus(cursor, cmd, status)) {
196 LyXFunc::LyXFunc(LyXView * lv)
199 keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
200 cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
201 meta_fake_bit(key_modifier::none)
206 void LyXFunc::handleKeyFunc(kb_action action)
208 char c = encoded_last_key;
210 if (keyseq.length()) {
214 owner->getIntl().getTransManager()
215 .deadkey(c, get_accent(action).accent, view()->getLyXText());
216 // Need to clear, in case the minibuffer calls these
219 // copied verbatim from do_accent_char
220 view()->cursor().resetAnchor();
225 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
227 lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
229 // Do nothing if we have nothing (JMarc)
230 if (!keysym->isOK()) {
231 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
236 if (keysym->isModifier()) {
237 lyxerr[Debug::KEY] << "isModifier true" << endl;
241 Encoding const * encoding = view()->cursor().getEncoding();
243 encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
245 // Do a one-deep top-level lookup for
246 // cancel and meta-fake keys. RVDK_PATCH_5
247 cancel_meta_seq.reset();
249 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
250 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
251 << " action first set to [" << func.action << ']'
254 // When not cancel or meta-fake, do the normal lookup.
255 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
256 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
257 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
258 // remove Caps Lock and Mod2 as a modifiers
259 func = keyseq.addkey(keysym, (state | meta_fake_bit));
260 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
261 << "action now set to ["
262 << func.action << ']' << endl;
265 // Dont remove this unless you know what you are doing.
266 meta_fake_bit = key_modifier::none;
268 // Can this happen now ?
269 if (func.action == LFUN_NOACTION) {
270 func = FuncRequest(LFUN_PREFIX);
273 if (lyxerr.debugging(Debug::KEY)) {
274 lyxerr << BOOST_CURRENT_FUNCTION
276 << func.action << "]["
277 << keyseq.print() << ']'
281 // already here we know if it any point in going further
282 // why not return already here if action == -1 and
283 // num_bytes == 0? (Lgb)
285 if (keyseq.length() > 1) {
286 owner->message(keyseq.print());
290 // Maybe user can only reach the key via holding down shift.
291 // Let's see. But only if shift is the only modifier
292 if (func.action == LFUN_UNKNOWN_ACTION &&
293 state == key_modifier::shift) {
294 lyxerr[Debug::KEY] << "Trying without shift" << endl;
295 func = keyseq.addkey(keysym, key_modifier::none);
296 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
299 if (func.action == LFUN_UNKNOWN_ACTION) {
300 // Hmm, we didn't match any of the keysequences. See
301 // if it's normal insertable text not already covered
303 if (keysym->isText() && keyseq.length() == 1) {
304 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
305 func = FuncRequest(LFUN_SELFINSERT);
307 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
308 owner->message(_("Unknown function."));
313 if (func.action == LFUN_SELFINSERT) {
314 if (encoded_last_key != 0) {
315 string const arg(1, encoded_last_key);
316 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
318 << "SelfInsert arg[`" << arg << "']" << endl;
326 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
328 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
330 LCursor & cur = view()->cursor();
332 /* In LyX/Mac, when a dialog is open, the menus of the
333 application can still be accessed without giving focus to
334 the main window. In this case, we want to disable the menu
335 entries that are buffer-related.
338 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
341 buf = owner->buffer();
343 if (cmd.action == LFUN_NOACTION) {
344 flag.message(N_("Nothing to do"));
349 switch (cmd.action) {
350 case LFUN_UNKNOWN_ACTION:
351 #ifndef HAVE_LIBAIKSAURUS
352 case LFUN_THESAURUS_ENTRY:
358 flag |= lyx_gui::getStatus(cmd);
361 if (flag.unknown()) {
362 flag.message(N_("Unknown action"));
366 if (!flag.enabled()) {
367 if (flag.message().empty())
368 flag.message(N_("Command disabled"));
372 // Check whether we need a buffer
373 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
375 flag.message(N_("Command not allowed with"
376 "out any document open"));
381 // I would really like to avoid having this switch and rather try to
382 // encode this in the function itself.
383 // -- And I'd rather let an inset decide which LFUNs it is willing
384 // to handle (Andre')
386 switch (cmd.action) {
387 case LFUN_TOOLTIPS_TOGGLE:
388 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
391 case LFUN_READ_ONLY_TOGGLE:
392 flag.setOnOff(buf->isReadonly());
395 case LFUN_SWITCHBUFFER:
396 // toggle on the current buffer, but do not toggle off
397 // the other ones (is that a good idea?)
398 if (cmd.argument == buf->fileName())
403 enable = cmd.argument == "custom"
404 || Exporter::IsExportable(*buf, cmd.argument);
408 enable = cur.selection();
412 enable = buf->isLatex() && lyxrc.chktex_command != "none";
416 enable = Exporter::IsExportable(*buf, "program");
419 case LFUN_LAYOUT_TABULAR:
420 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
424 case LFUN_LAYOUT_PARAGRAPH:
425 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
428 case LFUN_VC_REGISTER:
429 enable = !buf->lyxvc().inUse();
431 case LFUN_VC_CHECKIN:
432 enable = buf->lyxvc().inUse() && !buf->isReadonly();
434 case LFUN_VC_CHECKOUT:
435 enable = buf->lyxvc().inUse() && buf->isReadonly();
439 enable = buf->lyxvc().inUse();
441 case LFUN_MENURELOAD:
442 enable = !buf->isUnnamed() && !buf->isClean();
445 case LFUN_INSET_SETTINGS: {
449 UpdatableInset * inset = cur.inset().asUpdatableInset();
450 lyxerr << "inset: " << inset << endl;
454 InsetBase::Code code = inset->lyxCode();
456 case InsetBase::TABULAR_CODE:
457 enable = cmd.argument == "tabular";
459 case InsetBase::ERT_CODE:
460 enable = cmd.argument == "ert";
462 case InsetBase::FLOAT_CODE:
463 enable = cmd.argument == "float";
465 case InsetBase::WRAP_CODE:
466 enable = cmd.argument == "wrap";
468 case InsetBase::NOTE_CODE:
469 enable = cmd.argument == "note";
471 case InsetBase::BRANCH_CODE:
472 enable = cmd.argument == "branch";
474 case InsetBase::BOX_CODE:
475 enable = cmd.argument == "box";
483 case LFUN_DIALOG_SHOW: {
484 string const name = cmd.getArg(0);
486 enable = name == "aboutlyx"
490 || name == "texinfo";
491 else if (name == "print")
492 enable = Exporter::IsExportable(*buf, "dvi")
493 && lyxrc.print_command != "none";
494 else if (name == "character" || name == "mathpanel")
495 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
496 else if (name == "vclog")
497 enable = buf->lyxvc().inUse();
498 else if (name == "latexlog")
499 enable = IsFileReadable(buf->getLogName().second);
503 case LFUN_DIALOG_SHOW_NEW_INSET:
504 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
507 case LFUN_DIALOG_UPDATE: {
508 string const name = cmd.getArg(0);
510 enable = name == "prefs";
514 // this one is difficult to get right. As a half-baked
515 // solution, we consider only the first action of the sequence
516 case LFUN_SEQUENCE: {
517 // argument contains ';'-terminated commands
518 string const firstcmd = token(cmd.argument, ';', 0);
519 FuncRequest func(lyxaction.lookupFunc(firstcmd));
520 func.origin = cmd.origin;
521 flag = getStatus(func);
525 case LFUN_MENUNEWTMPLT:
526 case LFUN_WORDFINDFORWARD:
527 case LFUN_WORDFINDBACKWARD:
529 case LFUN_EXEC_COMMAND:
532 case LFUN_CLOSEBUFFER:
541 case LFUN_RECONFIGURE:
545 case LFUN_DROP_LAYOUTS_CHOICE:
546 case LFUN_MENU_OPEN_BY_NAME:
549 case LFUN_GOTOFILEROW:
550 case LFUN_GOTO_PARAGRAPH:
551 case LFUN_DIALOG_SHOW_NEXT_INSET:
552 case LFUN_DIALOG_HIDE:
553 case LFUN_DIALOG_DISCONNECT_INSET:
555 case LFUN_TOGGLECURSORFOLLOW:
559 case LFUN_KMAP_TOGGLE:
561 case LFUN_EXPORT_CUSTOM:
563 case LFUN_SAVEPREFERENCES:
564 case LFUN_SCREEN_FONT_UPDATE:
567 case LFUN_EXTERNAL_EDIT:
568 case LFUN_GRAPHICS_EDIT:
569 case LFUN_ALL_INSETS_TOGGLE:
570 case LFUN_LANGUAGE_BUFFER:
571 case LFUN_TEXTCLASS_APPLY:
572 case LFUN_TEXTCLASS_LOAD:
573 case LFUN_SAVE_AS_DEFAULT:
574 case LFUN_BUFFERPARAMS_APPLY:
575 case LFUN_LYXRC_APPLY:
576 case LFUN_NEXTBUFFER:
577 case LFUN_PREVIOUSBUFFER:
578 // these are handled in our dispatch()
583 if (!::getStatus(cur, cmd, flag))
584 flag = view()->getStatus(cmd);
590 // Can we use a readonly buffer?
591 if (buf && buf->isReadonly()
592 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
593 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
594 flag.message(N_("Document is read-only"));
598 // the default error message if we disable the command
599 if (!flag.enabled() && flag.message().empty())
600 flag.message(N_("Command disabled"));
608 bool ensureBufferClean(BufferView * bv)
610 Buffer & buf = *bv->buffer();
614 string const file = MakeDisplayPath(buf.fileName(), 30);
615 string text = bformat(_("The document %1$s has unsaved "
616 "changes.\n\nDo you want to save "
617 "the document?"), file);
618 int const ret = Alert::prompt(_("Save changed document?"),
619 text, 0, 1, _("&Save"),
623 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
625 return buf.isClean();
629 void showPrintError(string const & name)
631 string str = bformat(_("Could not print the document %1$s.\n"
632 "Check that your printer is set up correctly."),
633 MakeDisplayPath(name, 50));
634 Alert::error(_("Print document failed"), str);
638 void loadTextclass(string const & name)
640 std::pair<bool, lyx::textclass_type> const tc_pair =
641 textclasslist.NumberOfClass(name);
643 if (!tc_pair.first) {
644 lyxerr << "Document class \"" << name
645 << "\" does not exist."
650 lyx::textclass_type const tc = tc_pair.second;
652 if (!textclasslist[tc].load()) {
653 string s = bformat(_("The document could not be converted\n"
654 "into the document class %1$s."),
655 textclasslist[tc].name());
656 Alert::error(_("Could not change class"), s);
661 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
666 void LyXFunc::dispatch(FuncRequest const & cmd)
668 BOOST_ASSERT(view());
669 string const argument = cmd.argument;
670 kb_action const action = cmd.action;
672 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
673 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
675 // we have not done anything wrong yet.
677 dispatch_buffer.erase();
681 FuncStatus const flag = getStatus(cmd);
682 if (!flag.enabled()) {
683 // We cannot use this function here
684 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
685 << lyxaction.getActionName(action)
686 << " [" << action << "] is disabled at this location"
688 setErrorMessage(flag.message());
691 if (view()->available())
692 view()->hideCursor();
696 case LFUN_WORDFINDFORWARD:
697 case LFUN_WORDFINDBACKWARD: {
698 static string last_search;
699 string searched_string;
701 if (!argument.empty()) {
702 last_search = argument;
703 searched_string = argument;
705 searched_string = last_search;
708 if (searched_string.empty())
711 bool const fw = action == LFUN_WORDFINDFORWARD;
713 lyx::find::find2string(searched_string, true, false, fw);
714 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
719 owner->message(keyseq.printOptions());
722 case LFUN_EXEC_COMMAND:
723 owner->getToolbars().display("minibuffer", true);
724 owner->focus_command_buffer();
729 meta_fake_bit = key_modifier::none;
730 if (view()->available())
731 // cancel any selection
732 dispatch(FuncRequest(LFUN_MARK_OFF));
733 setMessage(N_("Cancel"));
737 meta_fake_bit = key_modifier::alt;
738 setMessage(keyseq.print());
741 case LFUN_READ_ONLY_TOGGLE:
742 if (owner->buffer()->lyxvc().inUse())
743 owner->buffer()->lyxvc().toggleReadOnly();
745 owner->buffer()->setReadonly(
746 !owner->buffer()->isReadonly());
749 // --- Menus -----------------------------------------------
751 menuNew(argument, false);
754 case LFUN_MENUNEWTMPLT:
755 menuNew(argument, true);
758 case LFUN_CLOSEBUFFER:
763 if (!owner->buffer()->isUnnamed()) {
764 string const str = bformat(_("Saving document %1$s..."),
765 MakeDisplayPath(owner->buffer()->fileName()));
767 MenuWrite(owner->buffer());
768 owner->message(str + _(" done."));
770 WriteAs(owner->buffer());
774 WriteAs(owner->buffer(), argument);
777 case LFUN_MENURELOAD: {
778 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
779 string text = bformat(_("Any changes will be lost. Are you sure "
780 "you want to revert to the saved version of the document %1$s?"), file);
781 int const ret = Alert::prompt(_("Revert to saved document?"),
782 text, 0, 1, _("&Revert"), _("&Cancel"));
790 Exporter::Export(owner->buffer(), argument, true);
791 view()->showErrorList(BufferFormat(*owner->buffer()));
795 Exporter::Preview(owner->buffer(), argument);
796 view()->showErrorList(BufferFormat(*owner->buffer()));
800 Exporter::Export(owner->buffer(), "program", true);
801 view()->showErrorList(_("Build"));
805 owner->buffer()->runChktex();
806 view()->showErrorList(_("ChkTeX"));
810 if (argument == "custom")
811 owner->getDialogs().show("sendto");
813 Exporter::Export(owner->buffer(), argument, false);
814 view()->showErrorList(BufferFormat(*owner->buffer()));
818 case LFUN_EXPORT_CUSTOM: {
820 string command = split(argument, format_name, ' ');
821 Format const * format = formats.getFormat(format_name);
823 lyxerr << "Format \"" << format_name
824 << "\" not recognized!"
829 Buffer * buffer = owner->buffer();
831 // The name of the file created by the conversion process
834 // Output to filename
835 if (format->name() == "lyx") {
836 string const latexname =
837 buffer->getLatexName(false);
838 filename = ChangeExtension(latexname,
839 format->extension());
840 filename = AddName(buffer->temppath(), filename);
842 if (!buffer->writeFile(filename))
846 Exporter::Export(buffer, format_name, true,
850 // Substitute $$FName for filename
851 if (!contains(command, "$$FName"))
852 command = "( " + command + " ) < $$FName";
853 command = subst(command, "$$FName", filename);
855 // Execute the command in the background
857 call.startscript(Systemcall::DontWait, command);
864 string command = split(split(argument, target, ' '),
868 || target_name.empty()
869 || command.empty()) {
870 lyxerr << "Unable to parse \""
871 << argument << '"' << std::endl;
874 if (target != "printer" && target != "file") {
875 lyxerr << "Unrecognized target \""
876 << target << '"' << std::endl;
880 Buffer * buffer = owner->buffer();
882 if (!Exporter::Export(buffer, "dvi", true)) {
883 showPrintError(buffer->fileName());
887 // Push directory path.
888 string const path = buffer->temppath();
891 // there are three cases here:
892 // 1. we print to a file
893 // 2. we print directly to a printer
894 // 3. we print using a spool command (print to file first)
897 string const dviname =
898 ChangeExtension(buffer->getLatexName(true),
901 if (target == "printer") {
902 if (!lyxrc.print_spool_command.empty()) {
903 // case 3: print using a spool
904 string const psname =
905 ChangeExtension(dviname,".ps");
906 command += lyxrc.print_to_file
909 + QuoteName(dviname);
912 lyxrc.print_spool_command +' ';
913 if (target_name != "default") {
914 command2 += lyxrc.print_spool_printerprefix
918 command2 += QuoteName(psname);
920 // If successful, then spool command
921 res = one.startscript(
926 res = one.startscript(
927 Systemcall::DontWait,
930 // case 2: print directly to a printer
931 res = one.startscript(
932 Systemcall::DontWait,
933 command + QuoteName(dviname));
937 // case 1: print to a file
938 command += lyxrc.print_to_file
939 + QuoteName(MakeAbsPath(target_name,
942 + QuoteName(dviname);
943 res = one.startscript(Systemcall::DontWait,
948 showPrintError(buffer->fileName());
961 InsetCommandParams p("tableofcontents");
962 string const data = InsetCommandMailer::params2string("toc", p);
963 owner->getDialogs().show("toc", data, 0);
971 case LFUN_RECONFIGURE:
975 case LFUN_HELP_OPEN: {
976 string const arg = argument;
978 setErrorMessage(N_("Missing argument"));
981 string const fname = i18nLibFileSearch("doc", arg, "lyx");
983 lyxerr << "LyX: unable to find documentation file `"
984 << arg << "'. Bad installation?" << endl;
987 owner->message(bformat(_("Opening help file %1$s..."),
988 MakeDisplayPath(fname)));
989 view()->loadLyXFile(fname, false);
993 // --- version control -------------------------------
994 case LFUN_VC_REGISTER:
995 if (!ensureBufferClean(view()))
997 if (!owner->buffer()->lyxvc().inUse()) {
998 owner->buffer()->lyxvc().registrer();
1003 case LFUN_VC_CHECKIN:
1004 if (!ensureBufferClean(view()))
1006 if (owner->buffer()->lyxvc().inUse()
1007 && !owner->buffer()->isReadonly()) {
1008 owner->buffer()->lyxvc().checkIn();
1013 case LFUN_VC_CHECKOUT:
1014 if (!ensureBufferClean(view()))
1016 if (owner->buffer()->lyxvc().inUse()
1017 && owner->buffer()->isReadonly()) {
1018 owner->buffer()->lyxvc().checkOut();
1023 case LFUN_VC_REVERT:
1024 owner->buffer()->lyxvc().revert();
1029 owner->buffer()->lyxvc().undoLast();
1033 // --- buffers ----------------------------------------
1034 case LFUN_SWITCHBUFFER:
1035 view()->setBuffer(bufferlist.getBuffer(argument));
1038 case LFUN_NEXTBUFFER:
1039 view()->setBuffer(bufferlist.next(view()->buffer()));
1042 case LFUN_PREVIOUSBUFFER:
1043 view()->setBuffer(bufferlist.previous(view()->buffer()));
1047 NewFile(view(), argument);
1050 case LFUN_FILE_OPEN:
1054 case LFUN_DROP_LAYOUTS_CHOICE:
1055 owner->getToolbars().openLayoutList();
1058 case LFUN_MENU_OPEN_BY_NAME:
1059 owner->getMenubar().openByName(argument);
1062 // --- lyxserver commands ----------------------------
1064 setMessage(owner->buffer()->fileName());
1065 lyxerr[Debug::INFO] << "FNAME["
1066 << owner->buffer()->fileName()
1071 dispatch_buffer = keyseq.print();
1072 lyxserver->notifyClient(dispatch_buffer);
1075 case LFUN_GOTOFILEROW: {
1078 istringstream is(argument);
1079 is >> file_name >> row;
1080 if (prefixIs(file_name, package().temp_dir())) {
1081 // Needed by inverse dvi search. If it is a file
1082 // in tmpdir, call the apropriated function
1083 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1085 // Must replace extension of the file to be .lyx
1086 // and get full path
1087 string const s = ChangeExtension(file_name, ".lyx");
1088 // Either change buffer or load the file
1089 if (bufferlist.exists(s)) {
1090 view()->setBuffer(bufferlist.getBuffer(s));
1092 view()->loadLyXFile(s);
1096 view()->setCursorFromRow(row);
1099 // see BufferView_pimpl::center()
1100 view()->updateScrollbar();
1104 case LFUN_GOTO_PARAGRAPH: {
1105 istringstream is(argument);
1108 ParIterator par = owner->buffer()->getParFromID(id);
1109 if (par == owner->buffer()->par_iterator_end()) {
1110 lyxerr[Debug::INFO] << "No matching paragraph found! ["
1111 << id << ']' << endl;
1114 lyxerr[Debug::INFO] << "Paragraph " << par->id()
1115 << " found." << endl;
1119 view()->setCursor(par, 0);
1121 view()->switchKeyMap();
1122 owner->view_state_changed();
1125 // see BufferView_pimpl::center()
1126 view()->updateScrollbar();
1130 case LFUN_DIALOG_SHOW: {
1131 string const name = cmd.getArg(0);
1132 string data = trim(cmd.argument.substr(name.size()));
1134 if (name == "character") {
1135 data = freefont2string();
1137 owner->getDialogs().show("character", data);
1140 else if (name == "latexlog") {
1141 pair<Buffer::LogType, string> const logfile =
1142 owner->buffer()->getLogName();
1143 switch (logfile.first) {
1144 case Buffer::latexlog:
1147 case Buffer::buildlog:
1151 data += logfile.second;
1152 owner->getDialogs().show("log", data);
1154 else if (name == "vclog") {
1155 string const data = "vc " +
1156 owner->buffer()->lyxvc().getLogFile();
1157 owner->getDialogs().show("log", data);
1160 owner->getDialogs().show(name, data);
1164 case LFUN_DIALOG_SHOW_NEW_INSET: {
1165 string const name = cmd.getArg(0);
1166 string data = trim(cmd.argument.substr(name.size()));
1167 if (name == "bibitem" ||
1169 name == "include" ||
1175 InsetCommandParams p(name);
1176 data = InsetCommandMailer::params2string(name, p);
1177 } else if (name == "box") {
1178 // \c data == "Boxed" || "Frameless" etc
1179 InsetBoxParams p(data);
1180 data = InsetBoxMailer::params2string(p);
1181 } else if (name == "branch") {
1182 InsetBranchParams p;
1183 data = InsetBranchMailer::params2string(p);
1184 } else if (name == "citation") {
1185 InsetCommandParams p("cite");
1186 data = InsetCommandMailer::params2string(name, p);
1187 } else if (name == "ert") {
1188 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1189 } else if (name == "external") {
1190 InsetExternalParams p;
1191 Buffer const & buffer = *owner->buffer();
1192 data = InsetExternalMailer::params2string(p, buffer);
1193 } else if (name == "float") {
1195 data = InsetFloatMailer::params2string(p);
1196 } else if (name == "graphics") {
1197 InsetGraphicsParams p;
1198 Buffer const & buffer = *owner->buffer();
1199 data = InsetGraphicsMailer::params2string(p, buffer);
1200 } else if (name == "note") {
1202 data = InsetNoteMailer::params2string(p);
1203 } else if (name == "vspace") {
1205 data = InsetVSpaceMailer::params2string(space);
1206 } else if (name == "wrap") {
1208 data = InsetWrapMailer::params2string(p);
1210 owner->getDialogs().show(name, data, 0);
1214 case LFUN_DIALOG_SHOW_NEXT_INSET:
1217 case LFUN_DIALOG_UPDATE: {
1218 string const & name = argument;
1219 // Can only update a dialog connected to an existing inset
1220 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1222 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1223 inset->dispatch(view()->cursor(), fr);
1224 } else if (name == "paragraph") {
1225 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1226 } else if (name == "prefs") {
1227 owner->getDialogs().update(name, string());
1232 case LFUN_DIALOG_HIDE:
1233 Dialogs::hide(argument, 0);
1236 case LFUN_DIALOG_DISCONNECT_INSET:
1237 owner->getDialogs().disconnect(argument);
1240 case LFUN_CHILDOPEN: {
1241 string const filename =
1242 MakeAbsPath(argument, owner->buffer()->filePath());
1243 setMessage(N_("Opening child document ") +
1244 MakeDisplayPath(filename) + "...");
1245 view()->savePosition(0);
1246 string const parentfilename = owner->buffer()->fileName();
1247 if (bufferlist.exists(filename))
1248 view()->setBuffer(bufferlist.getBuffer(filename));
1250 view()->loadLyXFile(filename);
1251 // Set the parent name of the child document.
1252 // This makes insertion of citations and references in the child work,
1253 // when the target is in the parent or another child document.
1254 owner->buffer()->setParentName(parentfilename);
1258 case LFUN_TOGGLECURSORFOLLOW:
1259 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1263 owner->getIntl().KeyMapOn(false);
1266 case LFUN_KMAP_PRIM:
1267 owner->getIntl().KeyMapPrim();
1271 owner->getIntl().KeyMapSec();
1274 case LFUN_KMAP_TOGGLE:
1275 owner->getIntl().ToggleKeyMap();
1281 string rest = split(argument, countstr, ' ');
1282 istringstream is(countstr);
1285 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1286 for (int i = 0; i < count; ++i)
1287 dispatch(lyxaction.lookupFunc(rest));
1291 case LFUN_SEQUENCE: {
1292 // argument contains ';'-terminated commands
1293 string arg = argument;
1294 while (!arg.empty()) {
1296 arg = split(arg, first, ';');
1297 FuncRequest func(lyxaction.lookupFunc(first));
1298 func.origin = cmd.origin;
1304 case LFUN_SAVEPREFERENCES: {
1305 Path p(package().user_support());
1306 lyxrc.write("preferences", false);
1310 case LFUN_SCREEN_FONT_UPDATE:
1311 // handle the screen font changes.
1312 lyxrc.set_font_norm_type();
1313 lyx_gui::update_fonts();
1314 // All visible buffers will need resize
1318 case LFUN_SET_COLOR: {
1320 string const x11_name = split(argument, lyx_name, ' ');
1321 if (lyx_name.empty() || x11_name.empty()) {
1322 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1327 bool const graphicsbg_changed =
1328 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1329 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1331 if (!lcolor.setColor(lyx_name, x11_name)) {
1333 bformat(_("Set-color \"%1$s\" failed "
1334 "- color is undefined or "
1335 "may not be redefined"), lyx_name));
1339 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1341 if (graphicsbg_changed) {
1342 #ifdef WITH_WARNINGS
1343 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1346 lyx::graphics::GCache::get().changeDisplay(true);
1353 owner->message(argument);
1356 case LFUN_TOOLTIPS_TOGGLE:
1357 owner->getDialogs().toggleTooltips();
1360 case LFUN_EXTERNAL_EDIT: {
1361 FuncRequest fr(action, argument);
1362 InsetExternal().dispatch(view()->cursor(), fr);
1366 case LFUN_GRAPHICS_EDIT: {
1367 FuncRequest fr(action, argument);
1368 InsetGraphics().dispatch(view()->cursor(), fr);
1372 case LFUN_ALL_INSETS_TOGGLE: {
1374 string const name = split(argument, action, ' ');
1375 InsetBase::Code const inset_code =
1376 InsetBase::translate(name);
1378 LCursor & cur = view()->cursor();
1379 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1381 InsetBase & inset = owner->buffer()->inset();
1382 InsetIterator it = inset_iterator_begin(inset);
1383 InsetIterator const end = inset_iterator_end(inset);
1384 for (; it != end; ++it) {
1385 if (inset_code == InsetBase::NO_CODE
1386 || inset_code == it->lyxCode())
1387 it->dispatch(cur, fr);
1392 case LFUN_LANGUAGE_BUFFER: {
1393 Buffer & buffer = *owner->buffer();
1394 Language const * oldL = buffer.params().language;
1395 Language const * newL = languages.getLanguage(argument);
1396 if (!newL || oldL == newL)
1399 if (oldL->RightToLeft() == newL->RightToLeft()
1400 && !buffer.isMultiLingual())
1401 buffer.changeLanguage(oldL, newL);
1403 buffer.updateDocLang(newL);
1407 case LFUN_SAVE_AS_DEFAULT: {
1408 string const fname =
1409 AddName(AddPath(package().user_support(), "templates/"),
1411 Buffer defaults(fname);
1413 istringstream ss(argument);
1416 int const unknown_tokens = defaults.readHeader(lex);
1418 if (unknown_tokens != 0) {
1419 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1420 << unknown_tokens << " unknown token"
1421 << (unknown_tokens == 1 ? "" : "s")
1425 if (defaults.writeFile(defaults.fileName()))
1426 setMessage(_("Document defaults saved in ")
1427 + MakeDisplayPath(fname));
1429 setErrorMessage(_("Unable to save document defaults"));
1433 case LFUN_BUFFERPARAMS_APPLY: {
1434 biblio::CiteEngine const engine =
1435 owner->buffer()->params().cite_engine;
1437 istringstream ss(argument);
1440 int const unknown_tokens =
1441 owner->buffer()->readHeader(lex);
1443 if (unknown_tokens != 0) {
1444 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1445 << unknown_tokens << " unknown token"
1446 << (unknown_tokens == 1 ? "" : "s")
1449 if (engine == owner->buffer()->params().cite_engine)
1452 LCursor & cur = view()->cursor();
1453 FuncRequest fr(LFUN_INSET_REFRESH);
1455 InsetBase & inset = owner->buffer()->inset();
1456 InsetIterator it = inset_iterator_begin(inset);
1457 InsetIterator const end = inset_iterator_end(inset);
1458 for (; it != end; ++it)
1459 if (it->lyxCode() == InsetBase::CITE_CODE)
1460 it->dispatch(cur, fr);
1464 case LFUN_TEXTCLASS_APPLY: {
1465 Buffer * buffer = owner->buffer();
1467 lyx::textclass_type const old_class =
1468 buffer->params().textclass;
1470 loadTextclass(argument);
1472 std::pair<bool, lyx::textclass_type> const tc_pair =
1473 textclasslist.NumberOfClass(argument);
1478 lyx::textclass_type const new_class = tc_pair.second;
1479 if (old_class == new_class)
1483 owner->message(_("Converting document to new document class..."));
1485 lyx::cap::SwitchLayoutsBetweenClasses(
1486 old_class, new_class,
1487 buffer->paragraphs(), el);
1489 bufferErrors(*buffer, el);
1490 view()->showErrorList(_("Class switch"));
1494 case LFUN_TEXTCLASS_LOAD:
1495 loadTextclass(argument);
1498 case LFUN_LYXRC_APPLY: {
1499 LyXRC const lyxrc_orig = lyxrc;
1501 istringstream ss(argument);
1502 bool const success = lyxrc.read(ss) == 0;
1505 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1506 << "Unable to read lyxrc data"
1511 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1516 view()->cursor().dispatch(cmd);
1517 update |= view()->cursor().result().update();
1518 if (!view()->cursor().result().dispatched()) {
1519 update |= view()->dispatch(cmd);
1526 if (view()->available()) {
1527 // Redraw screen unless explicitly told otherwise.
1528 // This also initializes the position cache for all insets
1529 // in (at least partially) visible top-level paragraphs.
1530 view()->update(true, update);
1532 // if we executed a mutating lfun, mark the buffer as dirty
1533 if (getStatus(cmd).enabled()
1534 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1535 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1536 view()->buffer()->markDirty();
1539 if (view()->cursor().inTexted()) {
1540 view()->owner()->updateLayoutChoice();
1543 sendDispatchMessage(getMessage(), cmd);
1547 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1549 owner->updateMenubar();
1550 owner->updateToolbars();
1552 const bool verbose = (cmd.origin == FuncRequest::UI
1553 || cmd.origin == FuncRequest::COMMANDBUFFER);
1555 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1556 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1558 owner->message(msg);
1562 string dispatch_msg = msg;
1563 if (!dispatch_msg.empty())
1564 dispatch_msg += ' ';
1566 string comname = lyxaction.getActionName(cmd.action);
1568 bool argsadded = false;
1570 if (!cmd.argument.empty()) {
1571 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1572 comname += ' ' + cmd.argument;
1577 string const shortcuts = toplevel_keymap->printbindings(cmd);
1579 if (!shortcuts.empty()) {
1580 comname += ": " + shortcuts;
1581 } else if (!argsadded && !cmd.argument.empty()) {
1582 comname += ' ' + cmd.argument;
1585 if (!comname.empty()) {
1586 comname = rtrim(comname);
1587 dispatch_msg += '(' + comname + ')';
1590 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1591 if (!dispatch_msg.empty())
1592 owner->message(dispatch_msg);
1596 void LyXFunc::setupLocalKeymap()
1598 keyseq.stdmap = toplevel_keymap.get();
1599 keyseq.curmap = toplevel_keymap.get();
1600 cancel_meta_seq.stdmap = toplevel_keymap.get();
1601 cancel_meta_seq.curmap = toplevel_keymap.get();
1605 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1607 string initpath = lyxrc.document_path;
1608 string filename(name);
1610 if (view()->available()) {
1611 string const trypath = owner->buffer()->filePath();
1612 // If directory is writeable, use this as default.
1613 if (IsDirWriteable(trypath))
1617 static int newfile_number;
1619 if (filename.empty()) {
1620 filename = AddName(lyxrc.document_path,
1621 "newfile" + convert<string>(++newfile_number) + ".lyx");
1622 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1624 filename = AddName(lyxrc.document_path,
1625 "newfile" + convert<string>(newfile_number) +
1630 // The template stuff
1633 FileDialog fileDlg(_("Select template file"),
1634 LFUN_SELECT_FILE_SYNC,
1635 make_pair(string(_("Documents|#o#O")),
1636 string(lyxrc.document_path)),
1637 make_pair(string(_("Templates|#T#t")),
1638 string(lyxrc.template_path)));
1640 FileDialog::Result result =
1641 fileDlg.open(lyxrc.template_path,
1642 FileFilterList(_("LyX Documents (*.lyx)")),
1645 if (result.first == FileDialog::Later)
1647 if (result.second.empty())
1649 templname = result.second;
1652 view()->newFile(filename, templname, !name.empty());
1656 void LyXFunc::open(string const & fname)
1658 string initpath = lyxrc.document_path;
1660 if (view()->available()) {
1661 string const trypath = owner->buffer()->filePath();
1662 // If directory is writeable, use this as default.
1663 if (IsDirWriteable(trypath))
1669 if (fname.empty()) {
1670 FileDialog fileDlg(_("Select document to open"),
1672 make_pair(string(_("Documents|#o#O")),
1673 string(lyxrc.document_path)),
1674 make_pair(string(_("Examples|#E#e")),
1675 string(AddPath(package().system_support(), "examples"))));
1677 FileDialog::Result result =
1678 fileDlg.open(initpath,
1679 FileFilterList(_("LyX Documents (*.lyx)")),
1682 if (result.first == FileDialog::Later)
1685 filename = result.second;
1687 // check selected filename
1688 if (filename.empty()) {
1689 owner->message(_("Canceled."));
1695 // get absolute path of file and add ".lyx" to the filename if
1697 string const fullpath = FileSearch(string(), filename, "lyx");
1698 if (!fullpath.empty()) {
1699 filename = fullpath;
1702 string const disp_fn(MakeDisplayPath(filename));
1704 // if the file doesn't exist, let the user create one
1705 if (!fs::exists(filename)) {
1706 // the user specifically chose this name. Believe them.
1707 view()->newFile(filename, "", true);
1711 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1714 if (view()->loadLyXFile(filename)) {
1715 str2 = bformat(_("Document %1$s opened."), disp_fn);
1717 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1719 owner->message(str2);
1723 void LyXFunc::doImport(string const & argument)
1726 string filename = split(argument, format, ' ');
1728 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1729 << " file: " << filename << endl;
1731 // need user interaction
1732 if (filename.empty()) {
1733 string initpath = lyxrc.document_path;
1735 if (view()->available()) {
1736 string const trypath = owner->buffer()->filePath();
1737 // If directory is writeable, use this as default.
1738 if (IsDirWriteable(trypath))
1742 string const text = bformat(_("Select %1$s file to import"),
1743 formats.prettyName(format));
1745 FileDialog fileDlg(text,
1747 make_pair(string(_("Documents|#o#O")),
1748 string(lyxrc.document_path)),
1749 make_pair(string(_("Examples|#E#e")),
1750 string(AddPath(package().system_support(), "examples"))));
1752 string const filter = formats.prettyName(format)
1753 + " (*." + formats.extension(format) + ')';
1755 FileDialog::Result result =
1756 fileDlg.open(initpath,
1757 FileFilterList(filter),
1760 if (result.first == FileDialog::Later)
1763 filename = result.second;
1765 // check selected filename
1766 if (filename.empty())
1767 owner->message(_("Canceled."));
1770 if (filename.empty())
1773 // get absolute path of file
1774 filename = MakeAbsPath(filename);
1776 string const lyxfile = ChangeExtension(filename, ".lyx");
1778 // Check if the document already is open
1779 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1780 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1781 owner->message(_("Canceled."));
1786 // if the file exists already, and we didn't do
1787 // -i lyx thefile.lyx, warn
1788 if (fs::exists(lyxfile) && filename != lyxfile) {
1789 string const file = MakeDisplayPath(lyxfile, 30);
1791 string text = bformat(_("The document %1$s already exists.\n\n"
1792 "Do you want to over-write that document?"), file);
1793 int const ret = Alert::prompt(_("Over-write document?"),
1794 text, 0, 1, _("&Over-write"), _("&Cancel"));
1797 owner->message(_("Canceled."));
1802 Importer::Import(owner, filename, format);
1806 void LyXFunc::closeBuffer()
1808 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1809 if (bufferlist.empty()) {
1810 // need this otherwise SEGV may occur while
1811 // trying to set variables that don't exist
1812 // since there's no current buffer
1813 owner->getDialogs().hideBufferDependent();
1815 view()->setBuffer(bufferlist.first());
1821 // Each "owner" should have it's own message method. lyxview and
1822 // the minibuffer would use the minibuffer, but lyxserver would
1823 // send an ERROR signal to its client. Alejandro 970603
1824 // This function is bit problematic when it comes to NLS, to make the
1825 // lyx servers client be language indepenent we must not translate
1826 // strings sent to this func.
1827 void LyXFunc::setErrorMessage(string const & m) const
1829 dispatch_buffer = m;
1834 void LyXFunc::setMessage(string const & m) const
1836 dispatch_buffer = m;
1840 string const LyXFunc::viewStatusMessage()
1842 // When meta-fake key is pressed, show the key sequence so far + "M-".
1844 return keyseq.print() + "M-";
1846 // Else, when a non-complete key sequence is pressed,
1847 // show the available options.
1848 if (keyseq.length() > 0 && !keyseq.deleted())
1849 return keyseq.printOptions();
1851 if (!view()->available())
1852 return _("Welcome to LyX!");
1854 return view()->cursor().currentState();
1858 BufferView * LyXFunc::view() const
1860 BOOST_ASSERT(owner);
1861 return owner->view().get();
1865 bool LyXFunc::wasMetaKey() const
1867 return (meta_fake_bit != key_modifier::none);
1873 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1875 // Why the switch you might ask. It is a trick to ensure that all
1876 // the elements in the LyXRCTags enum is handled. As you can see
1877 // there are no breaks at all. So it is just a huge fall-through.
1878 // The nice thing is that we will get a warning from the compiler
1879 // if we forget an element.
1880 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1882 case LyXRC::RC_ACCEPT_COMPOUND:
1883 case LyXRC::RC_ALT_LANG:
1884 case LyXRC::RC_ASCIIROFF_COMMAND:
1885 case LyXRC::RC_ASCII_LINELEN:
1886 case LyXRC::RC_AUTOREGIONDELETE:
1887 case LyXRC::RC_AUTORESET_OPTIONS:
1888 case LyXRC::RC_AUTOSAVE:
1889 case LyXRC::RC_AUTO_NUMBER:
1890 case LyXRC::RC_BACKUPDIR_PATH:
1891 case LyXRC::RC_BIBTEX_COMMAND:
1892 case LyXRC::RC_BINDFILE:
1893 case LyXRC::RC_CHECKLASTFILES:
1894 case LyXRC::RC_CHKTEX_COMMAND:
1895 case LyXRC::RC_CONVERTER:
1896 case LyXRC::RC_COPIER:
1897 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1898 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1899 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1900 case LyXRC::RC_CYGWIN_PATH_FIX:
1901 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1902 namespace os = lyx::support::os;
1903 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1905 case LyXRC::RC_DATE_INSERT_FORMAT:
1906 case LyXRC::RC_DEFAULT_LANGUAGE:
1907 case LyXRC::RC_DEFAULT_PAPERSIZE:
1908 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1909 case LyXRC::RC_DISPLAY_GRAPHICS:
1910 case LyXRC::RC_DOCUMENTPATH:
1911 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1912 if (fs::exists(lyxrc_new.document_path) &&
1913 fs::is_directory(lyxrc_new.document_path)) {
1914 using lyx::support::package;
1915 package().document_dir() = lyxrc.document_path;
1918 case LyXRC::RC_ESC_CHARS:
1919 case LyXRC::RC_FONT_ENCODING:
1920 case LyXRC::RC_FORMAT:
1921 case LyXRC::RC_INDEX_COMMAND:
1922 case LyXRC::RC_INPUT:
1923 case LyXRC::RC_KBMAP:
1924 case LyXRC::RC_KBMAP_PRIMARY:
1925 case LyXRC::RC_KBMAP_SECONDARY:
1926 case LyXRC::RC_LABEL_INIT_LENGTH:
1927 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1928 case LyXRC::RC_LANGUAGE_AUTO_END:
1929 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1930 case LyXRC::RC_LANGUAGE_COMMAND_END:
1931 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1932 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1933 case LyXRC::RC_LANGUAGE_PACKAGE:
1934 case LyXRC::RC_LANGUAGE_USE_BABEL:
1935 case LyXRC::RC_LASTFILES:
1936 case LyXRC::RC_MAKE_BACKUP:
1937 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1938 case LyXRC::RC_NUMLASTFILES:
1939 case LyXRC::RC_PATH_PREFIX:
1940 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1941 using lyx::support::prependEnvPath;
1942 prependEnvPath("PATH", lyxrc.path_prefix);
1944 case LyXRC::RC_PERS_DICT:
1945 case LyXRC::RC_POPUP_BOLD_FONT:
1946 case LyXRC::RC_POPUP_FONT_ENCODING:
1947 case LyXRC::RC_POPUP_NORMAL_FONT:
1948 case LyXRC::RC_PREVIEW:
1949 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1950 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1951 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1952 case LyXRC::RC_PRINTCOPIESFLAG:
1953 case LyXRC::RC_PRINTER:
1954 case LyXRC::RC_PRINTEVENPAGEFLAG:
1955 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1956 case LyXRC::RC_PRINTFILEEXTENSION:
1957 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1958 case LyXRC::RC_PRINTODDPAGEFLAG:
1959 case LyXRC::RC_PRINTPAGERANGEFLAG:
1960 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1961 case LyXRC::RC_PRINTPAPERFLAG:
1962 case LyXRC::RC_PRINTREVERSEFLAG:
1963 case LyXRC::RC_PRINTSPOOL_COMMAND:
1964 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1965 case LyXRC::RC_PRINTTOFILE:
1966 case LyXRC::RC_PRINTTOPRINTER:
1967 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1968 case LyXRC::RC_PRINT_COMMAND:
1969 case LyXRC::RC_RTL_SUPPORT:
1970 case LyXRC::RC_SCREEN_DPI:
1971 case LyXRC::RC_SCREEN_FONT_ENCODING:
1972 case LyXRC::RC_SCREEN_FONT_ROMAN:
1973 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1974 case LyXRC::RC_SCREEN_FONT_SANS:
1975 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1976 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1977 case LyXRC::RC_SCREEN_FONT_SIZES:
1978 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1979 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1980 case LyXRC::RC_SCREEN_ZOOM:
1981 case LyXRC::RC_SERVERPIPE:
1982 case LyXRC::RC_SET_COLOR:
1983 case LyXRC::RC_SHOW_BANNER:
1984 case LyXRC::RC_SPELL_COMMAND:
1985 case LyXRC::RC_TEMPDIRPATH:
1986 case LyXRC::RC_TEMPLATEPATH:
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: