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 InsetBase::Code code = cur.inset().lyxCode();
433 case InsetBase::TABULAR_CODE:
434 enable = cmd.argument == "tabular";
436 case InsetBase::ERT_CODE:
437 enable = cmd.argument == "ert";
439 case InsetBase::FLOAT_CODE:
440 enable = cmd.argument == "float";
442 case InsetBase::WRAP_CODE:
443 enable = cmd.argument == "wrap";
445 case InsetBase::NOTE_CODE:
446 enable = cmd.argument == "note";
448 case InsetBase::BRANCH_CODE:
449 enable = cmd.argument == "branch";
451 case InsetBase::BOX_CODE:
452 enable = cmd.argument == "box";
460 case LFUN_INSET_APPLY: {
461 string const name = cmd.getArg(0);
462 InsetBase * inset = owner->getDialogs().getOpenInset(name);
464 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
466 bool const success = inset->getStatus(cur, fr, fs);
467 // Every inset is supposed to handle this
468 BOOST_ASSERT(success);
471 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
472 flag |= getStatus(fr);
474 enable = flag.enabled();
478 case LFUN_DIALOG_SHOW: {
479 string const name = cmd.getArg(0);
481 enable = name == "aboutlyx"
485 || name == "texinfo";
486 else if (name == "print")
487 enable = Exporter::IsExportable(*buf, "dvi")
488 && lyxrc.print_command != "none";
489 else if (name == "character" || name == "mathpanel")
490 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
491 else if (name == "latexlog")
492 enable = IsFileReadable(buf->getLogName().second);
493 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
494 else if (name == "spellchecker")
497 else if (name == "vclog")
498 enable = buf->lyxvc().inUse();
502 case LFUN_DIALOG_SHOW_NEW_INSET:
503 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
506 case LFUN_DIALOG_UPDATE: {
507 string const name = cmd.getArg(0);
509 enable = name == "prefs";
513 // this one is difficult to get right. As a half-baked
514 // solution, we consider only the first action of the sequence
515 case LFUN_SEQUENCE: {
516 // argument contains ';'-terminated commands
517 string const firstcmd = token(cmd.argument, ';', 0);
518 FuncRequest func(lyxaction.lookupFunc(firstcmd));
519 func.origin = cmd.origin;
520 flag = getStatus(func);
524 case LFUN_MENUNEWTMPLT:
525 case LFUN_WORDFINDFORWARD:
526 case LFUN_WORDFINDBACKWARD:
528 case LFUN_EXEC_COMMAND:
531 case LFUN_CLOSEBUFFER:
540 case LFUN_RECONFIGURE:
544 case LFUN_DROP_LAYOUTS_CHOICE:
545 case LFUN_MENU_OPEN_BY_NAME:
548 case LFUN_GOTOFILEROW:
549 case LFUN_DIALOG_SHOW_NEXT_INSET:
550 case LFUN_DIALOG_HIDE:
551 case LFUN_DIALOG_DISCONNECT_INSET:
553 case LFUN_TOGGLECURSORFOLLOW:
557 case LFUN_KMAP_TOGGLE:
559 case LFUN_EXPORT_CUSTOM:
561 case LFUN_SAVEPREFERENCES:
562 case LFUN_SCREEN_FONT_UPDATE:
565 case LFUN_EXTERNAL_EDIT:
566 case LFUN_GRAPHICS_EDIT:
567 case LFUN_ALL_INSETS_TOGGLE:
568 case LFUN_LANGUAGE_BUFFER:
569 case LFUN_TEXTCLASS_APPLY:
570 case LFUN_TEXTCLASS_LOAD:
571 case LFUN_SAVE_AS_DEFAULT:
572 case LFUN_BUFFERPARAMS_APPLY:
573 case LFUN_LYXRC_APPLY:
574 case LFUN_NEXTBUFFER:
575 case LFUN_PREVIOUSBUFFER:
576 // these are handled in our dispatch()
581 if (!::getStatus(cur, cmd, flag))
582 flag = view()->getStatus(cmd);
588 // Can we use a readonly buffer?
589 if (buf && buf->isReadonly()
590 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
591 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
592 flag.message(N_("Document is read-only"));
596 // the default error message if we disable the command
597 if (!flag.enabled() && flag.message().empty())
598 flag.message(N_("Command disabled"));
606 bool ensureBufferClean(BufferView * bv)
608 Buffer & buf = *bv->buffer();
612 string const file = MakeDisplayPath(buf.fileName(), 30);
613 string text = bformat(_("The document %1$s has unsaved "
614 "changes.\n\nDo you want to save "
615 "the document?"), file);
616 int const ret = Alert::prompt(_("Save changed document?"),
617 text, 0, 1, _("&Save"),
621 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
623 return buf.isClean();
627 void showPrintError(string const & name)
629 string str = bformat(_("Could not print the document %1$s.\n"
630 "Check that your printer is set up correctly."),
631 MakeDisplayPath(name, 50));
632 Alert::error(_("Print document failed"), str);
636 void loadTextclass(string const & name)
638 std::pair<bool, lyx::textclass_type> const tc_pair =
639 textclasslist.NumberOfClass(name);
641 if (!tc_pair.first) {
642 lyxerr << "Document class \"" << name
643 << "\" does not exist."
648 lyx::textclass_type const tc = tc_pair.second;
650 if (!textclasslist[tc].load()) {
651 string s = bformat(_("The document could not be converted\n"
652 "into the document class %1$s."),
653 textclasslist[tc].name());
654 Alert::error(_("Could not change class"), s);
659 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
664 void LyXFunc::dispatch(FuncRequest const & cmd)
666 BOOST_ASSERT(view());
667 string const argument = cmd.argument;
668 kb_action const action = cmd.action;
670 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
671 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
673 // we have not done anything wrong yet.
675 dispatch_buffer.erase();
679 FuncStatus const flag = getStatus(cmd);
680 if (!flag.enabled()) {
681 // We cannot use this function here
682 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
683 << lyxaction.getActionName(action)
684 << " [" << action << "] is disabled at this location"
686 setErrorMessage(flag.message());
689 if (view()->available())
690 view()->hideCursor();
694 case LFUN_WORDFINDFORWARD:
695 case LFUN_WORDFINDBACKWARD: {
696 static string last_search;
697 string searched_string;
699 if (!argument.empty()) {
700 last_search = argument;
701 searched_string = argument;
703 searched_string = last_search;
706 if (searched_string.empty())
709 bool const fw = action == LFUN_WORDFINDFORWARD;
711 lyx::find::find2string(searched_string, true, false, fw);
712 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
717 owner->message(keyseq.printOptions());
720 case LFUN_EXEC_COMMAND:
721 owner->getToolbars().display("minibuffer", true);
722 owner->focus_command_buffer();
727 meta_fake_bit = key_modifier::none;
728 if (view()->available())
729 // cancel any selection
730 dispatch(FuncRequest(LFUN_MARK_OFF));
731 setMessage(N_("Cancel"));
735 meta_fake_bit = key_modifier::alt;
736 setMessage(keyseq.print());
739 case LFUN_READ_ONLY_TOGGLE:
740 if (owner->buffer()->lyxvc().inUse())
741 owner->buffer()->lyxvc().toggleReadOnly();
743 owner->buffer()->setReadonly(
744 !owner->buffer()->isReadonly());
747 // --- Menus -----------------------------------------------
749 menuNew(argument, false);
752 case LFUN_MENUNEWTMPLT:
753 menuNew(argument, true);
756 case LFUN_CLOSEBUFFER:
761 if (!owner->buffer()->isUnnamed()) {
762 string const str = bformat(_("Saving document %1$s..."),
763 MakeDisplayPath(owner->buffer()->fileName()));
765 MenuWrite(owner->buffer());
766 owner->message(str + _(" done."));
768 WriteAs(owner->buffer());
772 WriteAs(owner->buffer(), argument);
775 case LFUN_MENURELOAD: {
776 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
777 string text = bformat(_("Any changes will be lost. Are you sure "
778 "you want to revert to the saved version of the document %1$s?"), file);
779 int const ret = Alert::prompt(_("Revert to saved document?"),
780 text, 0, 1, _("&Revert"), _("&Cancel"));
788 Exporter::Export(owner->buffer(), argument, true);
789 view()->showErrorList(BufferFormat(*owner->buffer()));
793 Exporter::Preview(owner->buffer(), argument);
794 view()->showErrorList(BufferFormat(*owner->buffer()));
798 Exporter::Export(owner->buffer(), "program", true);
799 view()->showErrorList(_("Build"));
803 owner->buffer()->runChktex();
804 view()->showErrorList(_("ChkTeX"));
808 if (argument == "custom")
809 owner->getDialogs().show("sendto");
811 Exporter::Export(owner->buffer(), argument, false);
812 view()->showErrorList(BufferFormat(*owner->buffer()));
816 case LFUN_EXPORT_CUSTOM: {
818 string command = split(argument, format_name, ' ');
819 Format const * format = formats.getFormat(format_name);
821 lyxerr << "Format \"" << format_name
822 << "\" not recognized!"
827 Buffer * buffer = owner->buffer();
829 // The name of the file created by the conversion process
832 // Output to filename
833 if (format->name() == "lyx") {
834 string const latexname =
835 buffer->getLatexName(false);
836 filename = ChangeExtension(latexname,
837 format->extension());
838 filename = AddName(buffer->temppath(), filename);
840 if (!buffer->writeFile(filename))
844 Exporter::Export(buffer, format_name, true,
848 // Substitute $$FName for filename
849 if (!contains(command, "$$FName"))
850 command = "( " + command + " ) < $$FName";
851 command = subst(command, "$$FName", filename);
853 // Execute the command in the background
855 call.startscript(Systemcall::DontWait, command);
862 string command = split(split(argument, target, ' '),
866 || target_name.empty()
867 || command.empty()) {
868 lyxerr << "Unable to parse \""
869 << argument << '"' << std::endl;
872 if (target != "printer" && target != "file") {
873 lyxerr << "Unrecognized target \""
874 << target << '"' << std::endl;
878 Buffer * buffer = owner->buffer();
880 if (!Exporter::Export(buffer, "dvi", true)) {
881 showPrintError(buffer->fileName());
885 // Push directory path.
886 string const path = buffer->temppath();
889 // there are three cases here:
890 // 1. we print to a file
891 // 2. we print directly to a printer
892 // 3. we print using a spool command (print to file first)
895 string const dviname =
896 ChangeExtension(buffer->getLatexName(true),
899 if (target == "printer") {
900 if (!lyxrc.print_spool_command.empty()) {
901 // case 3: print using a spool
902 string const psname =
903 ChangeExtension(dviname,".ps");
904 command += lyxrc.print_to_file
907 + QuoteName(dviname);
910 lyxrc.print_spool_command +' ';
911 if (target_name != "default") {
912 command2 += lyxrc.print_spool_printerprefix
916 command2 += QuoteName(psname);
918 // If successful, then spool command
919 res = one.startscript(
924 res = one.startscript(
925 Systemcall::DontWait,
928 // case 2: print directly to a printer
929 res = one.startscript(
930 Systemcall::DontWait,
931 command + QuoteName(dviname));
935 // case 1: print to a file
936 command += lyxrc.print_to_file
937 + QuoteName(MakeAbsPath(target_name,
940 + QuoteName(dviname);
941 res = one.startscript(Systemcall::DontWait,
946 showPrintError(buffer->fileName());
955 QuitLyX(argument == "force");
959 InsetCommandParams p("tableofcontents");
960 string const data = InsetCommandMailer::params2string("toc", p);
961 owner->getDialogs().show("toc", data, 0);
969 case LFUN_RECONFIGURE:
973 case LFUN_HELP_OPEN: {
974 string const arg = argument;
976 setErrorMessage(N_("Missing argument"));
979 string const fname = i18nLibFileSearch("doc", arg, "lyx");
981 lyxerr << "LyX: unable to find documentation file `"
982 << arg << "'. Bad installation?" << endl;
985 owner->message(bformat(_("Opening help file %1$s..."),
986 MakeDisplayPath(fname)));
987 view()->loadLyXFile(fname, false);
991 // --- version control -------------------------------
992 case LFUN_VC_REGISTER:
993 if (!ensureBufferClean(view()))
995 if (!owner->buffer()->lyxvc().inUse()) {
996 owner->buffer()->lyxvc().registrer();
1001 case LFUN_VC_CHECKIN:
1002 if (!ensureBufferClean(view()))
1004 if (owner->buffer()->lyxvc().inUse()
1005 && !owner->buffer()->isReadonly()) {
1006 owner->buffer()->lyxvc().checkIn();
1011 case LFUN_VC_CHECKOUT:
1012 if (!ensureBufferClean(view()))
1014 if (owner->buffer()->lyxvc().inUse()
1015 && owner->buffer()->isReadonly()) {
1016 owner->buffer()->lyxvc().checkOut();
1021 case LFUN_VC_REVERT:
1022 owner->buffer()->lyxvc().revert();
1027 owner->buffer()->lyxvc().undoLast();
1031 // --- buffers ----------------------------------------
1032 case LFUN_SWITCHBUFFER:
1033 view()->setBuffer(bufferlist.getBuffer(argument));
1036 case LFUN_NEXTBUFFER:
1037 view()->setBuffer(bufferlist.next(view()->buffer()));
1040 case LFUN_PREVIOUSBUFFER:
1041 view()->setBuffer(bufferlist.previous(view()->buffer()));
1045 NewFile(view(), argument);
1048 case LFUN_FILE_OPEN:
1052 case LFUN_DROP_LAYOUTS_CHOICE:
1053 owner->getToolbars().openLayoutList();
1056 case LFUN_MENU_OPEN_BY_NAME:
1057 owner->getMenubar().openByName(argument);
1060 // --- lyxserver commands ----------------------------
1062 setMessage(owner->buffer()->fileName());
1063 lyxerr[Debug::INFO] << "FNAME["
1064 << owner->buffer()->fileName()
1069 dispatch_buffer = keyseq.print();
1070 lyxserver->notifyClient(dispatch_buffer);
1073 case LFUN_GOTOFILEROW: {
1076 istringstream is(argument);
1077 is >> file_name >> row;
1078 if (prefixIs(file_name, package().temp_dir())) {
1079 // Needed by inverse dvi search. If it is a file
1080 // in tmpdir, call the apropriated function
1081 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1083 // Must replace extension of the file to be .lyx
1084 // and get full path
1085 string const s = ChangeExtension(file_name, ".lyx");
1086 // Either change buffer or load the file
1087 if (bufferlist.exists(s)) {
1088 view()->setBuffer(bufferlist.getBuffer(s));
1090 view()->loadLyXFile(s);
1094 view()->setCursorFromRow(row);
1097 // see BufferView_pimpl::center()
1098 view()->updateScrollbar();
1102 case LFUN_DIALOG_SHOW: {
1103 string const name = cmd.getArg(0);
1104 string data = trim(cmd.argument.substr(name.size()));
1106 if (name == "character") {
1107 data = freefont2string();
1109 owner->getDialogs().show("character", data);
1112 else if (name == "latexlog") {
1113 pair<Buffer::LogType, string> const logfile =
1114 owner->buffer()->getLogName();
1115 switch (logfile.first) {
1116 case Buffer::latexlog:
1119 case Buffer::buildlog:
1123 data += logfile.second;
1124 owner->getDialogs().show("log", data);
1126 else if (name == "vclog") {
1127 string const data = "vc " +
1128 owner->buffer()->lyxvc().getLogFile();
1129 owner->getDialogs().show("log", data);
1132 owner->getDialogs().show(name, data);
1136 case LFUN_DIALOG_SHOW_NEW_INSET: {
1137 string const name = cmd.getArg(0);
1138 string data = trim(cmd.argument.substr(name.size()));
1139 if (name == "bibitem" ||
1141 name == "include" ||
1147 InsetCommandParams p(name);
1148 data = InsetCommandMailer::params2string(name, p);
1149 } else if (name == "box") {
1150 // \c data == "Boxed" || "Frameless" etc
1151 InsetBoxParams p(data);
1152 data = InsetBoxMailer::params2string(p);
1153 } else if (name == "branch") {
1154 InsetBranchParams p;
1155 data = InsetBranchMailer::params2string(p);
1156 } else if (name == "citation") {
1157 InsetCommandParams p("cite");
1158 data = InsetCommandMailer::params2string(name, p);
1159 } else if (name == "ert") {
1160 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1161 } else if (name == "external") {
1162 InsetExternalParams p;
1163 Buffer const & buffer = *owner->buffer();
1164 data = InsetExternalMailer::params2string(p, buffer);
1165 } else if (name == "float") {
1167 data = InsetFloatMailer::params2string(p);
1168 } else if (name == "graphics") {
1169 InsetGraphicsParams p;
1170 Buffer const & buffer = *owner->buffer();
1171 data = InsetGraphicsMailer::params2string(p, buffer);
1172 } else if (name == "note") {
1174 data = InsetNoteMailer::params2string(p);
1175 } else if (name == "vspace") {
1177 data = InsetVSpaceMailer::params2string(space);
1178 } else if (name == "wrap") {
1180 data = InsetWrapMailer::params2string(p);
1182 owner->getDialogs().show(name, data, 0);
1186 case LFUN_DIALOG_SHOW_NEXT_INSET:
1189 case LFUN_DIALOG_UPDATE: {
1190 string const & name = argument;
1191 // Can only update a dialog connected to an existing inset
1192 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1194 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1195 inset->dispatch(view()->cursor(), fr);
1196 } else if (name == "paragraph") {
1197 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1198 } else if (name == "prefs") {
1199 owner->getDialogs().update(name, string());
1204 case LFUN_DIALOG_HIDE:
1205 Dialogs::hide(argument, 0);
1208 case LFUN_DIALOG_DISCONNECT_INSET:
1209 owner->getDialogs().disconnect(argument);
1212 case LFUN_CHILDOPEN: {
1213 string const filename =
1214 MakeAbsPath(argument, owner->buffer()->filePath());
1215 setMessage(N_("Opening child document ") +
1216 MakeDisplayPath(filename) + "...");
1217 view()->savePosition(0);
1218 string const parentfilename = owner->buffer()->fileName();
1219 if (bufferlist.exists(filename))
1220 view()->setBuffer(bufferlist.getBuffer(filename));
1222 view()->loadLyXFile(filename);
1223 // Set the parent name of the child document.
1224 // This makes insertion of citations and references in the child work,
1225 // when the target is in the parent or another child document.
1226 owner->buffer()->setParentName(parentfilename);
1230 case LFUN_TOGGLECURSORFOLLOW:
1231 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1235 owner->getIntl().KeyMapOn(false);
1238 case LFUN_KMAP_PRIM:
1239 owner->getIntl().KeyMapPrim();
1243 owner->getIntl().KeyMapSec();
1246 case LFUN_KMAP_TOGGLE:
1247 owner->getIntl().ToggleKeyMap();
1253 string rest = split(argument, countstr, ' ');
1254 istringstream is(countstr);
1257 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1258 for (int i = 0; i < count; ++i)
1259 dispatch(lyxaction.lookupFunc(rest));
1263 case LFUN_SEQUENCE: {
1264 // argument contains ';'-terminated commands
1265 string arg = argument;
1266 while (!arg.empty()) {
1268 arg = split(arg, first, ';');
1269 FuncRequest func(lyxaction.lookupFunc(first));
1270 func.origin = cmd.origin;
1276 case LFUN_SAVEPREFERENCES: {
1277 Path p(package().user_support());
1278 lyxrc.write("preferences", false);
1282 case LFUN_SCREEN_FONT_UPDATE:
1283 // handle the screen font changes.
1284 lyxrc.set_font_norm_type();
1285 lyx_gui::update_fonts();
1286 // All visible buffers will need resize
1290 case LFUN_SET_COLOR: {
1292 string const x11_name = split(argument, lyx_name, ' ');
1293 if (lyx_name.empty() || x11_name.empty()) {
1294 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1299 bool const graphicsbg_changed =
1300 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1301 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1303 if (!lcolor.setColor(lyx_name, x11_name)) {
1305 bformat(_("Set-color \"%1$s\" failed "
1306 "- color is undefined or "
1307 "may not be redefined"), lyx_name));
1311 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1313 if (graphicsbg_changed) {
1314 #ifdef WITH_WARNINGS
1315 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1318 lyx::graphics::GCache::get().changeDisplay(true);
1325 owner->message(argument);
1328 case LFUN_TOOLTIPS_TOGGLE:
1329 owner->getDialogs().toggleTooltips();
1332 case LFUN_EXTERNAL_EDIT: {
1333 FuncRequest fr(action, argument);
1334 InsetExternal().dispatch(view()->cursor(), fr);
1338 case LFUN_GRAPHICS_EDIT: {
1339 FuncRequest fr(action, argument);
1340 InsetGraphics().dispatch(view()->cursor(), fr);
1344 case LFUN_INSET_APPLY: {
1345 string const name = cmd.getArg(0);
1346 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1348 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1349 inset->dispatch(view()->cursor(), fr);
1351 FuncRequest fr(LFUN_INSET_INSERT, argument);
1354 // ideally, the update flag should be set by the insets,
1355 // but this is not possible currently
1360 case LFUN_ALL_INSETS_TOGGLE: {
1362 string const name = split(argument, action, ' ');
1363 InsetBase::Code const inset_code =
1364 InsetBase::translate(name);
1366 LCursor & cur = view()->cursor();
1367 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1369 InsetBase & inset = owner->buffer()->inset();
1370 InsetIterator it = inset_iterator_begin(inset);
1371 InsetIterator const end = inset_iterator_end(inset);
1372 for (; it != end; ++it) {
1373 if (inset_code == InsetBase::NO_CODE
1374 || inset_code == it->lyxCode())
1375 it->dispatch(cur, fr);
1380 case LFUN_LANGUAGE_BUFFER: {
1381 Buffer & buffer = *owner->buffer();
1382 Language const * oldL = buffer.params().language;
1383 Language const * newL = languages.getLanguage(argument);
1384 if (!newL || oldL == newL)
1387 if (oldL->RightToLeft() == newL->RightToLeft()
1388 && !buffer.isMultiLingual())
1389 buffer.changeLanguage(oldL, newL);
1391 buffer.updateDocLang(newL);
1395 case LFUN_SAVE_AS_DEFAULT: {
1396 string const fname =
1397 AddName(AddPath(package().user_support(), "templates/"),
1399 Buffer defaults(fname);
1401 istringstream ss(argument);
1404 int const unknown_tokens = defaults.readHeader(lex);
1406 if (unknown_tokens != 0) {
1407 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1408 << unknown_tokens << " unknown token"
1409 << (unknown_tokens == 1 ? "" : "s")
1413 if (defaults.writeFile(defaults.fileName()))
1414 setMessage(_("Document defaults saved in ")
1415 + MakeDisplayPath(fname));
1417 setErrorMessage(_("Unable to save document defaults"));
1421 case LFUN_BUFFERPARAMS_APPLY: {
1422 biblio::CiteEngine const engine =
1423 owner->buffer()->params().cite_engine;
1425 istringstream ss(argument);
1428 int const unknown_tokens =
1429 owner->buffer()->readHeader(lex);
1431 if (unknown_tokens != 0) {
1432 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1433 << unknown_tokens << " unknown token"
1434 << (unknown_tokens == 1 ? "" : "s")
1437 if (engine == owner->buffer()->params().cite_engine)
1440 LCursor & cur = view()->cursor();
1441 FuncRequest fr(LFUN_INSET_REFRESH);
1443 InsetBase & inset = owner->buffer()->inset();
1444 InsetIterator it = inset_iterator_begin(inset);
1445 InsetIterator const end = inset_iterator_end(inset);
1446 for (; it != end; ++it)
1447 if (it->lyxCode() == InsetBase::CITE_CODE)
1448 it->dispatch(cur, fr);
1452 case LFUN_TEXTCLASS_APPLY: {
1453 recordUndoFullDocument(view());
1454 Buffer * buffer = owner->buffer();
1456 lyx::textclass_type const old_class =
1457 buffer->params().textclass;
1459 loadTextclass(argument);
1461 std::pair<bool, lyx::textclass_type> const tc_pair =
1462 textclasslist.NumberOfClass(argument);
1467 lyx::textclass_type const new_class = tc_pair.second;
1468 if (old_class == new_class)
1472 owner->message(_("Converting document to new document class..."));
1473 StableDocIterator backcur(view()->cursor());
1475 lyx::cap::SwitchBetweenClasses(
1476 old_class, new_class,
1477 buffer->paragraphs(), el);
1479 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1480 bufferErrors(*buffer, el);
1481 view()->showErrorList(_("Class switch"));
1482 updateCounters(*buffer);
1487 case LFUN_TEXTCLASS_LOAD:
1488 loadTextclass(argument);
1491 case LFUN_LYXRC_APPLY: {
1492 LyXRC const lyxrc_orig = lyxrc;
1494 istringstream ss(argument);
1495 bool const success = lyxrc.read(ss) == 0;
1498 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1499 << "Unable to read lyxrc data"
1504 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1509 view()->cursor().dispatch(cmd);
1510 update |= view()->cursor().result().update();
1511 if (!view()->cursor().result().dispatched())
1512 update |= view()->dispatch(cmd);
1517 if (view()->available()) {
1518 // Redraw screen unless explicitly told otherwise.
1519 // This also initializes the position cache for all insets
1520 // in (at least partially) visible top-level paragraphs.
1522 view()->update(Update::FitCursor | Update::Force);
1524 view()->update(Update::FitCursor);
1526 // if we executed a mutating lfun, mark the buffer as dirty
1527 // FIXME: Why not use flag.enabled() but call getStatus again?
1528 if (getStatus(cmd).enabled()
1529 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1530 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1531 view()->buffer()->markDirty();
1534 if (view()->cursor().inTexted()) {
1535 view()->owner()->updateLayoutChoice();
1538 sendDispatchMessage(_(getMessage()), cmd);
1542 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1544 owner->updateMenubar();
1545 owner->updateToolbars();
1547 const bool verbose = (cmd.origin == FuncRequest::UI
1548 || cmd.origin == FuncRequest::COMMANDBUFFER);
1550 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1551 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1553 owner->message(msg);
1557 string dispatch_msg = msg;
1558 if (!dispatch_msg.empty())
1559 dispatch_msg += ' ';
1561 string comname = lyxaction.getActionName(cmd.action);
1563 bool argsadded = false;
1565 if (!cmd.argument.empty()) {
1566 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1567 comname += ' ' + cmd.argument;
1572 string const shortcuts = toplevel_keymap->printbindings(cmd);
1574 if (!shortcuts.empty())
1575 comname += ": " + shortcuts;
1576 else if (!argsadded && !cmd.argument.empty())
1577 comname += ' ' + cmd.argument;
1579 if (!comname.empty()) {
1580 comname = rtrim(comname);
1581 dispatch_msg += '(' + rtrim(comname) + ')';
1584 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1585 if (!dispatch_msg.empty())
1586 owner->message(dispatch_msg);
1590 void LyXFunc::setupLocalKeymap()
1592 keyseq.stdmap = toplevel_keymap.get();
1593 keyseq.curmap = toplevel_keymap.get();
1594 cancel_meta_seq.stdmap = toplevel_keymap.get();
1595 cancel_meta_seq.curmap = toplevel_keymap.get();
1599 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1601 string initpath = lyxrc.document_path;
1602 string filename(name);
1604 if (view()->available()) {
1605 string const trypath = owner->buffer()->filePath();
1606 // If directory is writeable, use this as default.
1607 if (IsDirWriteable(trypath))
1611 static int newfile_number;
1613 if (filename.empty()) {
1614 filename = AddName(lyxrc.document_path,
1615 "newfile" + convert<string>(++newfile_number) + ".lyx");
1616 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1618 filename = AddName(lyxrc.document_path,
1619 "newfile" + convert<string>(newfile_number) +
1624 // The template stuff
1627 FileDialog fileDlg(_("Select template file"),
1628 LFUN_SELECT_FILE_SYNC,
1629 make_pair(string(_("Documents|#o#O")),
1630 string(lyxrc.document_path)),
1631 make_pair(string(_("Templates|#T#t")),
1632 string(lyxrc.template_path)));
1634 FileDialog::Result result =
1635 fileDlg.open(lyxrc.template_path,
1636 FileFilterList(_("LyX Documents (*.lyx)")),
1639 if (result.first == FileDialog::Later)
1641 if (result.second.empty())
1643 templname = result.second;
1646 view()->newFile(filename, templname, !name.empty());
1650 void LyXFunc::open(string const & fname)
1652 string initpath = lyxrc.document_path;
1654 if (view()->available()) {
1655 string const trypath = owner->buffer()->filePath();
1656 // If directory is writeable, use this as default.
1657 if (IsDirWriteable(trypath))
1663 if (fname.empty()) {
1664 FileDialog fileDlg(_("Select document to open"),
1666 make_pair(string(_("Documents|#o#O")),
1667 string(lyxrc.document_path)),
1668 make_pair(string(_("Examples|#E#e")),
1669 string(AddPath(package().system_support(), "examples"))));
1671 FileDialog::Result result =
1672 fileDlg.open(initpath,
1673 FileFilterList(_("LyX Documents (*.lyx)")),
1676 if (result.first == FileDialog::Later)
1679 filename = result.second;
1681 // check selected filename
1682 if (filename.empty()) {
1683 owner->message(_("Canceled."));
1689 // get absolute path of file and add ".lyx" to the filename if
1691 string const fullpath = FileSearch(string(), filename, "lyx");
1692 if (!fullpath.empty()) {
1693 filename = fullpath;
1696 string const disp_fn(MakeDisplayPath(filename));
1698 // if the file doesn't exist, let the user create one
1699 if (!fs::exists(filename)) {
1700 // the user specifically chose this name. Believe them.
1701 view()->newFile(filename, "", true);
1705 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1708 if (view()->loadLyXFile(filename)) {
1709 str2 = bformat(_("Document %1$s opened."), disp_fn);
1711 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1713 owner->message(str2);
1717 void LyXFunc::doImport(string const & argument)
1720 string filename = split(argument, format, ' ');
1722 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1723 << " file: " << filename << endl;
1725 // need user interaction
1726 if (filename.empty()) {
1727 string initpath = lyxrc.document_path;
1729 if (view()->available()) {
1730 string const trypath = owner->buffer()->filePath();
1731 // If directory is writeable, use this as default.
1732 if (IsDirWriteable(trypath))
1736 string const text = bformat(_("Select %1$s file to import"),
1737 formats.prettyName(format));
1739 FileDialog fileDlg(text,
1741 make_pair(string(_("Documents|#o#O")),
1742 string(lyxrc.document_path)),
1743 make_pair(string(_("Examples|#E#e")),
1744 string(AddPath(package().system_support(), "examples"))));
1746 string const filter = formats.prettyName(format)
1747 + " (*." + formats.extension(format) + ')';
1749 FileDialog::Result result =
1750 fileDlg.open(initpath,
1751 FileFilterList(filter),
1754 if (result.first == FileDialog::Later)
1757 filename = result.second;
1759 // check selected filename
1760 if (filename.empty())
1761 owner->message(_("Canceled."));
1764 if (filename.empty())
1767 // get absolute path of file
1768 filename = MakeAbsPath(filename);
1770 string const lyxfile = ChangeExtension(filename, ".lyx");
1772 // Check if the document already is open
1773 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1774 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1775 owner->message(_("Canceled."));
1780 // if the file exists already, and we didn't do
1781 // -i lyx thefile.lyx, warn
1782 if (fs::exists(lyxfile) && filename != lyxfile) {
1783 string const file = MakeDisplayPath(lyxfile, 30);
1785 string text = bformat(_("The document %1$s already exists.\n\n"
1786 "Do you want to over-write that document?"), file);
1787 int const ret = Alert::prompt(_("Over-write document?"),
1788 text, 0, 1, _("&Over-write"), _("&Cancel"));
1791 owner->message(_("Canceled."));
1796 Importer::Import(owner, filename, format);
1800 void LyXFunc::closeBuffer()
1802 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1803 if (bufferlist.empty()) {
1804 // need this otherwise SEGV may occur while
1805 // trying to set variables that don't exist
1806 // since there's no current buffer
1807 owner->getDialogs().hideBufferDependent();
1809 view()->setBuffer(bufferlist.first());
1815 // Each "owner" should have it's own message method. lyxview and
1816 // the minibuffer would use the minibuffer, but lyxserver would
1817 // send an ERROR signal to its client. Alejandro 970603
1818 // This function is bit problematic when it comes to NLS, to make the
1819 // lyx servers client be language indepenent we must not translate
1820 // strings sent to this func.
1821 void LyXFunc::setErrorMessage(string const & m) const
1823 dispatch_buffer = m;
1828 void LyXFunc::setMessage(string const & m) const
1830 dispatch_buffer = m;
1834 string const LyXFunc::viewStatusMessage()
1836 // When meta-fake key is pressed, show the key sequence so far + "M-".
1838 return keyseq.print() + "M-";
1840 // Else, when a non-complete key sequence is pressed,
1841 // show the available options.
1842 if (keyseq.length() > 0 && !keyseq.deleted())
1843 return keyseq.printOptions();
1845 if (!view()->available())
1846 return _("Welcome to LyX!");
1848 return view()->cursor().currentState();
1852 BufferView * LyXFunc::view() const
1854 BOOST_ASSERT(owner);
1855 return owner->view().get();
1859 bool LyXFunc::wasMetaKey() const
1861 return (meta_fake_bit != key_modifier::none);
1867 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1869 // Why the switch you might ask. It is a trick to ensure that all
1870 // the elements in the LyXRCTags enum is handled. As you can see
1871 // there are no breaks at all. So it is just a huge fall-through.
1872 // The nice thing is that we will get a warning from the compiler
1873 // if we forget an element.
1874 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1876 case LyXRC::RC_ACCEPT_COMPOUND:
1877 case LyXRC::RC_ALT_LANG:
1878 case LyXRC::RC_ASCIIROFF_COMMAND:
1879 case LyXRC::RC_ASCII_LINELEN:
1880 case LyXRC::RC_AUTOREGIONDELETE:
1881 case LyXRC::RC_AUTORESET_OPTIONS:
1882 case LyXRC::RC_AUTOSAVE:
1883 case LyXRC::RC_AUTO_NUMBER:
1884 case LyXRC::RC_BACKUPDIR_PATH:
1885 case LyXRC::RC_BIBTEX_COMMAND:
1886 case LyXRC::RC_BINDFILE:
1887 case LyXRC::RC_CHECKLASTFILES:
1888 case LyXRC::RC_CHKTEX_COMMAND:
1889 case LyXRC::RC_CONVERTER:
1890 case LyXRC::RC_COPIER:
1891 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1892 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1893 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1894 case LyXRC::RC_CYGWIN_PATH_FIX:
1895 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1896 namespace os = lyx::support::os;
1897 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1899 case LyXRC::RC_DATE_INSERT_FORMAT:
1900 case LyXRC::RC_DEFAULT_LANGUAGE:
1901 case LyXRC::RC_DEFAULT_PAPERSIZE:
1902 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1903 case LyXRC::RC_DISPLAY_GRAPHICS:
1904 case LyXRC::RC_DOCUMENTPATH:
1905 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1906 if (fs::exists(lyxrc_new.document_path) &&
1907 fs::is_directory(lyxrc_new.document_path)) {
1908 using lyx::support::package;
1909 package().document_dir() = lyxrc.document_path;
1912 case LyXRC::RC_ESC_CHARS:
1913 case LyXRC::RC_FONT_ENCODING:
1914 case LyXRC::RC_FORMAT:
1915 case LyXRC::RC_INDEX_COMMAND:
1916 case LyXRC::RC_INPUT:
1917 case LyXRC::RC_KBMAP:
1918 case LyXRC::RC_KBMAP_PRIMARY:
1919 case LyXRC::RC_KBMAP_SECONDARY:
1920 case LyXRC::RC_LABEL_INIT_LENGTH:
1921 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1922 case LyXRC::RC_LANGUAGE_AUTO_END:
1923 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1924 case LyXRC::RC_LANGUAGE_COMMAND_END:
1925 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1926 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1927 case LyXRC::RC_LANGUAGE_PACKAGE:
1928 case LyXRC::RC_LANGUAGE_USE_BABEL:
1929 case LyXRC::RC_LASTFILES:
1930 case LyXRC::RC_MAKE_BACKUP:
1931 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1932 case LyXRC::RC_NUMLASTFILES:
1933 case LyXRC::RC_PATH_PREFIX:
1934 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1935 using lyx::support::prependEnvPath;
1936 prependEnvPath("PATH", lyxrc.path_prefix);
1938 case LyXRC::RC_PERS_DICT:
1939 case LyXRC::RC_POPUP_BOLD_FONT:
1940 case LyXRC::RC_POPUP_FONT_ENCODING:
1941 case LyXRC::RC_POPUP_NORMAL_FONT:
1942 case LyXRC::RC_PREVIEW:
1943 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1944 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1945 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1946 case LyXRC::RC_PRINTCOPIESFLAG:
1947 case LyXRC::RC_PRINTER:
1948 case LyXRC::RC_PRINTEVENPAGEFLAG:
1949 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1950 case LyXRC::RC_PRINTFILEEXTENSION:
1951 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1952 case LyXRC::RC_PRINTODDPAGEFLAG:
1953 case LyXRC::RC_PRINTPAGERANGEFLAG:
1954 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1955 case LyXRC::RC_PRINTPAPERFLAG:
1956 case LyXRC::RC_PRINTREVERSEFLAG:
1957 case LyXRC::RC_PRINTSPOOL_COMMAND:
1958 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1959 case LyXRC::RC_PRINTTOFILE:
1960 case LyXRC::RC_PRINTTOPRINTER:
1961 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1962 case LyXRC::RC_PRINT_COMMAND:
1963 case LyXRC::RC_RTL_SUPPORT:
1964 case LyXRC::RC_SCREEN_DPI:
1965 case LyXRC::RC_SCREEN_FONT_ENCODING:
1966 case LyXRC::RC_SCREEN_FONT_ROMAN:
1967 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1968 case LyXRC::RC_SCREEN_FONT_SANS:
1969 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1970 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1971 case LyXRC::RC_SCREEN_FONT_SIZES:
1972 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1973 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1974 case LyXRC::RC_SCREEN_ZOOM:
1975 case LyXRC::RC_SERVERPIPE:
1976 case LyXRC::RC_SET_COLOR:
1977 case LyXRC::RC_SHOW_BANNER:
1978 case LyXRC::RC_SPELL_COMMAND:
1979 case LyXRC::RC_TEMPDIRPATH:
1980 case LyXRC::RC_TEMPLATEPATH:
1981 case LyXRC::RC_TEX_ALLOWS_SPACES:
1982 case LyXRC::RC_UIFILE:
1983 case LyXRC::RC_USER_EMAIL:
1984 case LyXRC::RC_USER_NAME:
1985 case LyXRC::RC_USETEMPDIR:
1986 case LyXRC::RC_USE_ALT_LANG:
1987 case LyXRC::RC_USE_ESC_CHARS:
1988 case LyXRC::RC_USE_INP_ENC:
1989 case LyXRC::RC_USE_PERS_DICT:
1990 case LyXRC::RC_USE_SPELL_LIB:
1991 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1992 case LyXRC::RC_VIEWER:
1993 case LyXRC::RC_WHEEL_JUMP:
1994 case LyXRC::RC_LAST: